コード例 #1
0
class DigitalTwinsClient(object):  # type: ignore #pylint: disable=too-many-public-methods
    """Creates an instance of AzureDigitalTwinsAPI.

    :param str endpoint: The URL endpoint of an Azure search service
    :param ~azure.core.credentials.AzureKeyCredential credential:
        A credential to authenticate requests to the service
    """
    def __init__(self, endpoint, credential, **kwargs):
        # type: (str, AzureKeyCredential, **Any) -> None

        client_models = {
            k: v
            for k, v in models.__dict__.items() if isinstance(v, type)
        }
        self._serialize = Serializer(client_models)
        self._deserialize = Deserializer(client_models)
        self.endpoint = endpoint  #type: str
        self.credential = credential  #type AzureKeyCredential
        self._client = AzureDigitalTwinsAPI(
            credential=credential, base_url=endpoint,
            **kwargs)  #type: AzureDigitalTwinsAPI

    async def close(self) -> None:
        await self._client.close()

    async def __aenter__(self) -> "DigitalTwinsClient":
        await self._client.__aenter__()
        return self

    async def __aexit__(self, *exc_details) -> None:
        await self._client.__aexit__(*exc_details)

    @distributed_trace_async
    async def get_digital_twin(self, digital_twin_id, **kwargs):
        # type: (str, **Any) -> Dict[str, object]
        """Get a digital twin.

        :param str digital_twin_id: The Id of the digital twin.
        :return: Dictionary containing the twin.
        :rtype: Dict[str, object]
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`:
            If the digital twin doesn't exist.
        """
        return await self._client.digital_twins.get_by_id(
            digital_twin_id, **kwargs)

    @distributed_trace_async
    async def upsert_digital_twin(self, digital_twin_id, digital_twin,
                                  **kwargs):
        # type: (str, Dict[str, object], **Any) -> Dict[str, object]
        """Create or update a digital twin.

        :param str digital_twin_id: The Id of the digital twin.
        :param Dict[str, object] digital_twin:
            Dictionary containing the twin to create or update.
        :return: Dictionary containing the created or updated twin.
        :rtype: Dict[str, object]
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`:
            If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceExistsError`:
            If the digital twin is already exist.
        """
        return await self._client.digital_twins.add(digital_twin_id,
                                                    digital_twin, **kwargs)

    @distributed_trace_async
    async def update_digital_twin(self, digital_twin_id, json_patch, **kwargs):
        # type: (str, Dict[str, object], **Any) -> None
        """Update a digital twin using a json patch.

        :param str digital_twin_id: The Id of the digital twin.
        :param Dict[str, object] json_patch: An update specification described by JSON Patch.
            Updates to property values and $model elements may happen in the same request.
            Operations are limited to add, replace and remove.
        :keyword str etag: Only perform the operation if the entity's etag matches one of
            the etags provided or * is provided.
        :keyword ~azure.core.MatchConditions match_condition:
            The match condition to use upon the etag
        :return: None
        :rtype: None
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`:
            If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`:
            If there is no digital twin with the provided id.
        """
        etag = kwargs.get("etag", None)
        match_condition = kwargs.get("match_condition",
                                     MatchConditions.Unconditionally)

        return await self._client.digital_twins.update(digital_twin_id,
                                                       json_patch,
                                                       if_match=prep_if_match(
                                                           etag,
                                                           match_condition),
                                                       **kwargs)

    @distributed_trace_async
    async def delete_digital_twin(self, digital_twin_id, **kwargs):
        # type: (str, **Any) -> None
        """Delete a digital twin.

        :param str digital_twin_id: The Id of the digital twin.
        :keyword str etag: Only perform the operation if the entity's etag matches one of
            the etags provided or * is provided.
        :keyword ~azure.core.MatchConditions match_condition: the match condition to use upon the etag
        :return: None
        :rtype: None
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`:
            If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`:
            If there is no digital twin with the provided id.
        """
        etag = kwargs.get("etag", None)
        match_condition = kwargs.get("match_condition",
                                     MatchConditions.Unconditionally)

        return await self._client.digital_twins.delete(digital_twin_id,
                                                       if_match=prep_if_match(
                                                           etag,
                                                           match_condition),
                                                       **kwargs)

    @distributed_trace_async
    async def get_component(self, digital_twin_id, component_path, **kwargs):
        # type: (str, str, **Any) -> Dict[str, object]
        """Get a component on a digital twin.

        :param str digital_twin_id: The Id of the digital twin.
        :param str component_path: The component being retrieved.
        :return: Dictionary containing the component.
        :rtype: Dict[str, object]
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is either no
            digital twin with the provided id or the component path is invalid.
        """
        return await self._client.digital_twins.get_component(
            digital_twin_id, component_path, **kwargs)

    @distributed_trace_async
    async def update_component(self, digital_twin_id, component_path,
                               json_patch, **kwargs):
        # type: (str, str, Dict[str, object], **Any) -> None
        """Update properties of a component on a digital twin using a JSON patch.

        :param str digital_twin_id: The Id of the digital twin.
        :param str component_path: The component being updated.
        :param Dict[str, object] json_patch: An update specification described by JSON Patch.
        :keyword str etag: Only perform the operation if the entity's etag matches one of
            the etags provided or * is provided.
        :keyword ~azure.core.MatchConditions match_condition: the match condition to use upon the etag
        :return: None
        :rtype: None
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is either no
            digital twin with the provided id or the component path is invalid.
        """
        etag = kwargs.get("etag", None)
        match_condition = kwargs.get("match_condition",
                                     MatchConditions.Unconditionally)

        return await self._client.digital_twins.update_component(
            digital_twin_id,
            component_path,
            patch_document=json_patch,
            if_match=prep_if_match(etag, match_condition),
            **kwargs)

    @distributed_trace_async
    async def get_relationship(self, digital_twin_id, relationship_id,
                               **kwargs):
        # type: (str, str, **Any) -> Dict[str, object]
        """Get a relationship on a digital twin.

        :param str digital_twin_id: The Id of the digital twin.
        :param str relationship_id: The Id of the relationship to retrieve.
        :return: Dictionary containing the relationship.
        :rtype: Dict[str, object]
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is either no
            digital twin or relationship with the provided id.
        """
        return await self._client.digital_twins.get_relationship_by_id(
            digital_twin_id, relationship_id, **kwargs)

    @distributed_trace_async
    async def upsert_relationship(self,
                                  digital_twin_id,
                                  relationship_id,
                                  relationship=None,
                                  **kwargs):
        # type: (str, str, Optional[Dict[str, object]], **Any) -> Dict[str, object]
        """Create or update a relationship on a digital twin.

        :param str digital_twin_id: The Id of the digital twin.
        :param str relationship_id: The Id of the relationship to retrieve.
        :param Dict[str, object] relationship: Dictionary containing the relationship.
        :return: The created or updated relationship.
        :rtype: Dict[str, object]
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is either no
            digital twin, target digital twin or relationship with the provided id.
        """
        return await self._client.digital_twins.add_relationship(
            id=digital_twin_id,
            relationship_id=relationship_id,
            relationship=relationship,
            **kwargs)

    @distributed_trace_async
    async def update_relationship(self,
                                  digital_twin_id,
                                  relationship_id,
                                  json_patch=None,
                                  **kwargs):
        # type: (str, str, Dict[str, object], **Any) -> None
        """Updates the properties of a relationship on a digital twin using a JSON patch.

        :param str digital_twin_id: The Id of the digital twin.
        :param str relationship_id: The Id of the relationship to retrieve.
        :param Dict[str, object] json_patch: JSON Patch description of the update
            to the relationship properties.
        :keyword str etag: Only perform the operation if the entity's etag matches one of
            the etags provided or * is provided.
        :keyword ~azure.core.MatchConditions match_condition: the match condition to use upon the etag
        :return: None
        :rtype: None
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is either no
            digital twin or relationship with the provided id.
        """
        etag = kwargs.get("etag", None)
        match_condition = kwargs.get("match_condition",
                                     MatchConditions.Unconditionally)

        return await self._client.digital_twins.update_relationship(
            id=digital_twin_id,
            relationship_id=relationship_id,
            json_patch=json_patch,
            if_match=prep_if_match(etag, match_condition),
            **kwargs)

    @distributed_trace_async
    async def delete_relationship(self, digital_twin_id, relationship_id,
                                  **kwargs):
        # type: (str, str, **Any) -> None
        """Delete a digital twin.

        :param str digital_twin_id: The Id of the digital twin.
        :param str relationship_id: The Id of the relationship to delete.
        :keyword str etag: Only perform the operation if the entity's etag matches one of
            the etags provided or * is provided.
        :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag.
        :return: None
        :rtype: None
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is either no
            digital twin or relationship with the provided id.
        """
        etag = kwargs.get("etag", None)
        match_condition = kwargs.get("match_condition",
                                     MatchConditions.Unconditionally)

        return await self._client.digital_twins.delete_relationship(
            digital_twin_id,
            relationship_id,
            if_match=prep_if_match(etag, match_condition),
            **kwargs)

    @distributed_trace_async
    async def list_relationships(self,
                                 digital_twin_id,
                                 relationship_id=None,
                                 **kwargs):
        # type: (str, Optional[str], **Any) -> ~AsyncItemPaged[~azure.digitaltwins.models.Relationship]
        """Retrieve relationships for a digital twin.

        :param str digital_twin_id: The Id of the digital twin.
        :param str relationship_id: The Id of the relationship to
            get (if None all the relationship will be retrieved).
        :return: An iterator instance of list of Relationship
        :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.digitaltwins.models.Relationship]
        :raises: ~azure.core.exceptions.HttpResponseError
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is no
            digital twin with the provided id.
        """
        return await self._client.digital_twins.list_relationships(
            digital_twin_id, relationship_name=relationship_id, **kwargs)

    @distributed_trace_async
    async def list_incoming_relationships(self, digital_twin_id, **kwargs):
        # type: (str, str, **Any) -> ~azure.core.paging.AsyncItemPaged[~azure.digitaltwins.models.IncomingRelationship]
        """Retrieve all incoming relationships for a digital twin.

        :param str digital_twin_id: The Id of the digital twin.
        :return: An iterator like instance of either Relationship.
        :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.digitaltwins.models.IncomingRelationship]
        :raises: ~azure.core.exceptions.HttpResponseError
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is no
            digital twin with the provided id.
        """
        return await self._client.digital_twins.list_incoming_relationships(
            digital_twin_id, **kwargs)

    @distributed_trace_async
    async def publish_telemetry(self,
                                digital_twin_id,
                                payload,
                                message_id=None,
                                **kwargs):
        # type: (str, object, Optional[str], **Any) -> None
        """Publish telemetry from a digital twin, which is then consumed by
           one or many destination endpoints (subscribers) defined under.

        :param str digital_twin_id: The Id of the digital twin
        :param object payload: The telemetry payload to be sent
        :param str message_id: The message Id
        :return: None
        :rtype: None
        :raises: ~azure.core.exceptions.HttpResponseError
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is no
            digital twin with the provided id.
        """
        if not message_id:
            message_id = uuid.UUID
        timestamp = datetime.now

        return await self._client.digital_twins.send_telemetry(
            digital_twin_id,
            message_id,
            telemetry=payload,
            dt_timestamp=timestamp,
            **kwargs)

    @distributed_trace_async
    async def publish_component_telemetry(self,
                                          digital_twin_id,
                                          component_path,
                                          payload,
                                          message_id=None,
                                          **kwargs):
        # type: (str, str, object, Optional[str], **Any) -> None
        """Publish telemetry from a digital twin's component, which is then consumed by
            one or many destination endpoints (subscribers) defined under.

        :param str digital_twin_id: The Id of the digital twin.
        :param str component_path: The name of the DTDL component.
        :param object payload: The telemetry payload to be sent.
        :param str message_id: The message Id.
        :return: None
        :rtype: None
        :raises: ~azure.core.exceptions.HttpResponseError
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is no
            digital twin with the provided id or the component path is invalid.
        """
        if not message_id:
            message_id = uuid.UUID
        timestamp = datetime.now

        return await self._client.digital_twins.send_component_telemetry(
            digital_twin_id,
            component_path,
            dt_id=message_id,
            telemetry=payload,
            dt_timestamp=timestamp,
            **kwargs)

    @distributed_trace_async
    async def get_model(self, model_id, **kwargs):
        # type: (str, **Any) -> ~azure.digitaltwins.models.ModelData
        """Get a model, including the model metadata and the model definition.

        :param str model_id: The Id of the model.
        :keyword bool include_model_definition: When true the model definition
            will be returned as part of the result.
        :return: The ModelDate object.
        :rtype: ~azure.digitaltwins.models.ModelData
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: If there is no
            model with the provided id.
        """
        include_model_definition = kwargs.get("include_model_definition",
                                              False)

        return await self._client.digital_twin_models.get_by_id(
            model_id, include_model_definition, **kwargs)

    @distributed_trace_async
    async def list_models(self, dependencies_for, **kwargs):
        # type: (str, bool, int, **Any) -> ~azure.core.paging.AsyncItemPaged[~azure.digitaltwins.models.ModelData]
        """Get the list of models.

        :param List[str] dependencies_for: The model Ids to have dependencies retrieved.
            If omitted, all models are retrieved.
        :keyword bool include_model_definition: When true the model definition
            will be returned as part of the result.
        :keyword int results_per_page: The maximum number of items to retrieve per request.
            The server may choose to return less than the requested max.
        :return: An iterator instance of list of ModelData.
        :rtype: ~azure.core.paging.AsyncItemPaged[~azure.digitaltwins.models.ModelData]
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        """
        include_model_definition = kwargs.pop('include_model_definition',
                                              False)

        results_per_page = kwargs.pop('results_per_page', None)
        digital_twin_models_list_options = None
        if results_per_page is not None:
            digital_twin_models_list_options = {
                'max_item_count': results_per_page
            }

        return await self._client.digital_twin_models.list(
            dependencies_for=dependencies_for,
            include_model_definition=include_model_definition,
            digital_twin_models_list_options=digital_twin_models_list_options,
            **kwargs)

    @distributed_trace_async
    async def create_models(self, model_list=None, **kwargs):
        # type: (Optional[List[object]], **Any) -> List[~azure.digitaltwins.models.ModelData]
        """Create one or more models. When any error occurs, no models are uploaded.

        :param List[object] model_list: The set of models to create. Each string corresponds to exactly one model.
        :return: The list of ModelData
        :rtype: List[~azure.digitaltwins.models.ModelData]
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: One or more of
            the provided models already exist.
        """
        return await self._client.digital_twin_models.add(model_list, **kwargs)

    @distributed_trace_async
    async def decommission_model(self, model_id, **kwargs):
        # type: (str, **Any) -> None
        """Decommissions a model.

        :param str model_id: The id for the model. The id is globally unique and case sensitive.
        :return: None
        :rtype: None
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: There is no model
            with the provided id.
        """
        json_patch = "{ 'op': 'replace', 'path': '/decommissioned', 'value': true }"

        return await self._client.digital_twin_models.update(
            model_id, json_patch, **kwargs)

    @distributed_trace_async
    async def delete_model(self, model_id, **kwargs):
        # type: (str, **Any) -> None
        """Decommission a model using a json patch.

        :param str model_id: The Id of the model to decommission.
        :return: None
        :rtype: None
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: If the request is invalid.
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: There is no model
            with the provided id.
        :raises :class: `~azure.core.exceptions.ResourceExistsError`: There are dependencies
            on the model that prevent it from being deleted.
        """
        return await self._client.digital_twin_models.delete(
            model_id, **kwargs)

    @distributed_trace_async
    async def get_event_route(self, event_route_id, **kwargs):
        # type: (str, **Any) -> ~azure.digitaltwins.models.EventRoute
        """Get an event route.

        :param str event_route_id: The Id of the event route.
        :return: The EventRoute object.
        :rtype: ~azure.digitaltwins.models.EventRoute
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: There is no
            event route with the provided id.
        """
        return await self._client.event_routes.get_by_id(
            event_route_id, **kwargs)

    @distributed_trace_async
    async def list_event_routes(self, **kwargs):
        # type: (**Any) -> ~azure.core.paging.AsyncItemPaged[~azure.digitaltwins.models.EventRoute]
        """Retrieves all event routes.

        :keyword int results_per_page: The maximum number of items to retrieve per request.
            The server may choose to return less than the requested max.
        :return: An iterator instance of list of EventRoute.
        :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.digitaltwins.models.EventRoute]
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: The request is invalid.
        """
        event_routes_list_options = None
        results_per_page = kwargs.pop('results_per_page', None)
        if results_per_page is not None:
            event_routes_list_options = {'max_item_count': results_per_page}

        return await self._client.event_routes.list(
            event_routes_list_options=event_routes_list_options, **kwargs)

    @distributed_trace_async
    async def upsert_event_route(self, event_route_id, event_route, **kwargs):
        # type: (str, "models.EventRoute", **Any) -> None
        """Create or update an event route.

        :param str event_route_id: The Id of the event route to create or update.
        :param ~azure.digitaltwins.models.EventRoute event_route: The event route data.
        :return: None
        :rtype: None
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ServiceRequestError`: The request is invalid.
        """
        return await self._client.event_routes.add(event_route_id, event_route,
                                                   **kwargs)

    @distributed_trace_async
    async def delete_event_route(self, event_route_id, **kwargs):
        # type: (str, **Any) -> None
        """Delete an event route.

        :param str event_route_id: The Id of the event route to delete.
        :return: None
        :rtype: None
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        :raises :class: `~azure.core.exceptions.ResourceNotFoundError`: There is no
            event route with the provided id.
        """
        return await self._client.event_routes.delete(event_route_id, **kwargs)

    @distributed_trace_async
    async def query_twins(self, query_expression, **kwargs):
        # type: (str, **Any) -> ~azure.core.async_paging.AsyncItemPaged[Dict[str, object]]
        """Query for digital twins.

        :param str query_expression: The query expression to execute.
        :return: The QueryResult object.
        :rtype: ~azure.core.async_paging.AsyncItemPaged[Dict[str, object]]
        :raises :class: `~azure.core.exceptions.HttpResponseError`
        """
        def extract_data(pipeline_response):
            deserialized = self._deserialize('QueryResult', pipeline_response)
            list_of_elem = deserialized.value
            return deserialized.continuation_token or None, iter(list_of_elem)

        async def get_next(continuation_token=None):
            query_spec = self._serialize.serialize_dict(
                {
                    'query': query_expression,
                    'continuation_token': continuation_token
                }, 'QuerySpecification')
            pipeline_response = await self._client.query.query_twins(
                query_spec, **kwargs)
            return pipeline_response

        return AsyncItemPaged(get_next, extract_data)
コード例 #2
0
class TestRuntimeSerialized(unittest.TestCase):
    class TestObj(Model):

        _validation = {}
        _attribute_map = {
            'attr_a': {
                'key': 'id',
                'type': 'str'
            },
            'attr_b': {
                'key': 'AttrB',
                'type': 'int'
            },
            'attr_c': {
                'key': 'Key_C',
                'type': 'bool'
            },
            'attr_d': {
                'key': 'AttrD',
                'type': '[int]'
            },
            'attr_e': {
                'key': 'AttrE',
                'type': '{float}'
            }
        }

        def __init__(self):

            self.attr_a = None
            self.attr_b = None
            self.attr_c = None
            self.attr_d = None
            self.attr_e = None

        def __str__(self):
            return "Test_Object"

    def setUp(self):
        self.s = Serializer()
        return super(TestRuntimeSerialized, self).setUp()

    def test_validate(self):
        # Assert not necessary, should not raise exception
        self.s.validate("simplestring", "StringForLog", pattern="^[a-z]+$")
        self.s.validate(u"UTF8ééééé", "StringForLog", pattern=r"^[\w]+$")

    def test_obj_serialize_none(self):
        """Test that serialize None in object is still None.
        """
        obj = self.s.serialize_object({'test': None})
        self.assertIsNone(obj['test'])

    def test_obj_without_attr_map(self):
        """
        Test serializing an object with no attribute_map.
        """
        test_obj = type("BadTestObj", (), {})

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_obj_with_malformed_map(self):
        """
        Test serializing an object with a malformed attribute_map.
        """
        test_obj = type("BadTestObj", (Model, ), {"_attribute_map": None})

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        test_obj._attribute_map = {"attr": "val"}

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        test_obj._attribute_map = {"attr": {"val": 1}}

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_obj_with_mismatched_map(self):
        """
        Test serializing an object with mismatching attributes and map.
        """
        test_obj = type("BadTestObj", (Model, ), {"_attribute_map": None})
        test_obj._attribute_map = {"abc": {"key": "ABC", "type": "str"}}

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_attr_none(self):
        """
        Test serializing an object with None attributes.
        """
        test_obj = self.TestObj()
        message = self.s._serialize(test_obj)

        self.assertIsInstance(message, dict)
        self.assertFalse('id' in message)

    def test_attr_int(self):
        """
        Test serializing an object with Int attributes.
        """
        test_obj = self.TestObj()
        self.TestObj._validation = {
            'attr_b': {
                'required': True
            },
        }
        test_obj.attr_b = None

        with self.assertRaises(ValidationError):
            self.s._serialize(test_obj)

        test_obj.attr_b = 25

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrB'], int(test_obj.attr_b))

        test_obj.attr_b = "34534"

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrB'], int(test_obj.attr_b))

        test_obj.attr_b = "NotANumber"

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        self.TestObj._validation = {}

    def test_attr_str(self):
        """
        Test serializing an object with Str attributes.
        """
        test_obj = self.TestObj()
        self.TestObj._validation = {
            'attr_a': {
                'required': True
            },
        }
        test_obj.attr_a = None

        with self.assertRaises(ValidationError):
            self.s._serialize(test_obj)

        self.TestObj._validation = {}
        test_obj.attr_a = "TestString"

        message = self.s._serialize(test_obj)
        self.assertEqual(message['id'], str(test_obj.attr_a))

        test_obj.attr_a = 1234

        message = self.s._serialize(test_obj)
        self.assertEqual(message['id'], str(test_obj.attr_a))

        test_obj.attr_a = list()

        message = self.s._serialize(test_obj)
        self.assertEqual(message['id'], str(test_obj.attr_a))

        test_obj.attr_a = [1]

        message = self.s._serialize(test_obj)
        self.assertEqual(message['id'], str(test_obj.attr_a))

    def test_attr_bool(self):
        """
        Test serializing an object with bool attributes.
        """
        test_obj = self.TestObj()
        test_obj.attr_c = True

        message = self.s._serialize(test_obj)
        self.assertEqual(message['Key_C'], True)

        test_obj.attr_c = ""

        message = self.s._serialize(test_obj)
        self.assertTrue('Key_C' in message)

        test_obj.attr_c = None

        message = self.s._serialize(test_obj)
        self.assertFalse('Key_C' in message)

        test_obj.attr_c = "NotEmpty"

        message = self.s._serialize(test_obj)
        self.assertEqual(message['Key_C'], True)

    def test_attr_sequence(self):
        """
        Test serializing a sequence.
        """

        test_obj = ["A", "B", "C"]
        output = self.s._serialize(test_obj, '[str]', div='|')
        self.assertEqual(output, "|".join(test_obj))

        test_obj = [1, 2, 3]
        output = self.s._serialize(test_obj, '[str]', div=',')
        self.assertEqual(output, ",".join([str(i) for i in test_obj]))

    def test_attr_list_simple(self):
        """
        Test serializing an object with simple-typed list attributes
        """
        test_obj = self.TestObj()
        test_obj.attr_d = []

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrD'], test_obj.attr_d)

        test_obj.attr_d = [1, 2, 3]

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrD'], test_obj.attr_d)

        test_obj.attr_d = ["1", "2", "3"]

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrD'], [int(i) for i in test_obj.attr_d])

        test_obj.attr_d = ["test", "test2", "test3"]

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        test_obj.attr_d = "NotAList"

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_empty_list(self):

        input = []
        output = self.s._serialize(input, '[str]')
        self.assertEqual(output, input)

    def test_attr_list_complex(self):
        """
        Test serializing an object with a list of complex objects as an attribute.
        """
        list_obj = type("ListObj", (Model, ), {
            "_attribute_map": None,
            "_validation": {},
            "abc": None
        })
        list_obj._attribute_map = {"abc": {"key": "ABC", "type": "int"}}
        list_obj.abc = "123"

        test_obj = type("CmplxTestObj", (Model, ), {
            "_attribute_map": None,
            "_validation": {},
            "test_list": None
        })

        test_obj._attribute_map = {
            "test_list": {
                "key": "_list",
                "type": "[ListObj]"
            }
        }
        test_obj.test_list = [list_obj]

        message = self.s._serialize(test_obj)
        self.assertEqual(message, {'_list': [{'ABC': 123}]})

        list_obj = type("BadListObj", (Model, ), {"map": None})
        test_obj._attribute_map = {
            "test_list": {
                "key": "_list",
                "type": "[BadListObj]"
            }
        }
        test_obj.test_list = [list_obj]

        s = self.s._serialize(test_obj)
        self.assertEqual(s, {'_list': [{}]})

    def test_attr_dict_simple(self):
        """
        Test serializing an object with a simple dictionary attribute.
        """

        test_obj = self.TestObj()
        test_obj.attr_e = {"value": 3.14}

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrE']['value'],
                         float(test_obj.attr_e["value"]))

        test_obj.attr_e = {1: "3.14"}

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrE']['1'], float(test_obj.attr_e[1]))

        test_obj.attr_e = "NotADict"

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        test_obj.attr_e = {"value": "NotAFloat"}

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_serialize_datetime(self):

        date_obj = isodate.parse_datetime('2015-01-01T00:00:00')
        date_str = Serializer.serialize_iso(date_obj)

        self.assertEqual(date_str, '2015-01-01T00:00:00.000Z')

        date_obj = isodate.parse_datetime('1999-12-31T23:59:59-12:00')
        date_str = Serializer.serialize_iso(date_obj)

        self.assertEqual(date_str, '2000-01-01T11:59:59.000Z')

        with self.assertRaises(SerializationError):
            date_obj = isodate.parse_datetime('9999-12-31T23:59:59-12:00')
            date_str = Serializer.serialize_iso(date_obj)

        with self.assertRaises(SerializationError):
            date_obj = isodate.parse_datetime('0001-01-01T00:00:00+23:59')
            date_str = Serializer.serialize_iso(date_obj)

        date_obj = isodate.parse_datetime("2015-06-01T16:10:08.0121-07:00")
        date_str = Serializer.serialize_iso(date_obj)

        self.assertEqual(date_str, '2015-06-01T23:10:08.0121Z')

        date_obj = datetime.min
        date_str = Serializer.serialize_iso(date_obj)
        self.assertEqual(date_str, '0001-01-01T00:00:00.000Z')

        date_obj = datetime.max
        date_str = Serializer.serialize_iso(date_obj)
        self.assertEqual(date_str, '9999-12-31T23:59:59.999999Z')

    def test_serialize_primitive_types(self):

        a = self.s.serialize_data(1, 'int')
        self.assertEqual(a, 1)

        b = self.s.serialize_data(True, 'bool')
        self.assertEqual(b, True)

        c = self.s.serialize_data('True', 'str')
        self.assertEqual(c, 'True')

        d = self.s.serialize_data(100.0123, 'float')
        self.assertEqual(d, 100.0123)

    def test_serialize_object(self):

        a = self.s.body(1, 'object')
        self.assertEqual(a, 1)

        b = self.s.body(True, 'object')
        self.assertEqual(b, True)

        c = self.s.serialize_data('True', 'object')
        self.assertEqual(c, 'True')

        d = self.s.serialize_data(100.0123, 'object')
        self.assertEqual(d, 100.0123)

        e = self.s.serialize_data({}, 'object')
        self.assertEqual(e, {})

        f = self.s.body({"test": "data"}, 'object')
        self.assertEqual(f, {"test": "data"})

        g = self.s.body({"test": {"value": "data"}}, 'object')
        self.assertEqual(g, {"test": {"value": "data"}})

        h = self.s.serialize_data({"test": self.TestObj()}, 'object')
        self.assertEqual(h, {"test": "Test_Object"})

        i = self.s.serialize_data({"test": [1, 2, 3, 4, 5]}, 'object')
        self.assertEqual(i, {"test": [1, 2, 3, 4, 5]})

    def test_serialize_empty_iter(self):

        a = self.s.serialize_dict({}, 'int')
        self.assertEqual(a, {})

        b = self.s.serialize_iter([], 'int')
        self.assertEqual(b, [])

    def test_serialize_json_obj(self):
        class ComplexId(Model):

            _validation = {}
            _attribute_map = {
                'id': {
                    'key': 'id',
                    'type': 'int'
                },
                'name': {
                    'key': 'name',
                    'type': 'str'
                },
                'age': {
                    'key': 'age',
                    'type': 'float'
                },
                'male': {
                    'key': 'male',
                    'type': 'bool'
                },
                'birthday': {
                    'key': 'birthday',
                    'type': 'iso-8601'
                },
                'anniversary': {
                    'key': 'anniversary',
                    'type': 'iso-8601'
                }
            }

            id = 1
            name = "Joey"
            age = 23.36
            male = True
            birthday = '1992-01-01T00:00:00.000Z'
            anniversary = isodate.parse_datetime('2013-12-08T00:00:00')

        class ComplexJson(Model):

            _validation = {}
            _attribute_map = {
                'p1': {
                    'key': 'p1',
                    'type': 'str'
                },
                'p2': {
                    'key': 'p2',
                    'type': 'str'
                },
                'top_date': {
                    'key': 'top_date',
                    'type': 'iso-8601'
                },
                'top_dates': {
                    'key': 'top_dates',
                    'type': '[iso-8601]'
                },
                'insider': {
                    'key': 'insider',
                    'type': '{iso-8601}'
                },
                'top_complex': {
                    'key': 'top_complex',
                    'type': 'ComplexId'
                }
            }

            p1 = 'value1'
            p2 = 'value2'
            top_date = isodate.parse_datetime('2014-01-01T00:00:00')
            top_dates = [
                isodate.parse_datetime('1900-01-01T00:00:00'),
                isodate.parse_datetime('1901-01-01T00:00:00')
            ]
            insider = {
                'k1': isodate.parse_datetime('2015-01-01T00:00:00'),
                'k2': isodate.parse_datetime('2016-01-01T00:00:00'),
                'k3': isodate.parse_datetime('2017-01-01T00:00:00')
            }
            top_complex = ComplexId()

        message = self.s._serialize(ComplexJson())

        output = {
            'p1': 'value1',
            'p2': 'value2',
            'top_date': '2014-01-01T00:00:00.000Z',
            'top_dates':
            ['1900-01-01T00:00:00.000Z', '1901-01-01T00:00:00.000Z'],
            'insider': {
                'k1': '2015-01-01T00:00:00.000Z',
                'k2': '2016-01-01T00:00:00.000Z',
                'k3': '2017-01-01T00:00:00.000Z'
            },
            'top_complex': {
                'id': 1,
                'name': 'Joey',
                'age': 23.36,
                'male': True,
                'birthday': '1992-01-01T00:00:00.000Z',
                'anniversary': '2013-12-08T00:00:00.000Z',
            }
        }
        self.maxDiff = None
        self.assertEqual(message, output)

    def test_polymorphic_serialization(self):

        self.maxDiff = None

        class Zoo(Model):

            _attribute_map = {
                "animals": {
                    "key": "Animals",
                    "type": "[Animal]"
                },
            }

            def __init__(self, animals=None):
                self.animals = animals

        class Animal(Model):

            _attribute_map = {
                "name": {
                    "key": "Name",
                    "type": "str"
                },
                "d_type": {
                    "key": "dType",
                    "type": "str"
                }
            }

            _subtype_map = {'d_type': {"cat": "Cat", "dog": "Dog"}}

            def __init__(self, name=None):
                self.name = name

        class Dog(Animal):

            _attribute_map = {
                "name": {
                    "key": "Name",
                    "type": "str"
                },
                "likes_dog_food": {
                    "key": "likesDogFood",
                    "type": "bool"
                },
                "d_type": {
                    "key": "dType",
                    "type": "str"
                }
            }

            def __init__(self, name=None, likes_dog_food=None):
                self.likes_dog_food = likes_dog_food
                super(Dog, self).__init__(name)
                self.d_type = 'dog'

        class Cat(Animal):

            _attribute_map = {
                "name": {
                    "key": "Name",
                    "type": "str"
                },
                "likes_mice": {
                    "key": "likesMice",
                    "type": "bool"
                },
                "dislikes": {
                    "key": "dislikes",
                    "type": "Animal"
                },
                "d_type": {
                    "key": "dType",
                    "type": "str"
                }
            }

            _subtype_map = {"d_type": {"siamese": "Siamese"}}

            def __init__(self, name=None, likes_mice=None, dislikes=None):
                self.likes_mice = likes_mice
                self.dislikes = dislikes
                super(Cat, self).__init__(name)
                self.d_type = 'cat'

        class Siamese(Cat):

            _attribute_map = {
                "name": {
                    "key": "Name",
                    "type": "str"
                },
                "likes_mice": {
                    "key": "likesMice",
                    "type": "bool"
                },
                "dislikes": {
                    "key": "dislikes",
                    "type": "Animal"
                },
                "color": {
                    "key": "Color",
                    "type": "str"
                },
                "d_type": {
                    "key": "dType",
                    "type": "str"
                }
            }

            def __init__(self,
                         name=None,
                         likes_mice=None,
                         dislikes=None,
                         color=None):
                self.color = color
                super(Siamese, self).__init__(name, likes_mice, dislikes)
                self.d_type = 'siamese'

        message = {
            "Animals": [{
                "dType": "dog",
                "likesDogFood": True,
                "Name": "Fido"
            }, {
                "dType": "cat",
                "likesMice": False,
                "dislikes": {
                    "dType": "dog",
                    "likesDogFood": True,
                    "Name": "Angry"
                },
                "Name": "Felix"
            }, {
                "dType": "siamese",
                "Color": "grey",
                "likesMice": True,
                "Name": "Finch"
            }]
        }

        zoo = Zoo()
        angry = Dog()
        angry.name = "Angry"
        angry.likes_dog_food = True

        fido = Dog()
        fido.name = "Fido"
        fido.likes_dog_food = True

        felix = Cat()
        felix.name = "Felix"
        felix.likes_mice = False
        felix.dislikes = angry

        finch = Siamese()
        finch.name = "Finch"
        finch.color = "grey"
        finch.likes_mice = True

        zoo.animals = [fido, felix, finch]

        serialized = self.s._serialize(zoo)
        self.assertEqual(serialized, message)

        old_dependencies = self.s.dependencies
        self.s.dependencies = {
            'Zoo': Zoo,
            'Animal': Animal,
            'Dog': Dog,
            'Cat': Cat,
            'Siamese': Siamese
        }

        serialized = self.s.body(
            {
                "animals": [{
                    "dType": "dog",
                    "likes_dog_food": True,
                    "name": "Fido"
                }, {
                    "dType": "cat",
                    "likes_mice": False,
                    "dislikes": {
                        "dType": "dog",
                        "likes_dog_food": True,
                        "name": "Angry"
                    },
                    "name": "Felix"
                }, {
                    "dType": "siamese",
                    "color": "grey",
                    "likes_mice": True,
                    "name": "Finch"
                }]
            }, "Zoo")
        self.assertEqual(serialized, message)

        self.s.dependencies = old_dependencies
コード例 #3
0
class TestRuntimeSerialized(unittest.TestCase):

    class TestObj(Model):

        _validation = {}
        _attribute_map = {
            'attr_a': {'key':'id', 'type':'str'},
            'attr_b': {'key':'AttrB', 'type':'int'},
            'attr_c': {'key':'Key_C', 'type': 'bool'},
            'attr_d': {'key':'AttrD', 'type':'[int]'},
            'attr_e': {'key':'AttrE', 'type': '{float}'}
            }

        def __init__(self):

            self.attr_a = None
            self.attr_b = None
            self.attr_c = None
            self.attr_d = None
            self.attr_e = None

        def __str__(self):
            return "Test_Object"

    def setUp(self):
        self.s = Serializer()
        return super(TestRuntimeSerialized, self).setUp()

    def test_obj_without_attr_map(self):
        """
        Test serializing an object with no attribute_map.
        """
        test_obj = type("BadTestObj", (), {})

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_obj_with_malformed_map(self):
        """
        Test serializing an object with a malformed attribute_map.
        """
        test_obj = type("BadTestObj", (Model,), {"_attribute_map":None})

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        test_obj._attribute_map = {"attr":"val"}

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        test_obj._attribute_map = {"attr":{"val":1}}

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_obj_with_mismatched_map(self):
        """
        Test serializing an object with mismatching attributes and map.
        """
        test_obj = type("BadTestObj", (Model,), {"_attribute_map":None})
        test_obj._attribute_map = {"abc":{"key":"ABC", "type":"str"}}

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_attr_none(self):
        """
        Test serializing an object with None attributes.
        """
        test_obj = self.TestObj()
        message = self.s._serialize(test_obj)

        self.assertIsInstance(message, dict)
        self.assertFalse('id' in message)

    def test_attr_int(self):
        """
        Test serializing an object with Int attributes.
        """
        test_obj = self.TestObj()
        self.TestObj._validation = {
            'attr_b': {'required': True},
        }
        test_obj.attr_b = None

        with self.assertRaises(ValidationError):
            self.s._serialize(test_obj)

        test_obj.attr_b = 25

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrB'], int(test_obj.attr_b))

        test_obj.attr_b = "34534"

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrB'], int(test_obj.attr_b))

        test_obj.attr_b = "NotANumber"

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        self.TestObj._validation = {}

    def test_attr_str(self):
        """
        Test serializing an object with Str attributes.
        """
        test_obj = self.TestObj()
        self.TestObj._validation = {
            'attr_a': {'required': True},
        }
        test_obj.attr_a = None

        with self.assertRaises(ValidationError):
            self.s._serialize(test_obj)

        self.TestObj._validation = {}
        test_obj.attr_a = "TestString"

        message = self.s._serialize(test_obj)
        self.assertEqual(message['id'], str(test_obj.attr_a))

        test_obj.attr_a = 1234

        message = self.s._serialize(test_obj)
        self.assertEqual(message['id'], str(test_obj.attr_a))

        test_obj.attr_a = list()

        message = self.s._serialize(test_obj)
        self.assertEqual(message['id'], str(test_obj.attr_a))

        test_obj.attr_a = [1]

        message = self.s._serialize(test_obj)
        self.assertEqual(message['id'], str(test_obj.attr_a))

    def test_attr_bool(self):
        """
        Test serializing an object with bool attributes.
        """
        test_obj = self.TestObj()
        test_obj.attr_c = True

        message = self.s._serialize(test_obj)
        self.assertEqual(message['Key_C'], True)

        test_obj.attr_c = ""

        message = self.s._serialize(test_obj)
        self.assertTrue('Key_C' in message)

        test_obj.attr_c = None

        message = self.s._serialize(test_obj)
        self.assertFalse('Key_C' in message)

        test_obj.attr_c = "NotEmpty"

        message = self.s._serialize(test_obj)
        self.assertEqual(message['Key_C'], True)

    def test_attr_sequence(self):
        """
        Test serializing a sequence.
        """

        test_obj = ["A", "B", "C"]
        output = self.s._serialize(test_obj, '[str]', div='|')
        self.assertEqual(output, "|".join(test_obj))

        test_obj = [1,2,3]
        output = self.s._serialize(test_obj, '[str]', div=',')
        self.assertEqual(output, ",".join([str(i) for i in test_obj]))

    def test_attr_list_simple(self):
        """
        Test serializing an object with simple-typed list attributes
        """
        test_obj = self.TestObj()
        test_obj.attr_d = []

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrD'], test_obj.attr_d)

        test_obj.attr_d = [1,2,3]

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrD'], test_obj.attr_d)

        test_obj.attr_d = ["1","2","3"]

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrD'], [int(i) for i in test_obj.attr_d])

        test_obj.attr_d = ["test","test2","test3"]

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        test_obj.attr_d = "NotAList"

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_empty_list(self):

        input = []
        output = self.s._serialize(input, '[str]')
        self.assertEqual(output, input)

    def test_attr_list_complex(self):
        """
        Test serializing an object with a list of complex objects as an attribute.
        """
        list_obj = type("ListObj", (Model,), {"_attribute_map":None,
                                        "_validation":{},
                                        "abc":None})
        list_obj._attribute_map = {"abc":{"key":"ABC", "type":"int"}}
        list_obj.abc = "123"

        test_obj = type("CmplxTestObj", (Model,), {"_attribute_map":None,
                                             "_validation":{},
                                             "test_list":None})

        test_obj._attribute_map = {"test_list":{"key":"_list", "type":"[ListObj]"}}
        test_obj.test_list = [list_obj]

        message = self.s._serialize(test_obj)
        self.assertEqual(message, {'_list':[{'ABC':123}]})

        list_obj = type("BadListObj", (Model,), {"map":None})
        test_obj._attribute_map = {"test_list":{"key":"_list", "type":"[BadListObj]"}}
        test_obj.test_list = [list_obj]

        s = self.s._serialize(test_obj)
        self.assertEqual(s, {'_list':[{}]})

    def test_attr_dict_simple(self):
        """
        Test serializing an object with a simple dictionary attribute.
        """

        test_obj = self.TestObj()
        test_obj.attr_e = {"value": 3.14}

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrE']['value'], float(test_obj.attr_e["value"]))

        test_obj.attr_e = {1: "3.14"}

        message = self.s._serialize(test_obj)
        self.assertEqual(message['AttrE']['1'], float(test_obj.attr_e[1]))

        test_obj.attr_e = "NotADict"

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

        test_obj.attr_e = {"value": "NotAFloat"}

        with self.assertRaises(SerializationError):
            self.s._serialize(test_obj)

    def test_serialize_datetime(self):

        date_obj = isodate.parse_datetime('2015-01-01T00:00:00')
        date_str = Serializer.serialize_iso(date_obj)

        self.assertEqual(date_str, '2015-01-01T00:00:00.000Z')

        date_obj = isodate.parse_datetime('1999-12-31T23:59:59-12:00')
        date_str = Serializer.serialize_iso(date_obj)

        self.assertEqual(date_str, '2000-01-01T11:59:59.000Z')

        with self.assertRaises(SerializationError):
            date_obj = isodate.parse_datetime('9999-12-31T23:59:59-12:00')
            date_str = Serializer.serialize_iso(date_obj)

        with self.assertRaises(SerializationError):
            date_obj = isodate.parse_datetime('0001-01-01T00:00:00+23:59')
            date_str = Serializer.serialize_iso(date_obj)


        date_obj = isodate.parse_datetime("2015-06-01T16:10:08.0121-07:00")
        date_str = Serializer.serialize_iso(date_obj)

        self.assertEqual(date_str, '2015-06-01T23:10:08.0121Z')

        date_obj = datetime.min
        date_str = Serializer.serialize_iso(date_obj)
        self.assertEqual(date_str, '0001-01-01T00:00:00.000Z')

        date_obj = datetime.max
        date_str = Serializer.serialize_iso(date_obj)
        self.assertEqual(date_str, '9999-12-31T23:59:59.999999Z')


    def test_serialize_primitive_types(self):

        a = self.s.serialize_data(1, 'int')
        self.assertEqual(a, 1)

        b = self.s.serialize_data(True, 'bool')
        self.assertEqual(b, True)

        c = self.s.serialize_data('True', 'str')
        self.assertEqual(c, 'True')

        d = self.s.serialize_data(100.0123, 'float')
        self.assertEqual(d, 100.0123)

    def test_serialize_object(self):

        a = self.s.body(1, 'object')
        self.assertEqual(a, 1)

        b = self.s.body(True, 'object')
        self.assertEqual(b, True)

        c = self.s.serialize_data('True', 'object')
        self.assertEqual(c, 'True')

        d = self.s.serialize_data(100.0123, 'object')
        self.assertEqual(d, 100.0123)

        e = self.s.serialize_data({}, 'object')
        self.assertEqual(e, {})

        f = self.s.body({"test":"data"}, 'object')
        self.assertEqual(f, {"test":"data"})

        g = self.s.body({"test":{"value":"data"}}, 'object')
        self.assertEqual(g, {"test":{"value":"data"}})

        h = self.s.serialize_data({"test":self.TestObj()}, 'object')
        self.assertEqual(h, {"test":"Test_Object"})

        i =  self.s.serialize_data({"test":[1,2,3,4,5]}, 'object')
        self.assertEqual(i, {"test":[1,2,3,4,5]})

    def test_serialize_empty_iter(self):

        a = self.s.serialize_dict({}, 'int')
        self.assertEqual(a, {})

        b = self.s.serialize_iter([], 'int')
        self.assertEqual(b, [])

    def test_serialize_json_obj(self):

        class ComplexId(Model):

            _validation = {}
            _attribute_map = {'id':{'key':'id','type':'int'},
                              'name':{'key':'name','type':'str'},
                              'age':{'key':'age','type':'float'},
                              'male':{'key':'male','type':'bool'},
                              'birthday':{'key':'birthday','type':'iso-8601'},
                              'anniversary':{'key':'anniversary', 'type':'iso-8601'}}

            id = 1
            name = "Joey"
            age = 23.36
            male = True
            birthday = '1992-01-01T00:00:00.000Z'
            anniversary = isodate.parse_datetime('2013-12-08T00:00:00')

        class ComplexJson(Model):

            _validation = {}
            _attribute_map = {'p1':{'key':'p1','type':'str'},
                              'p2':{'key':'p2','type':'str'},
                              'top_date':{'key':'top_date', 'type':'iso-8601'},
                              'top_dates':{'key':'top_dates', 'type':'[iso-8601]'},
                              'insider':{'key':'insider','type':'{iso-8601}'},
                              'top_complex':{'key':'top_complex','type':'ComplexId'}}

            p1 = 'value1'
            p2 = 'value2'
            top_date = isodate.parse_datetime('2014-01-01T00:00:00')
            top_dates = [isodate.parse_datetime('1900-01-01T00:00:00'), isodate.parse_datetime('1901-01-01T00:00:00')]
            insider = {
                'k1': isodate.parse_datetime('2015-01-01T00:00:00'),
                'k2': isodate.parse_datetime('2016-01-01T00:00:00'),
                'k3': isodate.parse_datetime('2017-01-01T00:00:00')}
            top_complex = ComplexId()

        message =self.s._serialize(ComplexJson())

        output = { 
            'p1': 'value1', 
            'p2': 'value2', 
            'top_date': '2014-01-01T00:00:00.000Z', 
            'top_dates': [ 
                '1900-01-01T00:00:00.000Z', 
                '1901-01-01T00:00:00.000Z' 
            ], 
            'insider': {
                'k1': '2015-01-01T00:00:00.000Z', 
                'k2': '2016-01-01T00:00:00.000Z', 
                'k3': '2017-01-01T00:00:00.000Z' 
            }, 
            'top_complex': { 
                'id': 1, 
                'name': 'Joey', 
                'age': 23.36, 
                'male': True, 
                'birthday': '1992-01-01T00:00:00.000Z', 
                'anniversary': '2013-12-08T00:00:00.000Z', 
            } 
        }
        self.maxDiff = None
        self.assertEqual(message, output) 

    def test_polymorphic_serialization(self):

        self.maxDiff = None
        class Zoo(Model):

            _attribute_map = {
                "animals":{"key":"Animals", "type":"[Animal]"},
                }

            def __init__(self):
                self.animals = None

        class Animal(Model):

            _attribute_map = {
                "name":{"key":"Name", "type":"str"}
                }

            _subtype_map = {
                'dType': {"cat":"Cat", "dog":"Dog"}
                }

            def __init__(self):
                self.name = None

        class Dog(Animal):

            _attribute_map = {
                "name":{"key":"Name", "type":"str"},
                "likes_dog_food":{"key":"likesDogFood","type":"bool"}
                }

            def __init__(self):
                self.likes_dog_food = None
                super(Dog, self).__init__()

        class Cat(Animal):

            _attribute_map = {
                "name":{"key":"Name", "type":"str"},
                "likes_mice":{"key":"likesMice","type":"bool"},
                "dislikes":{"key":"dislikes","type":"Animal"}
                }

            _subtype_map = {
                "dType":{"siamese":"Siamese"}
                }

            def __init__(self):
                self.likes_mice = None
                self.dislikes = None
                super(Cat, self).__init__()

        class Siamese(Cat):

            _attribute_map = {
                "name":{"key":"Name", "type":"str"},
                "likes_mice":{"key":"likesMice","type":"bool"},
                "dislikes":{"key":"dislikes","type":"Animal"},
                "color":{"key":"Color", "type":"str"}
                }

            def __init__(self):
                self.color = None
                super(Siamese, self).__init__()

        message = {
            "Animals": [ 
            { 
            "dType": "dog", 
            "likesDogFood": True, 
            "Name": "Fido" 
            }, 
            { 
            "dType": "cat", 
            "likesMice": False, 
            "dislikes": { 
            "dType": "dog", 
            "likesDogFood": True, 
            "Name": "Angry" 
            }, 
            "Name": "Felix" 
            }, 
            { 
            "dType": "siamese", 
            "Color": "grey", 
            "likesMice": True, 
            "Name": "Finch" 
            }]}

        zoo = Zoo()
        angry = Dog()
        angry.name = "Angry"
        angry.likes_dog_food = True

        fido = Dog()
        fido.name = "Fido"
        fido.likes_dog_food = True

        felix = Cat()
        felix.name = "Felix"
        felix.likes_mice = False
        felix.dislikes = angry

        finch = Siamese()
        finch.name = "Finch"
        finch.color = "grey"
        finch.likes_mice = True

        zoo.animals = [fido, felix, finch]

        serialized = self.s._serialize(zoo)
        self.assertEqual(serialized, message)