Example #1
0
    def __post_init__(self) -> None:
        convert_params_headers(self.headers)
        convert_params_headers(self.params)

        if self.content_type is not None:
            if self.headers is None:
                self.headers = dict()
            MimeType.add_to_headers(self.headers, self.content_type)
    def test_from_headers(self, mimetype):
        headers = {"Content-Type": MimeType.to_string(mimetype)}
        extracted = MimeType.from_headers(headers)

        if isinstance(mimetype, MimeType):
            assert extracted is mimetype
        else:
            assert extracted == mimetype
Example #3
0
def _validate_response_content(
        response: requests.Response,
        data_schema: Optional[Schema] = None) -> Optional[Any]:
    if data_schema is None:
        return None

    try:
        try:
            mimetype: Optional[MimeTypeTolerant] = MimeType.from_name(
                response.headers.get("Content-Type"))
        except ValueError:
            mimetype = None

        loaded, _ = decode_content(
            response.content,
            mimetype=mimetype,
            data_schema=data_schema,
            allow_sniff=True,
        )
        return loaded

    except (json.JSONDecodeError, InvalidBSON, InvalidDocument,
            UnicodeDecodeError):
        raise ContentDecodeError("Could not load response data.")

    except ValidationError:
        raise DataValidationError("Error validating returned data")
Example #4
0
    def test_schema_round_trip(self, mimetype):

        data = DataToTest()
        schema = SchemaToTest()
        headers = dict()

        encoded = encode_content(
            data, mimetype=mimetype, headers=headers, data_schema=schema
        )
        print(encoded.decode())

        assert isinstance(encoded, bytes)
        header_content_type = headers["Content-Type"]
        if mimetype is None:
            assert header_content_type == MimeType.JSON.value
        else:
            assert header_content_type == MimeType.from_name(mimetype).value

        loaded, decoded = decode_content(
            encoded, mimetype=mimetype, data_schema=schema, allow_sniff=True
        )

        assert isinstance(loaded, DataToTest)
        assert loaded == data

        assert isinstance(decoded, Mapping)
Example #5
0
 def mimetype(self) -> Union[str, MimeType]:
     """Mimetype pulled from ``'Content-Type'`` request header."""
     mimetype = super().mimetype
     try:
         return MimeType.from_name(mimetype)
     except ValueError:
         return mimetype
Example #6
0
    async def execute(self) -> ResponseData:
        """
        Executes request and handles response from spanreed endpoint.
        """
        params = copy.copy(self.endpoint_settings.query_params)
        params.update(self.query_params)
        for key, value in self.projection.items():
            params["project." + key] = str(value)
        convert_params_headers(params)

        if self._paging is not None:
            self._paging.offset += self._paging.offset_start
            params["paging-offset"] = str(self._paging.offset)
            params["paging-limit"] = str(self._paging.limit)

        headers = copy.copy(self.endpoint_settings.headers)
        headers.update(self.headers)
        convert_params_headers(self.headers)

        if self.mimetype_accept is not None:
            headers["Accept"] = MimeType.to_string(self.mimetype_accept)

        base_url = (f"{self.client.protocol}://{self.client.host_name}"
                    f"{self.endpoint_settings.endpoint}")
        url = base_url.format(**self.path_params)

        req_schema = self.endpoint_settings.req_schema

        try:
            data = encode_content(
                content=self.media,
                mimetype=self.mimetype_send,
                headers=headers,
                data_schema=req_schema,
                encoders=self.client._ENCODERS,
            )
        except ContentTypeUnknownBase as error:
            raise ContentTypeUnknownError(str(error), response=None)

        # allow for method to be passed in caps.
        method = self.endpoint_settings.method.lower()
        method_func = getattr(self.client.session, method)

        response = await method_func(url=url,
                                     params=params,
                                     headers=headers,
                                     data=data)

        self.executed = True

        return await handle_response_aio(
            response=response,
            valid_status_codes=self.endpoint_settings.resp_codes,
            data_schema=self.endpoint_settings.resp_schema,
            api_errors_additional=self.client.api_error_index,
            current_data_object=self.update_obj,
            data_object_updater=self.endpoint_settings.data_updater,
            decoders=self.client._DECODERS,
        )
Example #7
0
def register_mimetype(mimetype: MimeTypeTolerant, encoder: EncoderType,
                      decoder: DecoderType) -> None:
    try:
        mimetype = MimeType.from_name(mimetype)
    except ValueError:
        pass

    SpanClient._ENCODERS[mimetype] = encoder
    SpanClient._DECODERS[mimetype] = decoder
Example #8
0
    def __post_init__(self) -> None:
        self.content_type = None
        mock_text = self._text

        if self._json is not None:
            self.mock_json(self._json)
        elif self._yaml is not None:
            self.mock_yaml(self._yaml)
        elif self._bson is not None:
            self.mock_bson(self._bson)
        elif mock_text is not None:
            self.mock_text(mock_text)

        if self._content_type is not None:
            self.content_type = MimeType.to_string(
                self._content_type)  # type: ignore

        if self.content_type is not None:
            MimeType.add_to_headers(self.headers, self.content_type)

        if self._exception is not None:
            self.mock_exception(self._exception)
Example #9
0
    def test_data_round_trip(self, mimetype):
        data = {"key": 10}
        headers = dict()

        encoded = encode_content(data, mimetype=mimetype, headers=headers)
        print(str(encoded))

        assert isinstance(encoded, bytes)
        assert headers["Content-Type"] == MimeType.from_name(mimetype).value

        loaded, decoded = decode_content(encoded, mimetype=mimetype)

        assert dict(decoded) == dict(loaded) == data
Example #10
0
    def register_mimetype(self, mimetype: MimeTypeTolerant,
                          encoder: EncoderType, decoder: DecoderType) -> None:
        """
        Registers encoder and decoder function for a given mimetype.

        :param mimetype: to register for ex: ``'text/csv'``.
        :param encoder: Encodes mimetype data to binary.
        :param decoder: Decodes mimetype data to binary.
        :return:
        """
        try:
            mimetype = MimeType.from_name(mimetype)
        except ValueError:
            pass

        self._encoders[mimetype] = encoder
        self._decoders[mimetype] = decoder
    def mimetype(self) -> MimeTypeTolerant:
        if self._mimetype is NOT_LOADED:

            # Check the builtin content type first.
            mimetype: MimeTypeTolerant = self.message.content_type
            if not mimetype:
                # if that is none, check the custom header.
                mimetype = self.headers.get("Content-Type")

            if mimetype:
                try:
                    mimetype = MimeType.from_name(mimetype)
                except ValueError:
                    pass
            else:
                mimetype = None

            self._mimetype = mimetype

        return self._mimetype
Example #12
0
    def validate_request(
        self,
        req_url: str,
        req_headers: MutableMapping[str, str],
        req_params: MutableMapping[str, str],
        req_data: Optional[bytes],
        mock_response: MockResponse,
    ) -> None:
        self.req_url = req_url
        self.req_params = req_params
        self.req_headers = req_headers
        self.req_data = req_data
        self.req_data_decoded = None

        self.validate_url()
        self.validate_headers()
        self.validate_params()

        mimetype = MimeType.from_headers(req_headers)
        self.validate_media(mimetype=mimetype)
        self.validate_media_type(mimetype)

        if self.custom_hook is not None:
            self.custom_hook(self, mock_response)
 def test_to_string_none_error(self):
     with pytest.raises(ValueError):
         MimeType.to_string(None)
 def test_is_mimetype_none(self):
     assert MimeType.is_mimetype(None, MimeType.JSON) is False
 def test_mimetype_parsing(self, name: str):
     assert MimeType.from_name(name) is MimeType.JSON
Example #16
0
async def handle_response_aio(
    response: ClientResponse,
    valid_status_codes: Union[int, Tuple[int, ...]] = 200,
    data_schema: Optional[Union[Schema, MimeType]] = None,
    api_errors_additional: Optional[Dict[int, Type[APIError]]] = None,
    current_data_object: Optional[ModelType] = None,
    data_object_updater: Optional[Callable[[ModelType, Any], None]] = None,
    decoders: DecoderIndexType = DEFAULT_DECODERS,
) -> ResponseData:
    """
    Examines response from SpanReed service and raises reported errors.

    :param response: from aiohttp
    :param valid_status_codes: Valid return http code(s).
    :param data_schema: Schema object for loading responses.
    :param api_errors_additional: Code, Error Class Mapping of Additional APIError types
        the response may return.
    :param current_data_object: Current object which represents response payload. Will
        be updated in-place with response data.
    :param data_object_updater: Callable which takes args:
        (current_data_object, new_data_object). Used to update current_data_object
        in place of the default updater.

    :return: Loaded data, raw data mapping (dict or bson record).

    :raises ResponseStatusError: If status code does match.
    :raises ContentTypeUnknownError: If content-type is not a type that is known.
    :raises marshmallow.ValidationError: If data not consistent with schema.
    """

    # Try to raise error, catch if it does not exist.
    try:
        raise Error.from_headers(response.headers).to_exception(api_errors_additional)
    except NoErrorReturnedError:
        pass

    _check_status_code(
        received_code=response.status,
        valid_status_codes=valid_status_codes,
        response=response,
    )

    content = await response.read()

    if content or data_schema is not None:
        try:
            loaded_data, decoded_data = decode_content(
                content=content,
                mimetype=MimeType.from_headers(response.headers),
                data_schema=data_schema,
                allow_sniff=True,
                decoders=decoders,
            )
        except ContentDecodeBase as error:
            raise ContentDecodeError(str(error), response=response)
        except ContentTypeUnknownBase as error:
            raise ContentTypeUnknownError(str(error), response=response)
    else:
        loaded_data, decoded_data = None, None

    if current_data_object is not None:
        _update_data(
            current_data_object=current_data_object,
            new_data_object=loaded_data,
            object_updater=data_object_updater,
        )
        loaded_data = current_data_object

    return ResponseData(resp=response, loaded=loaded_data, decoded=decoded_data)
    def test_add_none_to_headers(self):
        headers = dict()
        MimeType.add_to_headers(headers, None)

        assert headers == dict()