def on_deserialize(self, value):
        value = callable_to_dict(value)

        for key in value:
            item = value[key]
            if item is not None and not checkers.is_callable(item):
                raise SQLAthanorError('on_deserialize for %s must be callable' % key)

        self._on_deserialize = value
Ejemplo n.º 2
0
    def __init__(self,
                 argument,
                 supports_json=False,
                 supports_yaml=False,
                 supports_dict=False,
                 on_serialize=None,
                 on_deserialize=None,
                 **kwargs):
        """Provide a relationship between two mapped classes.

        This corresponds to a parent-child or associate table relationship.
        The constructed class is an instance of :class:`RelationshipProperty`.

        When serializing or de-serializing relationships, they essentially become
        "nested" objects. For example, if you have an ``Account`` table with a
        relationship to a ``User`` table, you might want to nest or embed a list of
        ``User`` objects within a serialized ``Account`` object.

        .. caution::

          Unlike columns, properties, or hybrid properties, relationships
          cannot be serialized to CSV. This is because a serialized relationship
          is essentially a "nested" object within another object.

          Therefore, the ``supports_csv`` option cannot be set and will always be
          interpreted as ``False``.

        .. warning::

          This constructor is analogous to the original
          :ref:`SQLAlchemy relationship() <sqlalchemy:sqlalchemy.orm.relationship>`
          from which it inherits. The only difference is that it supports additional
          keyword arguments which are not supported in the original, and which
          are documented below.

          **For the original SQLAlchemy version, see:**
          :ref:`(SQLAlchemy) relationship() <sqlalchemy:sqlalchemy.orm.relationship>`

        :param argument: see
          :ref:`(SQLAlchemy) relationship() <sqlalchemy:sqlalchemy.orm.relationship>`

        :param supports_json: Determines whether the column can be serialized to or
          de-serialized from JSON format. If ``True``, can be serialized to JSON and
          de-serialized from JSON. If ``False``, will not be included when serialized
          to JSON and will be ignored if present in a de-serialized JSON.

          Can also accept a 2-member :class:`tuple <python:tuple>` (inbound / outbound)
          which determines de-serialization and serialization support respectively.

          Defaults to ``False``, which means the column will not be serialized to JSON
          or de-serialized from JSON.

        :type supports_json: :class:`bool <python:bool>` / :class:`tuple <python:tuple>` of
          form (inbound: :class:`bool <python:bool>`, outbound: :class:`bool <python:bool>`)

        :param supports_yaml: Determines whether the column can be serialized to or
          de-serialized from YAML format. If ``True``, can be serialized to YAML and
          de-serialized from YAML. If ``False``, will not be included when serialized
          to YAML and will be ignored if present in a de-serialized YAML.

          Can also accept a 2-member :class:`tuple <python:tuple>` (inbound / outbound)
          which determines de-serialization and serialization support respectively.

          Defaults to ``False``, which means the column will not be serialized to YAML
          or de-serialized from YAML.

        :type supports_yaml: :class:`bool <python:bool>` / :class:`tuple <python:tuple>` of
          form (inbound: :class:`bool <python:bool>`, outbound: :class:`bool <python:bool>`)

        :param supports_dict: Determines whether the column can be serialized to or
          de-serialized to a Python :class:`dict <python:dict>`. If ``True``, can
          be serialized to :class:`dict <python:dict>` and de-serialized from a
          :class:`dict <python:dict>`. If ``False``, will not be included when serialized
          to :class:`dict <python:dict>` and will be ignored if present in a de-serialized
          :class:`dict <python:dict>`.

          Can also accept a 2-member :class:`tuple <python:tuple>` (inbound / outbound)
          which determines de-serialization and serialization support respectively.

          Defaults to ``False``, which means the column will not be serialized to a
          :class:`dict <python:dict>` or de-serialized from a :class:`dict <python:dict>`.

        :type supports_dict: :class:`bool <python:bool>` / :class:`tuple <python:tuple>` of
          form (inbound: :class:`bool <python:bool>`, outbound: :class:`bool <python:bool>`)

        """
        # pylint: disable=too-many-branches
        if on_serialize is not None and not isinstance(on_serialize, dict):
            on_serialize = {
                'csv': on_serialize,
                'json': on_serialize,
                'yaml': on_serialize,
                'dict': on_serialize
            }
        elif on_serialize is not None:
            if 'csv' not in on_serialize:
                on_serialize['csv'] = None
            if 'json' not in on_serialize:
                on_serialize['json'] = None
            if 'yaml' not in on_serialize:
                on_serialize['yaml'] = None
            if 'dict' not in on_serialize:
                on_serialize['dict'] = None
        else:
            on_serialize = {
                'csv': None,
                'json': None,
                'yaml': None,
                'dict': None
            }

        for key in on_serialize:
            item = on_serialize[key]
            if item is not None and not checkers.is_callable(item):
                raise SQLAthanorError('on_serialize for %s must be callable' %
                                      key)

        if on_deserialize is not None and not isinstance(on_deserialize, dict):
            on_deserialize = {
                'csv': on_deserialize,
                'json': on_deserialize,
                'yaml': on_deserialize,
                'dict': on_deserialize
            }
        elif on_deserialize is not None:
            if 'csv' not in on_deserialize:
                on_deserialize['csv'] = None
            if 'json' not in on_deserialize:
                on_deserialize['json'] = None
            if 'yaml' not in on_deserialize:
                on_deserialize['yaml'] = None
            if 'dict' not in on_deserialize:
                on_deserialize['dict'] = None
        else:
            on_deserialize = {
                'csv': None,
                'json': None,
                'yaml': None,
                'dict': None
            }

        for key in on_deserialize:
            item = on_deserialize[key]
            if item is not None and not checkers.is_callable(item):
                raise SQLAthanorError(
                    'on_deserialize for %s must be callable' % key)

        if supports_json is True:
            supports_json = (True, True)
        elif not supports_json:
            supports_json = (False, False)

        if supports_yaml is True:
            supports_yaml = (True, True)
        elif not supports_yaml:
            supports_yaml = (False, False)

        if supports_dict is True:
            supports_dict = (True, True)
        elif not supports_dict:
            supports_dict = (False, False)

        self.supports_csv = (False, False)
        self.csv_sequence = None
        self.supports_json = supports_json
        self.supports_yaml = supports_yaml
        self.supports_dict = supports_dict
        self.on_serialize = on_serialize
        self.on_deserialize = on_deserialize

        comparator_factory = kwargs.pop('comparator_factory',
                                        RelationshipProperty.Comparator)

        super(RelationshipProperty,
              self).__init__(argument,
                             comparator_factory=comparator_factory,
                             **kwargs)