ó
íÂÐZc           @   sx   d  Z  d d l Z d d l Z d d l Z d d l Z d d l m Z m Z e j e j	 ƒ d e
 f d „  ƒ  Yƒ Z d S(   s   JOSE interfaces.iÿÿÿÿN(   t   errorst   utilt   JSONDeSerializablec           B   sk   e  Z d  Z e j d „  ƒ Z d „  Z e j d „  ƒ Z	 e
 d „  ƒ Z d „  Z d „  Z e
 d „  ƒ Z RS(   sø  Interface for (de)serializable JSON objects.

    Please recall, that standard Python library implements
    :class:`json.JSONEncoder` and :class:`json.JSONDecoder` that perform
    translations based on respective :ref:`conversion tables
    <conversion-table>` that look pretty much like the one below (for
    complete tables see relevant Python documentation):

    .. _conversion-table:

    ======  ======
     JSON   Python
    ======  ======
    object  dict
    ...     ...
    ======  ======

    While the above **conversion table** is about translation of JSON
    documents to/from the basic Python types only,
    :class:`JSONDeSerializable` introduces the following two concepts:

      serialization
        Turning an arbitrary Python object into Python object that can
        be encoded into a JSON document. **Full serialization** produces
        a Python object composed of only basic types as required by the
        :ref:`conversion table <conversion-table>`. **Partial
        serialization** (accomplished by :meth:`to_partial_json`)
        produces a Python object that might also be built from other
        :class:`JSONDeSerializable` objects.

      deserialization
        Turning a decoded Python object (necessarily one of the basic
        types as required by the :ref:`conversion table
        <conversion-table>`) into an arbitrary Python object.

    Serialization produces **serialized object** ("partially serialized
    object" or "fully serialized object" for partial and full
    serialization respectively) and deserialization produces
    **deserialized object**, both usually denoted in the source code as
    ``jobj``.

    Wording in the official Python documentation might be confusing
    after reading the above, but in the light of those definitions, one
    can view :meth:`json.JSONDecoder.decode` as decoder and
    deserializer of basic types, :meth:`json.JSONEncoder.default` as
    serializer of basic types, :meth:`json.JSONEncoder.encode`  as
    serializer and encoder of basic types.

    One could extend :mod:`json` to support arbitrary object
    (de)serialization either by:

      - overriding :meth:`json.JSONDecoder.decode` and
        :meth:`json.JSONEncoder.default` in subclasses

      - or passing ``object_hook`` argument (or ``object_hook_pairs``)
        to :func:`json.load`/:func:`json.loads` or ``default`` argument
        for :func:`json.dump`/:func:`json.dumps`.

    Interestingly, ``default`` is required to perform only partial
    serialization, as :func:`json.dumps` applies ``default``
    recursively. This is the idea behind making :meth:`to_partial_json`
    produce only partial serialization, while providing custom
    :meth:`json_dumps` that dumps with ``default`` set to
    :meth:`json_dump_default`.

    To make further documentation a bit more concrete, please, consider
    the following imaginatory implementation example::

      class Foo(JSONDeSerializable):
          def to_partial_json(self):
              return 'foo'

          @classmethod
          def from_json(cls, jobj):
              return Foo()

      class Bar(JSONDeSerializable):
          def to_partial_json(self):
              return [Foo(), Foo()]

          @classmethod
          def from_json(cls, jobj):
              return Bar()

    c         C   s   t  ƒ  ‚ d S(   sÖ  Partially serialize.

        Following the example, **partial serialization** means the following::

          assert isinstance(Bar().to_partial_json()[0], Foo)
          assert isinstance(Bar().to_partial_json()[1], Foo)

          # in particular...
          assert Bar().to_partial_json() != ['foo', 'foo']

        :raises josepy.errors.SerializationError:
            in case of any serialization error.
        :returns: Partially serializable object.

        N(   t   NotImplementedError(   t   self(    (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyt   to_partial_jsong   s    c            s   ‡  f d †  ‰  ˆ  |  ƒ S(   sD  Fully serialize.

        Again, following the example from before, **full serialization**
        means the following::

          assert Bar().to_json() == ['foo', 'foo']

        :raises josepy.errors.SerializationError:
            in case of any serialization error.
        :returns: Fully serialized object.

        c            sÊ   t  |  t ƒ r ˆ  |  j ƒ  ƒ St  |  t j ƒ r5 |  St  |  t ƒ ra g  |  D] } ˆ  | ƒ ^ qK St  |  t j ƒ r t ‡  f d †  |  Dƒ ƒ St  |  t j	 ƒ rÂ t
 ‡  f d †  t j |  ƒ Dƒ ƒ S|  Sd  S(   Nc         3   s   |  ] } ˆ  | ƒ Vq d  S(   N(    (   t   .0t   subobj(   t
   _serialize(    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pys	   <genexpr>‘   s    c         3   s-   |  ]# \ } } ˆ  | ƒ ˆ  | ƒ f Vq d  S(   N(    (   R   t   keyt   value(   R   (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pys	   <genexpr>“   s   (   t
   isinstanceR   R   t   sixt   string_typest   listt   collectionst   Sequencet   tuplet   Mappingt   dictt	   iteritems(   t   objR   (   R   (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyR   ‡   s    (    (   R   (    (   R   s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyt   to_jsonz   s    c         C   s   |  ƒ  S(   sÕ  Deserialize a decoded JSON document.

        :param jobj: Python object, composed of only other basic data
            types, as decoded from JSON document. Not necessarily
            :class:`dict` (as decoded from "JSON object" document).

        :raises josepy.errors.DeserializationError:
            if decoding was unsuccessful, e.g. in case of unparseable
            X509 certificate, or wrong padding in JOSE base64 encoded
            string, etc.

        (    (   t   clst   jobj(    (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyt	   from_jsonš   s    c         C   sE   y t  j | ƒ } Wn" t k
 r7 } t j | ƒ ‚ n X|  j | ƒ S(   s&   Deserialize from JSON document string.(   t   jsont   loadst
   ValueErrorR    t   DeserializationErrorR   (   R   t   json_stringR   t   error(    (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyt
   json_loads¬   s
    c         K   s   t  j |  d |  j | S(   ss   Dump to JSON string using proper serializer.

        :returns: JSON document string.
        :rtype: str

        t   default(   R   t   dumpst   json_dump_default(   R   t   kwargs(    (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyt
   json_dumpsµ   s    c         C   s   |  j  d t d d d d ƒ S(   sN   Dump the object to pretty JSON document string.

        :rtype: str

        t	   sort_keyst   indenti   t
   separatorst   ,s   : (   R)   s   : (   R%   t   True(   R   (    (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyt   json_dumps_pretty¾   s    c         C   s3   t  | t ƒ r | j ƒ  St t | ƒ d ƒ ‚ d S(   sµ  Serialize Python object.

        This function is meant to be passed as ``default`` to
        :func:`json.dump` or :func:`json.dumps`. They call
        ``default(python_object)`` only for non-basic Python types, so
        this function necessarily raises :class:`TypeError` if
        ``python_object`` is not an instance of
        :class:`IJSONSerializable`.

        Please read the class docstring for more information.

        s    is not JSON serializableN(   R   R   R   t	   TypeErrort   repr(   R   t   python_object(    (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyR#   Æ   s    
(   t   __name__t
   __module__t   __doc__t   abct   abstractmethodR   R   R   t   abstractclassmethodR   t   classmethodR    R%   R+   R#   (    (    (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyR      s   W	 				(   R1   R2   R   R   R   t   josepyR    R   t   add_metaclasst   ABCMetat   objectR   (    (    (    s5   /usr/lib/python2.7/dist-packages/josepy/interfaces.pyt   <module>   s   