Esempio n. 1
0
def test_multipart_invalid_value(value):
    client = Client(dispatch=MockDispatch())
    data = {"text": value}
    files = {"file": io.BytesIO(b"<file content>")}
    with pytest.raises(TypeError) as e:
        client.post("http://127.0.0.1:8000/", data=data, files=files)
    assert "Invalid type for value" in str(e.value)
    def _get_token(self, client: Client, concourse_url: str) -> str:
        concourse_login = f"{concourse_url}/sky/login"

        r = client.get(concourse_login, follow_redirects=True)

        ldap_url = expect(
            re.search(_LDAP_URL_REGEX, r.text),
            "BUG: no ldap url found"
        ).group(0)

        ldap_login_url = f"{concourse_url}{ldap_url}"

        print("Concourse login")
        username = input("Username: "******"login": username, "password": password}

        r = client.post(ldap_login_url, data=data, follow_redirects=True)

        token = expect(
            re.search(_BEARER_REGEX, r.text),
            "BUG: no bearer found"
        ).group(1)

        return token
Esempio n. 3
0
def get_slots(
    entityId,
    medicalStaffId,
    reasonId,
    start_date,
    end_date,
    client: httpx.Client = DEFAULT_CLIENT,
    request: ScraperRequest = None,
):
    base_url = ORDOCLIC_API.get("slots")
    payload = {
        "entityId": entityId,
        "medicalStaffId": medicalStaffId,
        "reasonId": reasonId,
        "dateEnd": f"{end_date}T00:00:00.000Z",
        "dateStart": f"{start_date}T23:59:59.000Z",
    }
    headers = {"Content-type": "application/json", "Accept": "text/plain"}
    if request:
        request.increase_request_count("slots")
    try:
        r = client.post(base_url, data=json.dumps(payload), headers=headers)
        r.raise_for_status()
    except httpx.TimeoutException as hex:
        logger.warning(f"request timed out for center: {base_url}")
        return False
    except httpx.HTTPStatusError as hex:
        logger.warning(f"{base_url} returned error {hex.response.status_code}")
        return None
    return r.json()
Esempio n. 4
0
def send_message_to_channel(text: str,
                            service_id: str,
                            client: httpx.Client = None):
    """Huey task to send message to specific payload for specific slack service

    Args:
        payload (dict): payload for serivce
        service_id (str): service id of the service (ex of service: Webhook)
        client (httpx.Client, optional): client to send requests. Defaults to None.

    Raises:
        e: httpx.HTTPStatusError
    """
    if settings.SLACK_NOTIF_IS_ACTIVE:
        if not client:
            client = get_default_client()

        try:
            data = {"text": text}
            response = client.post(f"{BASE_URL}{service_id}", json=data)
            response.raise_for_status()
            logger.info("send message to slack")
            logger.info(response.json())
            return response.json()
        except httpx.HTTPStatusError as e:
            logger.error("Error while fetching `%s`: %s", e.request.url, e)
            raise e
Esempio n. 5
0
def _send_chunk(client: httpx.Client, config: Config, file: ResumableFile,
                chunk: FileChunk) -> bool:
    """Upload the chunk to the server.

    Returns
    -------
    bool
        True if the upload was successful

    Raises
    ------
    ResumableError
        If the server responded with an error code indicating permanent failure
    """
    try:
        response = client.post(
            config.target,
            data=_build_query(file, chunk, config.additional_query_params),
            files={"file": chunk.read()},
        )
    except httpx.TransportError:
        # The request itself failed. The calling function will retry.
        return False
    if response.status_code in config.permanent_errors:
        raise ResumableError(f"{response.status_code} Error: {response.text}")
    return response.status_code in [200, 201]
def refresh_grant(client: httpx.Client,
                  token_uri: typing.Union["URL", str, RawURL],
                  refresh_token: str,
                  scopes: str = None):
    payload = {
        "refresh_token": refresh_token,
    }
    # if scopes:
    #     payload["scope"] = scopes

    logger.debug(f"HTTP Request: POST {token_uri} {client.headers} {payload}")
    response = client.post(url=token_uri, json=payload)
    response_data = response.json()

    try:
        access_token = response_data["access_token"]
    except KeyError as caught_exc:
        new_exc = exceptions.RefreshError("No access token in response.",
                                          response_data)
        raise new_exc from caught_exc

    refresh_token = response_data.get("refresh_token", refresh_token)
    expiry = _parse_expiry(response_data)

    return access_token, refresh_token, expiry, response_data
Esempio n. 7
0
def get_slots(entityId,
              medicalStaffId,
              reasonId,
              start_date,
              end_date,
              client: httpx.Client = DEFAULT_CLIENT):
    base_url = "https://api.ordoclic.fr/v1/solar/slots/availableSlots"
    payload = {
        "entityId": entityId,
        "medicalStaffId": medicalStaffId,
        "reasonId": reasonId,
        "dateEnd": f"{end_date}T00:00:00.000Z",
        "dateStart": f"{start_date}T23:59:59.000Z",
    }
    headers = {"Content-type": "application/json", "Accept": "text/plain"}
    try:
        r = client.post(base_url, data=json.dumps(payload), headers=headers)
        r.raise_for_status()
    except httpx.TimeoutException as hex:
        logger.warning(f"request timed out for center: {base_url}")
        return False
    except httpx.HTTPStatusError as hex:
        logger.warning(f"{base_url} returned error {hex.response.status_code}")
        return None
    return r.json()
Esempio n. 8
0
 def _submit2(self, json, client: httpx.Client):
     if self.message_id is None:
         message = client.post(f'{self.webhook}?wait=true', json=json)
         self.message_id = message.json()['id']
     else:
         client.patch(f'{self.webhook}/messages/{self.message_id}',
                      json=json)
Esempio n. 9
0
def get_availabilities_week(
    reason_id: int, organization_id: int, start_date: datetime, client: httpx.Client = DEFAULT_CLIENT
) -> Optional[list]:
    url = AVECMONDOC_API.get("availabilities_per_day", "")
    payload = {
        "consultationReasonId": reason_id,
        "disabledPeriods": [],
        "fullDisplay": True,
        "organizationId": organization_id,
        "periodEnd": (start_date + timedelta(days=(AVECMONDOC_DAYS_PER_PAGE - 1))).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
        "periodStart": start_date.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
        "type": "inOffice",
    }
    headers = {"Content-type": "application/json", "Accept": "application/json"}
    try:
        r = client.post(url, data=json.dumps(payload), headers=headers)
        r.raise_for_status()
    except httpx.TimeoutException as hex:
        logger.warning(f"request timed out for center: {url}")
        return None
    except httpx.HTTPStatusError as hex:
        logger.warning(f"{url} returned error {hex.response.status_code}")
        logger.warning(payload)
        return None
    return r.json()
Esempio n. 10
0
class HTTPClient:
    def __init__(
        self,
        base_url: str,
        default_headers: Optional[dict] = None,
        default_params: Optional[dict] = None,
    ):
        self.base_url = base_url
        self.default_headers = default_headers or {}
        self.default_params = default_params or {}

        self.http_client = Client(
            base_url=self.base_url, headers=default_headers, params=self.default_params
        )

    def get(self, url: str, params: dict, headers: dict = None):
        custom_headers = headers or {}

        if not params.get("_rticket"):
            params["_rticket"] = int(round(time() * 1000))

        response = self.http_client.get(url=url, params=params, headers=custom_headers)

        return response

    def post(self, url: str, data: dict, headers: dict = None):
        custom_headers = headers or {}

        rticket = int(round(time() * 1000))

        response = self.http_client.post(
            url=url, params={"_rticket": rticket}, data=data, headers=custom_headers
        )

        return response
Esempio n. 11
0
def commitPushedDate(
    client: httpx.Client, org: str, commit: GitHubRepoCommit
) -> Optional[str]:
    ql = """query ($org: String!, $repo: String!, $hash: String!) {
                repository(owner: $org, name: $repo) {
                    object(expression: $hash) {
                        ... on Commit {
                            pushedDate
                        }
                    }
                }
        }"""
    result = client.post(
        QL_ENDPOINT,
        json={
            "query": ql,
            "variables": {"org": org, "repo": commit.name, "hash": commit.commit_hash,},
        },
    )
    if result.status_code == 200:
        body: Dict = result.json()
        if body.get("errors", None) is not None:
            print(body["errors"])
            return None
        else:
            commit_obj: Dict[str, Any] = body["data"]["repository"]["object"]
            return commit_obj["pushedDate"]
Esempio n. 12
0
    def admin_login(protocol: str,
                    host: str,
                    port: str,
                    username: str = None,
                    password: str = None,
                    suppress_exception: bool = False,
                    no_admin: bool = False) -> str:
        """Login and get an access token

        Args:
            protocol (str): "http://" or "https://". Defaults to None. # noqa: E501
            host (str): homeserver address. Defaults to None.
            port (int): homeserver listening port. Defaults to None.
            username (str, optional): just username. Defaults to None.
            password (str, optional): just password. Defaults to None.
            suppress_exception (bool, optional): suppress exception or not, if not return False and the error in dict. Defaults to False. # noqa: E501

        Returns:
            str: access token
        """
        if username is None:
            username = input("Enter a username: "******"identifier": {
                "type": "m.id.user",
                "user": username
            },
            "type": "m.login.password",
            "password": password,
            "initial_device_display_name": "matrix-synapse-admin"
        }
        http = Client()
        base_url = f"{protocol}{host}:{port}"
        while True:
            resp = http.post(f"{base_url}{ClientAPI.BASE_PATH}/login",
                             json=login_data)
            data = resp.json()
            if "errcode" in data and data["errcode"] == "M_LIMIT_EXCEEDED":
                time.sleep(data["retry_after_ms"] / 1000)
                continue
            if resp.status_code == 200:
                access_token = data["access_token"]
                if not no_admin:
                    resp = User(host, port, access_token,
                                protocol).query(username)
                    if "errcode" not in resp:
                        return data["access_token"]
                    else:
                        data = resp
                else:
                    return access_token
            if suppress_exception:
                return False, data
            else:
                raise SynapseException(data["errcode"], data["error"])
Esempio n. 13
0
def test_remove_path():
    with WebServer('test').start() as server:
        client = Client(base_url=server.local_url())

        @http_endpoint('POST', '/{a:int}/foo')
        async def get_foo(request):
            a = request.path_params['a']
            b = await request.json()
            return JSONResponse(a * b)

        assert client.post('/12/foo',
                           json=15).status_code == HTTP_404_NOT_FOUND
        assert client.post('/12/bar',
                           json=15).status_code == HTTP_404_NOT_FOUND

        with server.patch_http_endpoint(get_foo):
            resp = client.post('/12/foo', json=15)
            resp.raise_for_status()
            assert resp.json() == 15 * 12

        assert client.post('/12/foo',
                           json=15).status_code == HTTP_404_NOT_FOUND
        assert client.post('/12/bar',
                           json=15).status_code == HTTP_404_NOT_FOUND
    with raises(HTTPError):
        client.post('/12/foo', json=15)
Esempio n. 14
0
def getSlots(entityId, medicalStaffId, reasonId, start_date, end_date, client: httpx.Client = DEFAULT_CLIENT):
    base_url = 'https://api.ordoclic.fr/v1/solar/slots/availableSlots'
    payload = {"entityId": entityId,
               "medicalStaffId": medicalStaffId,
               "reasonId": reasonId,
               "dateEnd": f"{end_date}T00:00:00.000Z",
               "dateStart": f"{start_date}T23:59:59.000Z"}
    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    r = client.post(base_url, data=json.dumps(payload), headers=headers)
    r.raise_for_status()
    return r.json()
Esempio n. 15
0
def viewerIsOrgMember(client: httpx.Client, org: str) -> Optional[bool]:
    ql = """query($org: String!){
                organization(login:$org){
                    viewerIsAMember
                }
        }"""
    result = client.post(QL_ENDPOINT, json={"query": ql, "variables": {"org": org}})

    if result.status_code == 200:
        body: Dict = result.json()
        if body.get("errors", None) is not None:
            print(body["errors"])
            return False
        else:
            org: Dict[str, Any] = body["data"]["organization"]
            return org["viewerIsAMember"]
    return None
Esempio n. 16
0
    def request_new_grant_with_post_kbank_special(
            self, url: str, data, grant_name: str,
            client: httpx.Client) -> Tuple[str, int]:
        with client:
            header = {"Content-Type": "application/x-www-form-urlencoded"}
            response = client.post(url, data=data, headers=header)

            if response.is_error:
                # As described in https://tools.ietf.org/html/rfc6749#section-5.2
                raise InvalidGrantRequest(response)

            content = response.json()

        token = content.get(grant_name)
        if not token:
            raise GrantNotProvided(grant_name, content)
        return token, content.get("expires_in")
Esempio n. 17
0
async def test_tutor_signup_with_email(client: httpx.Client):
    signup_func = lambda: client.post(
        "/signup",
        json={
            "full_name": "Danny::Novak",
            "email": "*****@*****.**",
            "gender": "M",
            "dob": "1991-12-16",  # year-month-day
            "password": "******",
            # sent in addition to signup info to skip email verification.
            "signup_info": {
                "verification": None
            },
        },
    )
    async with models.User.database:
        await clean_db()
        response = await signup_func()
        assert response.status_code == 200
        result: dict = response.json()
        access_token = result["data"]["access_token"]
        # decode jwt token
        user_data = jwt.decode(access_token, verify=False)
        user_info = {
            "email": "*****@*****.**",
            "gender": "M",
            "full_name": "Danny::Novak",
            "first_name": "Danny",
            "birthday": "1991-12-16",
        }
        for key in user_info.keys():
            assert user_data[key] == user_info[key]
        record = await models.User.objects.get(email=user_data["email"])
        assert record.email == "*****@*****.**"
        assert record.gender.value == "M"
        assert not record.email_verified
        # second attempt to signup should result in an error.
        response = await signup_func()
        assert response.status_code == 400
        assert response.json() == {
            "status": False,
            "errors": {
                "email": ["value_error.duplicate"]
            },
        }
Esempio n. 18
0
class Requests:
    """Client for requests"""
    def __init__(self):
        self._client = Client()

    def post(
        self,
        *,
        url: str,
        params: Optional[Dict] = None,
        body: Optional[Dict] = None,
        data: Optional[Dict] = None,
        files: Optional[Dict] = None,
    ) -> Response:
        """Send post request"""
        return self._client.post(url=url,
                                 params=params,
                                 json=body,
                                 data=data,
                                 files=files)
Esempio n. 19
0
    def request_new_grant_with_post_scb_special(
            self, url: str, data, grant_name: str,
            client: httpx.Client) -> Tuple[str, int]:
        with client:
            header = {
                "Content-Type": "application/json",
                "resourceOwnerId": self.client_id,
                "requestUId": uuid.uuid4().hex,
                "accept-language": "EN",
            }
            response = client.post(url, json=data, headers=header)

            if response.is_error:
                # As described in https://tools.ietf.org/html/rfc6749#section-5.2
                raise InvalidGrantRequest(response)

            content = response.json().get("data")

        token = content.get(grant_name)
        if not token:
            raise GrantNotProvided(grant_name, content)
        return token, content.get("expiresIn")
Esempio n. 20
0
def post_method(url: str,
                postdata=None,
                postjson=None,
                headers: dict = None,
                timeout=5,
                max_retries=5,
                c: httpx.Client = None):
    """
    timeout: 超时时间, 单位秒(s), 默认为 5 秒, 为 `None` 时禁用
    max_retries: 最大尝试次数, 默认为 5 次, 为 0 时禁用
    """
    k = 1
    while (k <= max_retries) or (max_retries == 0):
        try:
            if c is not None:
                res = c.post(url,
                             data=postdata,
                             json=postjson,
                             headers=headers,
                             timeout=timeout)
            else:
                res = httpx.post(url,
                                 data=postdata,
                                 json=postjson,
                                 headers=headers,
                                 timeout=timeout)
        except Exception as e:
            k = k + 1
            print(sys._getframe().f_code.co_name + ": " + str(e))
            time.sleep(1)
            continue
        else:
            break
    try:
        return res
    except Exception:
        sys.exit(sys._getframe().f_code.co_name + ": " +
                 "Max retries exceeded")
Esempio n. 21
0
def test_multipart_file_tuple():
    client = Client(dispatch=MockDispatch())

    # Test with a list of values 'data' argument, and a tuple style 'files' argument.
    data = {"text": ["abc"]}
    files = {"file": ("name.txt", io.BytesIO(b"<file content>"))}
    response = client.post("http://127.0.0.1:8000/", data=data, files=files)
    assert response.status_code == 200

    # We're using the cgi module to verify the behavior here, which is a
    # bit grungy, but sufficient just for our testing purposes.
    boundary = response.request.headers["Content-Type"].split("boundary=")[-1]
    content_length = response.request.headers["Content-Length"]
    pdict = {
        "boundary": boundary.encode("ascii"),
        "CONTENT-LENGTH": content_length
    }
    multipart = cgi.parse_multipart(io.BytesIO(response.content), pdict)

    # Note that the expected return type for text fields
    # appears to differs from 3.6 to 3.7+
    assert multipart["text"] == ["abc"] or multipart["text"] == [b"abc"]
    assert multipart["file"] == [b"<file content>"]
Esempio n. 22
0
def install_component(component_file: str = Argument(
    ..., help="The path to the component file containing the data")):
    """Function to install a component:

    - Takes as input a YAML file
    - Parses it as a dictionary through the Pydantic model
        TunableComponentsModel
    - Send it as a POST request to /components
    """
    api_client = Client(
        base_url=f"http://{api_settings.api_host}:{api_settings.api_port}",
        proxies={},
    )
    component = TunableComponentsModel.from_yaml(component_file)
    logger.debug(f"Sending component data {component.dict()}"
                 "to endpoint"
                 f"http: // {api_settings.api_host}: {api_settings.api_port}"
                 f"{api_settings.component_endpoint}")
    request = api_client.post(api_settings.component_endpoint,
                              json=component.dict())
    logger.info("Successfully registered components.")
    if not 200 <= request.status_code < 400:
        raise Exception("Could not create component with status code"
                        f"{request.status_code}")
Esempio n. 23
0
class RegisterCommands(object):
    """This object contains methods to help registering a command to Discord.
    While you shouldn't need to import this directly, it's still accessible if you
    prefer not to initalize a Dispike object.

    Important to remember all methods are not async.

    """

    def __init__(self, application_id: str, bot_token: str):
        """Initalize object provided with application_id and a bot token

        Args:
            application_id (str): Client ID
            bot_token (str): Bot user Token
        """
        self.__bot_token = bot_token
        self._application_id = application_id
        self._client = Client(
            base_url=f"https://discord.com/api/v8/applications/{self._application_id}/",
            event_hooks={
                "response": [dispike_httpx_event_hook_incoming_request],
                "request": [dispike_httpx_event_hook_outgoing_request],
            },
        )

    @logger.catch(reraise=True, message="Issue with bulk overrwriting commands")
    def bulk_overwrite_commands(
        self,
        commands: typing.List[DiscordCommand],
        guild_only: bool = False,
        guild_to_target: int = None,
    ):
        """Bulk OVERWRITE commands to specific guilds or globally.

        Args:
            commands (typing.List[DiscordCommand]): List of new commands (these commands will be overwritten)
            guild_only (bool, optional): Default to set global mode (True). Set to False to let the function know to expect a guild_id
            guild_to_target (int, optional): A guild Id if guild_only is set to True.
        """
        if guild_only == True:
            if guild_to_target is None:
                raise TypeError(
                    "if guild_only is set to true, a guild id must be provided."
                )

            logger.info(f"Targeting a specific guild -> {guild_to_target}")
            _request_url = f"guilds/{guild_to_target}/commands"
        else:
            _request_url = f"commands"

        _commands_to_json = [command.dict(exclude_none=True) for command in commands]
        _send_request = self._client.put(
            url=_request_url, json=_commands_to_json, headers=self.request_headers
        )
        if _send_request.status_code == 200:
            logger.info(
                f"Overwritten {len(_send_request.json())} commands.. Recieved ({len(_commands_to_json)}"
            )
            return True
        else:
            logger.debug(
                f"BULK Overwrite failed ({guild_only} = {guild_to_target}): Body: {_commands_to_json}.. Status code: {_send_request.status_code}"
            )
            raise DiscordAPIError(_send_request.status_code, _send_request.text)

    def register(
        self, command: DiscordCommand, guild_only=False, guild_to_target: int = None
    ):
        """Register a completed `DiscordCommand` model to Discord API.

        Args:
            command (DiscordCommand): A properly configured DiscordCommand
            guild_only (bool, optional): Default to set global mode (True). Set to False to let the function know to expect a guild_id
            guild_to_target (int, optional): A guild Id if guild_only is set to True.
        """
        if guild_only == True:
            if guild_to_target is None:
                raise TypeError(
                    "if guild_only is set to true, a guild id must be provided."
                )

            logger.info(f"Targeting a specific guild -> {guild_to_target}")
            _request_url = f"guilds/{guild_to_target}/commands"
        else:
            _request_url = f"commands"

        try:
            _command_to_json = command.dict(exclude_none=True)
            _send_request = self._client.post(
                _request_url, headers=self.request_headers, json=_command_to_json
            )
            if _send_request.status_code in [200, 201]:
                return True

            raise DiscordAPIError(_send_request.status_code, _send_request.text)
        except Exception:
            raise

    @property
    def request_headers(self):
        """Return a valid header for authorization

        Returns:
            dict: a valid header for authorization
        """
        return {"Authorization": f"Bot {self.__bot_token}"}

    @property
    def bot_token(self):
        """You cannot view the bot_token directly, but you can still 'update' it.

        Raises:
            PermissionError: If you attempt to view the bot token without a new value
        """
        raise PermissionError("You cannot view the bot token directly.")

    @bot_token.setter
    def bot_token(self, new_bot_token):
        if new_bot_token == self.__bot_token:
            raise TypeError("Bot token already set to that.")
        self.__bot_token = new_bot_token
Esempio n. 24
0
File: api.py Progetto: Xowap/DEV-CLI
class DevApi:
    """
    A class to access the dev.to API
    """

    BASE_URL = "https://dev.to/api"

    def __init__(self, api_key: Text):
        """
        Creates the HTTP client
        """

        self.api_key = api_key
        self.client = Client(headers=[("Api-Key", self.api_key)])

    def url(self, path: Text) -> Text:
        """
        Generates an URL, be careful not to put any slash at the start or the
        end.
        """

        return f"{self.BASE_URL}/{path}"

    def get_my_articles(self, publication: Text = "all") -> Iterator[Dict]:
        """
        Returns an iterator over all the articles corresponding to the
        publication filter.

        :param publication: Publication status. Allowed values are "published",
                            "unpublished" and "all"
        :return: An iterator of all selected articles
        """

        assert publication in {"published", "unpublished", "all"}

        url = self.url(f"articles/me/{publication}")

        class NoMorePages(Exception):
            """
            A way to communicate that there is no more page coming up from the
            API and that the polling of pages should stop now.
            """

        def get_page(page: int):
            """
            Returns a given page. Pages are 1-indexed.
            """

            r = self.client.get(url, params={"page": page})
            stop = True

            for article in r.json():
                stop = False
                yield article

            if stop:
                raise NoMorePages

        for i in range(1, 1000):
            try:
                yield from get_page(i)
            except NoMorePages:
                return

    def find_article(self, key: DevKey) -> Optional[Dict]:
        """
        Finds the first article matching they key. Let's take a moment to note
        that this method is really approximate but since we can't retrofit the
        API ID into the Markdown file it's the only decent way to go.
        """

        for article in self.get_my_articles():
            if article[key.name] == key.value:
                return article

    def create_article(self, parser: DevParser) -> None:
        """
        Creates an article based on the parsed file.
        """

        url = self.url("articles")

        if "title" not in parser.front_matter:
            raise DevApiError(
                "Cannot create an article with no `title` in the front matter")

        r = self.client.post(
            url,
            json={
                "title": parser.front_matter["title"],
                "body_markdown": parser.file_content,
            },
        )
        r.raise_for_status()

    def update_article(self, parser: DevParser, article_id: int) -> None:
        """
        Updates an article based on the parsed file and an existing ID.
        """

        url = self.url(f"articles/{article_id}")

        r = self.client.put(url, json={"body_markdown": parser.file_content})
        r.raise_for_status()
Esempio n. 25
0
class Request:
    """Start a requests session and provide helper methods for HTTP verbs.
    """
    def __init__(self):
        self.session = Client(timeout=10)
        self.headers = self.client.AuthHeader

    def InjectAttrs(self, **kwargs):
        """Add custom headers if requested, default authorisation header included in __init__.

        Args:
            headers (dict): Key value pairs for headers
        """
        if kwargs.get("headers"):
            self.headers = {**self.headers, **kwargs.get("headers")}
        if kwargs.get("start"):
            self.body.update({"start": kwargs.get("start")})

    @retry(
        retry_on_exceptions=(RetryException),
        max_calls_total=3,
        retry_window_after_first_call_in_seconds=10,
    )
    @basicauth
    def GET(self, url, params={}, headers: dict = {}) -> Response:
        """HTTP GET Request

        Args:
            url (str): URL to connect to.
            headers (dict, optional): Key Value pairs for additional headers. (default: None)

        Returns:
            Response -- HTTPX Response object
        """
        self.InjectAttrs(headers=headers)
        try:
            response = self.session.get(url,
                                        params=params,
                                        headers=self.headers)
            return response
        except _exceptions.TimeoutException:
            raise RetryException

    @retry(
        retry_on_exceptions=(RetryException),
        max_calls_total=3,
        retry_window_after_first_call_in_seconds=10,
    )
    @contenttype
    @basicauth
    def PATCH(
        self,
        url: str,
        body=None,
        headers: dict = {},
        idempotent: bool = False,
    ) -> Response:
        """HTTP PATCH Request

        Args:
            url (str): URL to connect to.
            body (dict, optional): JSON payload for the request. (default: dict())
            headers (dict, optional): Key Value pairs for additional headers. (default: None)
            idempotent (bool, optional): Is this request idempotent? (default: False)

        Returns:
            Response -- HTTPX Response object
        """
        self.InjectAttrs(headers=headers)
        try:
            response = self.session.patch(url, data=body, headers=self.headers)
            return response
        except _exceptions.TimeoutException:
            if idempotent is False:
                raise IdempotentTimeout(method="PATCH",
                                        url=url,
                                        data=body,
                                        headers=self.headers)
            else:
                print("retry")
                raise RetryException

    @retry(
        retry_on_exceptions=(RetryException),
        max_calls_total=3,
        retry_window_after_first_call_in_seconds=10,
    )
    @contenttype
    @basicauth
    def PUT(self, url: str, body: dict = {}, headers: dict = {}) -> Response:
        """HTTP PUT Request

        Args:
            url (str): URL to connect to.
            body (dict, optional): JSON payload for the request. (default: dict())
            headers (dict, optional): Key Value pairs for additional headers. (default: None)

        Returns:
            Response -- HTTPX Response object
        """
        self.InjectAttrs(headers=headers)
        try:
            response = self.session.put(url, data=body, headers=self.headers)
            return response
        except _exceptions.TimeoutException:
            raise RetryException

    @retry(
        retry_on_exceptions=(RetryException),
        max_calls_total=3,
        retry_window_after_first_call_in_seconds=10,
    )
    @contenttype
    @basicauth
    def POST(
        self,
        url: str,
        body: str = None,
        params: dict = None,
        headers: dict = {},
        idempotent: bool = False,
    ) -> Response:
        """HTTP POST Request

        Args:
            url (str): URL to connect to.
            body (dict, optional): JSON payload for the request. (default: dict())
            params (dict, optional): Dictionary for path parameters. (default: None)
            headers (dict, optional): Key Value pairs for additional headers. (default: None)
            idempotent (bool, optional): Is this request idempotent? (default: False)

        Returns:
            Response -- HTTPX Response object
        """
        self.InjectAttrs(headers=headers)
        try:
            response = self.session.post(url,
                                         data=body,
                                         params=params,
                                         headers=self.headers)
            return response
        except _exceptions.TimeoutException:
            if idempotent is False:
                raise IdempotentTimeout(method="POST",
                                        url=url,
                                        body=body,
                                        headers=self.headers)
            else:
                print("retry")
                raise RetryException

    @retry(
        retry_on_exceptions=(RetryException),
        max_calls_total=3,
        retry_window_after_first_call_in_seconds=10,
    )
    @contenttype
    @basicauth
    def DELETE(self,
               url: str,
               body: dict = {},
               headers: dict = {}) -> Response:
        """HTTP DELETE Request

        Args:
            url (str): URL to connect to.
            body (dict, optional): JSON payload for the request. (default: dict())
            headers (dict, optional): Key Value pairs for additional headers. (default: None)

        Returns:
            Response -- HTTPX Response object
        """
        self.InjectAttrs(headers=headers)
        try:
            response = self.session.delete(url, headers=self.headers)
            return response
        except _exceptions.TimeoutException:
            raise RetryException
Esempio n. 26
0
class ZebrunnerAPI(metaclass=Singleton):
    authenticated = False

    def __init__(self, service_url: str = None, access_token: str = None):
        if service_url and access_token:
            self.service_url = service_url.rstrip("/")
            self.access_token = access_token
            self._client = Client()
            self._auth_token = None
            self.authenticated = False

    def _sign_request(self, request: Request) -> Request:
        request.headers["Authorization"] = f"Bearer {self._auth_token}"
        return request

    def auth(self) -> None:
        if not self.access_token or not self.service_url:
            return

        url = self.service_url + "/api/iam/v1/auth/refresh"
        try:
            response = self._client.post(
                url, json={"refreshToken": self.access_token})
        except httpx.RequestError as e:
            logger.warning("Error while sending request to zebrunner.",
                           exc_info=e)
            return

        if response.status_code != 200:
            log_response(response, logging.ERROR)
            return

        self._auth_token = response.json()["authToken"]
        self._client.auth = self._sign_request
        self.authenticated = True

    def start_test_run(self, project_key: str,
                       body: StartTestRunModel) -> Optional[int]:
        url = self.service_url + "/api/reporting/v1/test-runs"

        try:
            response = self._client.post(url,
                                         params={"projectKey": project_key},
                                         json=body.dict(exclude_none=True,
                                                        by_alias=True))
        except httpx.RequestError as e:
            logger.warning("Error while sending request to zebrunner.",
                           exc_info=e)
            return None

        if response.status_code != 200:
            log_response(response, logging.ERROR)
            return None

        return response.json()["id"]

    def start_test(self, test_run_id: int,
                   body: StartTestModel) -> Optional[int]:
        url = self.service_url + f"/api/reporting/v1/test-runs/{test_run_id}/tests"

        try:
            response = self._client.post(url,
                                         json=body.dict(exclude_none=True,
                                                        by_alias=True))
        except httpx.RequestError as e:
            logger.warning("Error while sending request to zebrunner.",
                           exc_info=e)
            return None

        if response.status_code != 200:
            log_response(response, logging.ERROR)
            return None

        return response.json()["id"]

    def finish_test(self, test_run_id: int, test_id: int,
                    body: FinishTestModel) -> None:
        url = self.service_url + f"/api/reporting/v1/test-runs/{test_run_id}/tests/{test_id}"

        try:
            response = self._client.put(url,
                                        json=body.dict(exclude_none=True,
                                                       by_alias=True))
        except httpx.RequestError as e:
            logger.warning("Error while sending request to zebrunner.",
                           exc_info=e)
            return

        if response.status_code != 200:
            log_response(response, logging.ERROR)

    def finish_test_run(self, test_run_id: int) -> None:
        url = self.service_url + f"/api/reporting/v1/test-runs/{test_run_id}"
        try:
            response = self._client.put(
                url,
                json={
                    "endedAt":
                    (datetime.utcnow().replace(tzinfo=timezone.utc) -
                     timedelta(seconds=1)).isoformat()
                },
            )
        except httpx.RequestError as e:
            logger.warning("Error while sending request to zebrunner.",
                           exc_info=e)
            return

        if response.status_code != 200:
            log_response(response, logging.ERROR)
            return

    def send_logs(self, test_run_id: int, logs: List[LogRecordModel]) -> None:
        url = self.service_url + f"/api/reporting/v1/test-runs/{test_run_id}/logs"

        body = [x.dict(exclude_none=True, by_alias=True) for x in logs]
        self._client.post(url, json=body)

    def send_screenshot(self, test_run_id: int, test_id: int,
                        image_path: Union[str, Path]) -> None:
        url = self.service_url + f"/api/reporting/v1/test-runs/{test_run_id}/tests/{test_id}/screenshots"
        with open(image_path, "rb") as image:
            self._client.post(
                url,
                content=image.read(),
                headers={
                    "Content-Type": "image/png",
                    "x-zbr-screenshot-captured-at": round(time.time() * 1000)
                },
            )

    def send_artifact(self,
                      filename: Union[str, Path],
                      test_run_id: int,
                      test_id: Optional[int] = None) -> None:
        if test_id:
            url = f"{self.service_url}/api/reporting/v1/test-runs/{test_run_id}/tests/{test_id}/artifacts"
        else:
            url = f"{self.service_url}/api/reporting/v1/test-runs/{test_run_id}/artifacts"
        with open(filename, "rb") as file:
            self._client.post(url, files={"file": file})

    def send_artifact_references(self,
                                 references: List[ArtifactReferenceModel],
                                 test_run_id: int,
                                 test_id: Optional[int] = None) -> None:
        if test_id:
            url = f"{self.service_url}/api/reporting/v1/test-runs/{test_run_id}/tests/{test_id}/artifact-references"
        else:
            url = f"{self.service_url}/api/reporting/v1/test-runs/{test_run_id}/artifact-references/"
        json_items = [
            item.dict(exclude_none=True, by_alias=True) for item in references
        ]
        self._client.put(url, json={"items": json_items})

    def send_labels(self,
                    labels: List[LabelModel],
                    test_run_id: int,
                    test_id: Optional[int] = None) -> None:
        if test_id:
            url = f"{self.service_url}/api/reporting/v1/test-runs/{test_run_id}/tests/{test_id}/labels"
        else:
            url = f"{self.service_url}/api/reporting/v1/test-runs/{test_run_id}/labels"
        labels_json = [
            label.dict(exclude_none=True, by_alias=True) for label in labels
        ]
        self._client.put(url, json={"items": labels_json})

    def start_test_session(self, test_run_id: int,
                           body: StartTestSessionModel) -> Optional[str]:
        url = self.service_url + f"/api/reporting/v1/test-runs/{test_run_id}/test-sessions"
        response = self._client.post(url,
                                     json=body.dict(exclude_none=True,
                                                    by_alias=True))
        if not response.status_code == 200:
            log_response(response, logging.ERROR)
            return None

        return response.json().get("id")

    def finish_test_session(self, test_run_id: int, zebrunner_id: str,
                            body: FinishTestSessionModel) -> None:
        url = self.service_url + f"/api/reporting/v1/test-runs/{test_run_id}/test-sessions/{zebrunner_id}"
        self._client.put(url, json=body.dict(exclude_none=True, by_alias=True))

    def get_rerun_tests(self, run_context: str) -> RerunDataModel:
        url = self.service_url + "/api/reporting/v1/run-context-exchanges"
        run_context_dict = json.loads(run_context)
        response = self._client.post(url, json=run_context_dict)
        response_data = response.json()
        for test in response_data["tests"]:
            correlation_data = test["correlationData"]
            if correlation_data is not None:
                test["correlationData"] = json.loads(correlation_data)
        return RerunDataModel(**response_data)

    def close(self) -> None:
        self._client.close()
Esempio n. 27
0
class RegisterCommands(object):
    """This object contains methods to help registering a command to Discord.
    While you shouldn't need to import this directly, it's still accessible if you
    prefer not to initalize a Dispike object.

    Important to remember all methods are not async.
    """
    def __init__(self, application_id: str, bot_token: str):
        """Initalize object provided with application_id and a bot token

        Args:
            application_id (str): Client ID
            bot_token (str): Bot user Token
        """
        self.__bot_token = bot_token
        self._application_id = application_id
        self._client = Client(
            base_url=
            f"https://discord.com/api/v8/applications/{self._application_id}/")

    def register(self,
                 command: DiscordCommand,
                 guild_only=False,
                 guild_to_target: int = None):
        """Register a completed `DiscordCommand` model to Discord API.

        Args:
            command (DiscordCommand): A properly configured DiscordCommand
            guild_only (bool, optional): Default to set global mode (True). Set to False to let the function know to expect a guild_id
            guild_to_target (int, optional): A guild Id if guild_only is set to True.
        """
        if guild_only == True:
            if guild_to_target is None:
                raise TypeError(
                    "if guild_only is set to true, a guild id must be provided."
                )

            logger.info(f"Targeting a specific guild -> {guild_to_target}")
            _request_url = f"guilds/{guild_to_target}/commands"
        else:
            _request_url = f"commands"

        try:
            _command_to_json = command.dict(exclude_none=True)
            _send_request = self._client.post(_request_url,
                                              headers=self.request_headers,
                                              json=_command_to_json)
            if _send_request.status_code in [200, 201]:
                return True

            raise DiscordAPIError(_send_request.status_code,
                                  _send_request.text)
        except Exception:
            raise

    @property
    def request_headers(self):
        """Return a valid header for authorization

        Returns:
            dict: a valid header for authorization
        """
        return {"Authorization": f"Bot {self.__bot_token}"}

    @property
    def bot_token(self):
        """You cannot view the bot_token directly, but you can still 'update' it.

        Raises:
            PermissionError: If you attempt to view the bot token without a new value
        """
        raise PermissionError("You cannot view the bot token directly.")

    @bot_token.setter
    def bot_token(self, new_bot_token):
        if new_bot_token == self.__bot_token:
            raise TypeError("Bot token already set to that.")
        self.__bot_token = new_bot_token
Esempio n. 28
0
class SHAManExperiment:
    """This class represents an optimization experiment.

    It allows to plan, launch and store the information corresponding to
    an experiment.
    """

    def __init__(
        self,
        component_name: str,
        nbr_iteration: int,
        sbatch_file: str,
        experiment_name: str,
        configuration_file: str,
        sbatch_dir: str = None,
        slurm_dir: str = None,
        result_file: str = None,
    ) -> None:
        """Builds an object of class SHAManExperiment. This experiment is
        defined by giving:

            - The name of the component to tune.
            - The number of allowed iterations for the optimization process.
            - The name of the sbatch file to run.
            - The name of the experiment.
            - A configuration file to setup the experiment.
            - Where the slurm outputs should be stored
                (optional, if not specified, the outputs are deleted)
            - The path to the result file (optional, if not specified,
                no file is created).

        Args:
            component_name (str): The name of the component to use.
            nbr_iteration (int): The number of iterations.
            sbatch_file (str): The path to the sbatch file.
            experiment_name (str): The name of the experiment.
            sbatch_dir (str or Path): The working directory,
                where the shaman sbatch will be stored.
                If not specified, the directory where the command is called.
            slurm_dir (str or Path): The directory where the slurm outputs
                will be stored.
                If set to None, all the slurm outputs are removed after the
                end of the experiment.
            result_file (str): The path to the result file.
                If set to None, no such file is created and the results are
                debuged to the screen.
            configuration_file (str): The path to the configuration file.
                Defaults to the configuration file present in the package
                and called config.cfg.
        """
        # The name of the component that will be tuned through the experiment
        self.component_name = component_name
        # The maximum number of iterations
        self.nbr_iteration = nbr_iteration
        # The name of the sbatch to use, after ensuring its existence
        if Path(sbatch_file).exists():
            self.sbatch_file = sbatch_file
        else:
            raise FileNotFoundError(f"Could not find sbatch {sbatch_file}.")
        # Store information about the experiment
        self.experiment_name = experiment_name
        # Store the sbatch directory and convert to Path if not already
        if sbatch_dir:
            if isinstance(sbatch_dir, Path):
                self.sbatch_dir = sbatch_dir
            else:
                self.sbatch_dir = Path(sbatch_dir)
        else:
            self.sbatch_dir = Path.cwd()
        # Store the slurm directory and convert to Path if not already
        if slurm_dir:
            if isinstance(slurm_dir, Path):
                self.slurm_dir = slurm_dir
            else:
                self.slurm_dir = Path(slurm_dir)
        else:
            self.slurm_dir = None
        self.result_file = result_file
        self.experiment_id = ""

        # Parse the configuration
        self.configuration = SHAManConfig.from_yaml(
            configuration_file, self.component_name
        )
        # Create API client using the configuration information
        self.api_client = Client(base_url=self.api_url, proxies={})
        # Create the black box object using the informations
        self.bb_wrapper = BBWrapper(
            self.component_name,
            self.configuration.component_parameter_names,
            self.sbatch_file,
            sbatch_dir=self.sbatch_dir,
            component_configuration=self.api_url
            + "/"
            + api_settings.component_endpoint,
        )
        logger.debug(self.api_url + "/" + api_settings.component_endpoint)

        # Setup black box optimizer using configuration information
        self.bb_optimizer = self.setup_bb_optimizer()
        # Compute the start of the experiment
        self.experiment_start = \
            datetime.datetime.utcnow().strftime("%y/%m/%d %H:%M:%S")

    def setup_bb_optimizer(self) -> BBOptimizer:
        """Setups the black-box from the configuration."""
        # Create the BBOptimizer object using the different options in the
        # configuration
        # If pruning is enabled, parse corresponding fields
        if self.configuration.pruning:
            pruning = True
            max_step_cost = (
                self.bb_wrapper.default_target_value
                if self.configuration.pruning.max_step_duration == "default"
                else self.configuration.pruning.max_step_duration
            )
        else:
            max_step_cost = None
            pruning = False

        self.bb_optimizer = BBOptimizer(
            black_box=self.bb_wrapper,
            parameter_space=self.configuration.component_parameter_space,
            max_iteration=self.nbr_iteration,
            async_optim=pruning,
            max_step_cost=max_step_cost,
            **self.configuration.bbo_parameters,
        )
        return self.bb_optimizer

    def launch(self) -> None:
        """Launches the tuning experiment."""
        logger.debug("Creating experiment.")
        # Create the experiment through API request
        self.create_experiment()
        if self.configuration.experiment.default_first:
            # Launch a run using default parameterization of the component
            logger.info("Running application with default parametrization.")
            self.bb_wrapper.run_default()
        # Setup the optimizer
        logger.debug("Initializing black box optimizer.")
        self.setup_bb_optimizer()
        # Launch the optimization
        logger.debug("Launching optimization.")
        self.bb_optimizer.optimize(callbacks=[self.update_history])
        # Summarize the optimization
        # If there is a result file, write the output in it
        if self.result_file:
            orig_stdout = sys.stdout
            file_ = open(self.result_file, "w")
            sys.stdout = file_
            self.summarize()
            sys.stdout = orig_stdout
            file_.close()
        logger.debug(f"Summary of experiment: {self.summarize()}")

    def clean(self) -> None:
        """Cleans the experiment by removing the sbatch generated by Shaman.

        If there is no value specified for the slurm outputs folder,
        removes them.
        """
        for file_ in Path(__CURRENT_DIR__).glob("slurm*.out"):
            if self.slurm_dir:
                # Create if it doesn't already exist the folder
                self.slurm_dir.mkdir(exist_ok=True)
                # Move the output
                file_.rename(self.slurm_dir / file_.name)
            else:
                # Remove the output
                file_.unlink()
        # Clean up the sbatch file in the current dir where the experiment runs
        # Else keep it
        for file_ in Path(__CURRENT_DIR__).glob("*_shaman*.sbatch"):
            (Path(__CURRENT_DIR__) / file_).unlink()

    @property
    def api_url(self) -> str:
        """Returns as a string the URL to the API using the data in the
        configuration file."""
        return f"http://{api_settings.api_host}:{api_settings.api_port}"

    @property
    def start_experiment_dict(self) -> Dict:
        """Creates a dictionnary describing the experiment from its start."""
        return InitExperiment(
            **{
                "experiment_name": self.experiment_name,
                "experiment_start": self.experiment_start,
                "experiment_budget": self.nbr_iteration,
                "component": self.component_name,
                "experiment_parameters": dict(self.configuration.bbo),
                "noise_reduction_strategy":
                dict(self.configuration.noise_reduction)
                if self.configuration.noise_reduction
                else dict(),
                "pruning_strategy": {
                    "pruning_strategy": str(
                        self.configuration.pruning.max_step_duration
                    )
                    if self.configuration.pruning
                    else self.configuration.pruning
                },
                "sbatch": open(self.sbatch_file, "r").read(),
            }
        ).dict()

    def create_experiment(self) -> None:
        """Create the experiment upon initialization."""
        request = self.api_client.post(
            "experiments", json=self.start_experiment_dict)
        if not 200 <= request.status_code < 400:
            raise Exception(
                "Could not create experiment with status code"
                f"{request.status_code}"
            )
        self.experiment_id = request.json()["id"]

    @property
    def best_performance(self) -> float:
        """Returns the current best performance.

        Returns:
            float: The best time.
        """
        return self.bb_optimizer._get_best_performance()

    @property
    def improvement_default(self) -> float:
        """Computes the improvement compared to the default parametrization.

        Returns:
            float: The improvement compared to the default parametrization.
        """
        _, best_time = self.best_performance
        return float(
            round(
                (self.bb_wrapper.default_target_value - best_time)
                / self.bb_wrapper.default_target_value,
                2,
            )
            * 100
        )

    @property
    def average_noise(self) -> float:
        """Computes the average noise within the tested parametrization.

        Returns:
            float: The average measured noise.
        """
        return float(np.mean(self.bb_optimizer.measured_noise))

    def _updated_dict(self, history: Dict) -> Dict:
        """Builds the updated dictionary that will be sent at each iteration to
        the API.

        Args:
            history (Dict): The BBO history from the optimizer

        Returns:
            Dict: The updated dict to add to the POST request.
        """
        logger.debug(f"Current optimization history: {history}")
        best_parameters, best_fitness = self.best_performance
        logger.debug(f"Best parameters so far: {best_parameters}")
        logger.debug(f"Best performance so far: {best_fitness}")
        return IntermediateResult(
            **{
                "jobids": self.bb_wrapper.component.submitted_jobids[-1],
                "fitness": list(history["fitness"])[-1],
                "parameters": self.build_parameter_dict(
                    self.configuration.component_parameter_names,
                    history["parameters"].tolist(),
                )[-1],
                "truncated": bool(list(history["truncated"])[-1]),
                "resampled": bool(list(history["resampled"])[-1]),
                "initialization": bool(list(history["initialization"])[-1]),
                "improvement_default": self.improvement_default,
                "average_noise": self.average_noise,
                "explored_space":
                float(self.bb_optimizer.size_explored_space[0]),
                "best_parameters": self.build_parameter_dict(
                    self.configuration.component_parameter_names,
                    best_parameters.tolist(),
                ),
                "best_fitness": best_fitness,
            }
        ).dict()

    def update_history(self, history: Dict) -> None:
        """Update the optimization history at each BBO step and force
        conversion from numpy types.

        Args:
            history (dict): The BBO history
        """
        logger.debug(
            f"Writing update dictionary {self._updated_dict(history)}")
        request = self.api_client.put(
            f"experiments/{self.experiment_id}/update",
            json=self._updated_dict(history)
        )
        if not 200 <= request.status_code < 400:
            self.fail()
            raise Exception(
                "Could not finish experiment with status code"
                f"{request.status_code}"
            )

    @property
    def end_dict(self) -> Dict:
        """Comptues the dictionary sent to the API at the end of the
        experiment.

        Returns:
            Dict: The dictionary to send to the API.
        """
        best_parameters, best_fitness = self.best_performance
        return FinalResult(
            **{
                "averaged_fitness": self.bb_optimizer.averaged_fitness,
                "min_fitness": self.bb_optimizer.min_fitness,
                "max_fitness": self.bb_optimizer.max_fitness,
                "std_fitness": self.bb_optimizer.measured_noise,
                "resampled_nbr": self.bb_optimizer.resampled_nbr,
                "improvement_default": self.improvement_default,
                "elapsed_time": self.bb_optimizer.elapsed_time,
                "default_run": {
                    "fitness": self.bb_wrapper.default_target_value,
                    "job_id": self.bb_wrapper.default_jobid,
                    "parameters": self.bb_wrapper.default_parameters,
                },
                "average_noise": self.average_noise,
                "explored_space":
                float(self.bb_optimizer.size_explored_space[0]),
                "best_fitness": best_fitness,
                "best_parameters": self.build_parameter_dict(
                    self.configuration.component_parameter_names,
                    best_parameters.tolist(),
                ),
            }
        ).dict()

    def end(self):
        """End the experiment once it is over."""
        request = self.api_client.put(
            f"experiments/{self.experiment_id}/finish", json=self.end_dict
        )
        if not 200 <= request.status_code < 400:
            self.fail()
            raise Exception(
                "Could not finish experiment with status code"
                f"{request.status_code}"
            )

    def fail(self):
        """Fail the experiment.

        If there is an experiment id, sends a request at the endpoint
        /fail. Else, does not do anything (could be a good idea to
        perform some logging).
        """
        if self.experiment_id:
            request = self.api_client.put(
                f"experiments/{self.experiment_id}/fail")
            if not 200 <= request.status_code < 400:
                raise Exception(
                    "Could not fail experiment with status code"
                    f"{request.status_code}"
                )

    def stop(self):
        """Stop the experiment."""
        request = self.api_client.put(f"experiments/{self.experiment_id}/stop")
        if not 200 <= request.status_code < 400:
            raise Exception(
                "Could not fail experiment with status code"
                f"{request.status_code}"
            )

    def summarize(self):
        """Summarize the experiment by printing out the best parametrization,
        the associated fitness, and the BBO summary."""
        # Compute the optimal parametrization from the bb optimizer object
        optimal_param = self.build_parameter_dict(
            self.configuration.component_parameter_names,
            [self.bb_optimizer.best_parameters_in_grid],
        )
        print(f"Optimal time: {self.bb_optimizer.best_fitness}")
        print(
            f"Improvement compared to default:" f"{self.improvement_default}%")
        print(f"Optimal parametrization: {optimal_param}")
        print(
            "Number of early stops:"
            f"{sum(self.bb_optimizer.history['truncated'])}")
        print(
            "Average noise within each parametrization:"
            f"{self.bb_optimizer.measured_noise}"
        )
        self.bb_optimizer.summarize()

    @staticmethod
    def build_parameter_dict(
        parameter_names: List[str], parameter_values: List[List[float]]
    ) -> List[Dict]:
        """Static method to build the dictionary associated with the name of
        the parameters and their associated values.

        Args:
            parameter_names (list of str): The name of the parameters to use.
            parameter_values (list of lists of float):
                The values of the parameters

        Returns:
            list of dict: the dicts of the parameters with
                corresponding values.
        """
        # The list that will contain the dictionaries
        list_dict = []
        # Check if there is at least two nested elements in the dictionary
        if not isinstance(parameter_values[0], list):
            parameter_values = [parameter_values]
        for value in parameter_values:
            list_dict.append(dict(zip(parameter_names, value)))
        return list_dict
Esempio n. 29
0
class HTTPClient:
    def __init__(
        self,
        base_url: str,
        default_headers: Optional[dict] = None,
        default_params: Optional[dict] = None,
        history_len: int = 30,
    ):
        self.base_url = base_url
        self.default_headers = default_headers or {}
        self.default_params = default_params or {}

        self.history: Deque[Response] = deque(maxlen=history_len)

        self.http_client = Client(
            base_url=self.base_url, headers=default_headers, params=self.default_params
        )

    def get(self, url: str, params: dict, headers: Optional[dict] = None):
        custom_headers = headers or {}
        all_params = {**self._generate_params(), **params}

        logger.debug(f"Sending request to {url}", params=all_params, custom_headers=custom_headers)
        response = self.http_client.get(url=url, params=all_params, headers=custom_headers)

        self.history.append(response)

        body = response.text or "is empty!"

        logger.debug(f"Response return status_code: {response.status_code}, body: {body}")

        for cookie_name, cookie_data in response.cookies.items():
            self.http_client.cookies.set(cookie_name, cookie_data)
            logger.debug(f"New cookies: {dict(response.cookies)}")

        return response

    def post(
        self, url: str, data: dict, headers: Optional[dict] = None, params: Optional[dict] = None
    ):
        custom_headers = headers or {}
        custom_params = params or {}
        # merge parameters
        all_params = {**self._generate_params(), **custom_params}

        logger.debug(
            f"Sending request to {url}", params=all_params, custom_headers=custom_headers, data=data
        )

        response = self.http_client.post(
            url=url, params=all_params, data=data, headers=custom_headers,
        )

        self.history.append(response)

        body = response.text or "is empty!"
        logger.debug(f"Response return status_code: {response.status_code}, body: {body}")

        for cookie_name, cookie_data in response.cookies.items():
            self.http_client.cookies.set(cookie_name, cookie_data)
            logger.debug(f"New cookies: {dict(response.cookies)}")

        return response

    def _generate_params(self):
        now = str(int(round(time() * 1000)))

        params = {
            "_rticket": now,
            "ts": now,
            "mas": generate_mas(now),
            "as": generate_as(now),
            "cp": generate_cp(now),
            "idfa": str(uuid4()).upper(),
        }

        return params