Ë
    �ÏÏen  ã                   óŒ   — d Z ddlZddlZddlmZmZ ddlmZmZm	Z	m
Z
 ddlmZ  e	dd¬«      Z G d	„ dej                  ¬
«      Zy)zJOSE interfaces.é    N)ÚMappingÚSequence)ÚAnyÚTypeÚTypeVarÚUnion)ÚerrorsÚGenericJSONDeSerializableÚJSONDeSerializable)Úboundc                   óì   — e Zd ZdZej
                  defd„«       Zdefd„Ze	ej
                  de
e   dedefd„«       «       Ze	de
e   deeef   defd	„«       Zd
edefd„Zdefd„Ze	dd defd„«       Zy)r   aø  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()

    Úreturnc                 ó   — t        «       ‚)aÖ  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.

        )ÚNotImplementedError©Úselfs    ú3/usr/lib/python3/dist-packages/josepy/interfaces.pyÚto_partial_jsonz"JSONDeSerializable.to_partial_jsonc   s   € ô" "Ó#Ð#ó    c                 ó8   ‡— dt         dt         fˆfd„Š ‰| «      S )aD  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.

        Úobjr   c                 ó¢  •— t        | t        «      r ‰| j                  «       «      S t        | t        «      r| S t        | t        «      r| D �cg c]
  } ‰|«      ‘Œ c}S t        | t
        «      rt        ˆfd„| D «       «      S t        | t        «      r0| j                  «       D ��ci c]  \  }} ‰|«       ‰|«      “Œ c}}S | S c c}w c c}}w )Nc              3   ó.   •K  — | ]  } ‰|«      –— Œ y ­w)N© )Ú.0ÚsubobjÚ
_serializes     €r   ú	<genexpr>zAJSONDeSerializable.to_json.<locals>._serialize.<locals>.<genexpr>Ž   s   øè ø€ ÒB°F™Z¨×/ÑBùs   ƒ)	Ú
isinstancer   r   ÚstrÚlistr   Útupler   Úitems)r   r   ÚkeyÚvaluer   s       €r   r   z.JSONDeSerializable.to_json.<locals>._serialize„   s±   ø€ Ü˜#Ô1Ô2Ù! #×"5Ñ"5Ó"7Ó8Ð8Ü˜#œsÔ#Ø�
Ü˜C¤Ô&Ø9<Ö=¨v™
 6Õ*Ò=Ð=Ü˜C¤Ô*ô ÓB¸cÔBÓBÐBÜ˜C¤Ô)ØMPÏYÉYË[×Y¹z¸sÀE™
 3›©°EÓ):Ñ:ÓYÐYà�
ùò >ùó Zs   ÁCÂ'C)r   )r   r   s    @r   Úto_jsonzJSONDeSerializable.to_jsonv   s#   ø€ ð	œCð 	¤Cõ 	ñ  ˜$ÓÐr   ÚclsÚjobjc                 ó   —  | «       S )aÕ  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.

        r   )r'   r(   s     r   Ú	from_jsonzJSONDeSerializable.from_json–   s   € ñ" ‹uˆr   Újson_stringc                 óœ   — 	 t        j                  |«      }| j                  |«      S # t        $ r}t        j                  |«      ‚d}~ww xY w)z&Deserialize from JSON document string.N)ÚjsonÚloadsÚ
ValueErrorr	   ÚDeserializationErrorr*   )r'   r+   r.   Úerrors       r   Ú
json_loadszJSONDeSerializable.json_loads©   sI   € ð
	5Ü—J‘J˜{Ó+ˆEð �}‰}˜UÓ#Ð#øô ò 	5Ü×-Ñ-¨eÓ4Ð4ûð	5ús   ‚( ¨	A±AÁAÚkwargsc                 óF   — t        j                  | fd| j                  i|¤ŽS )zsDump to JSON string using proper serializer.

        :returns: JSON document string.
        :rtype: str

        Údefault)r-   ÚdumpsÚjson_dump_default)r   r3   s     r   Ú
json_dumpszJSONDeSerializable.json_dumps´   s#   € ô �z‰z˜$ÑI¨×(>Ñ(>ÐIÀ&ÑIÐIr   c                 ó*   — | j                  ddd¬«      S )zNDump the object to pretty JSON document string.

        :rtype: str

        Té   )ú,z: )Ú	sort_keysÚindentÚ
separators)r8   r   s    r   Újson_dumps_prettyz$JSONDeSerializable.json_dumps_pretty½   s   € ð �‰¨°aÀKˆÓPÐPr   Úpython_objectc                 óp   — t        |t        «      r|j                  «       S t        t	        |«      dz   «      ‚)aµ  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.

        z is not JSON serializable)r   r   r   Ú	TypeErrorÚrepr)r'   r@   s     r   r7   z$JSONDeSerializable.json_dump_defaultÅ   s4   € ô �mÔ%7Ô8Ø ×0Ñ0Ó2Ð2äœD Ó/Ð2MÑMÓNÐNr   N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚabcÚabstractmethodr   r   r&   Úclassmethodr   r
   r*   r   r    Úbytesr2   r8   r?   r7   r   r   r   r   r      sû   „ ñTðl 	×Ñð$ ò $ó ð$ð$ ˜ó  ð@ Ø×Ñð�tÐ5Ñ6ð ¸cð ÐF_ò ó ó ðð" ð$ØÐ+Ñ,ð$Ø;@ÀÀeÀÑ;Lð$à	"ò$ó ð$ðJ 3ð J¨3ó JðQ 3ó Qð ðOÐ.Bð OÀsò Oó ñOr   )Ú	metaclass)rG   rH   r-   Úcollections.abcr   r   Útypingr   r   r   r   Újosepyr	   r
   ÚABCMetar   r   r   r   ú<module>rQ      s=   ðÙ Û 
Û ß -ß ,Ó ,å á#Ð$?ÐG[Ô\Ð ôJO 3§;¡;ö JOr   