�
�t0^c @ s> d Z d d l Z d d l Z d d l Z d d l Z d d l Z d d l m Z m Z m Z m
Z
e j e � Z
d e f d � � YZ d e j f d � � YZ e j e � d e
j e j f d � � Y� Z d
� Z d e d � Z d � Z d e d
� Z d � Z d � Z d � Z d � Z d e f d � � YZ d S( s� JSON (de)serialization framework.
The framework presented here is somewhat based on `Go's "json" package`_
(especially the ``omitempty`` functionality).
.. _`Go's "json" package`: http://golang.org/pkg/encoding/json/
i����N( t b64t errorst
interfacest utilt Fieldc B s� e Z d Z d Z d e d d d � Z e d � � Z d � Z d � Z
d
� Z d � Z d � Z
d
� Z e d � � Z e d � � Z RS( s� JSON object field.
:class:`Field` is meant to be used together with
:class:`JSONObjectWithFields`.
``encoder`` (``decoder``) is a callable that accepts a single
parameter, i.e. a value to be encoded (decoded), and returns the
serialized (deserialized) value. In case of errors it should raise
:class:`~josepy.errors.SerializationError`
(:class:`~josepy.errors.DeserializationError`).
Note, that ``decoder`` should perform partial serialization only.
:ivar str json_name: Name of the field when encoded to JSON.
:ivar default: Default value (used when not present in JSON object).
:ivar bool omitempty: If ``True`` and the field value is empty, then
it will not be included in the serialized JSON object, and
``default`` will be used for deserialization. Otherwise, if ``False``,
field is considered as required, value will always be included in the
serialized JSON objected, and it must also be present when
deserializing.
t json_namet defaultt omitemptyt fdect fencc C s[ | | _ | | _ | | _ | d k r0 | j n | | _ | d k rN | j n | | _ d S( N( R R R t Nonet default_decoderR t default_encoderR ( t selfR R R t decodert encoder( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyt __init__/ s
c C s t | t � o | S( s� Is the provided value considered "empty" for this field?
This is useful for subclasses that might want to override the
definition of being empty, e.g. for some more exotic data types.
( t
isinstancet bool( t clst value( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyt _empty9 s c C s | j | � o | j S( s Omit the value in output?( R R ( R
R ( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyt omitC s c K sS t d | j d | j d | j d | j d | j � } | j | � t | � | � S( NR R R R R ( t dictR R R R R t updatet type( R
t kwargst current( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyt _update_paramsG s
c C s | j d | � S( s6 Descriptor to change the decoder on JSON object field.R ( R ( R
R ( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyR N s c C s | j d | � S( s6 Descriptor to change the encoder on JSON object field.R ( R ( R
R ( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyR R s c C s
| j | � S( s4 Decode a value, optionally with context JSON object.( R ( R
R ( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyt decodeV s c C s
| j | � S( s4 Encode a value, optionally with context JSON object.( R ( R
R ( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyt encodeZ s c sl t | t � r) t � f d � | D� � St | t � rd t j t � f d � t j | � D� � � S| Sd S( s� Default decoder.
Recursively deserialize into immutable types (
:class:`josepy.util.frozendict` instead of
:func:`dict`, :func:`tuple` instead of :func:`list`).
c 3 s | ] } � j | � Vq d S( N( R ( t .0t subvalue( R ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pys <genexpr>i s c 3 s3 | ]) \ } } � j | � � j | � f Vq d S( N( R ( R t keyR ( R ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pys <genexpr>l s N( R t listt tupleR R t
frozendictt sixt iteritems( R R ( ( R s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyR ^ s
c C s | S( s Default (passthrough) encoder.( ( R R ( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyR q s ( s json_names defaults omitemptys fdecs fencN( t __name__t
__module__t __doc__t __slots__R
t FalseR t classmethodR R R R R R R R R ( ( ( s4 /usr/lib/python2.7/site-packages/josepy/json_util.pyR s
t JSONObjectWithFieldsMetac B s e Z d Z d � Z RS( s� Metaclass for :class:`JSONObjectWithFields` and its subclasses.
It makes sure that, for any class ``cls`` with ``__metaclass__``
set to ``JSONObjectWithFieldsMeta``:
1. All fields (attributes of type :class:`Field`) in the class
definition are moved to the ``cls._fields`` dictionary, where
keys are field attribute names and values are fields themselves.
2. ``cls.__slots__`` is extended by all field attribute names
(i.e. not :attr:`Field.json_name`). Original ``cls.__slots__``
are stored in ``cls._orig_slots``.
In a consequence, for a field attribute name ``some_field``,
``cls.some_field`` will be a slot descriptor and not an instance
of :class:`Field`. For example::
some_field = Field('someField', default=())
class Foo(object):
__metaclass__ = JSONObjectWithFieldsMeta
__slots__ = ('baz',)
some_field = some_field
assert Foo.__slots__ == ('some_field', 'baz')
assert Foo._orig_slots == ()
assert Foo.some_field is not Field
assert Foo._fields.keys() == ['some_field']
assert Foo._fields['some_field'] is some_field
As an implementation note, this metaclass inherits from
:class:`abc.ABCMeta` (and not the usual :class:`type`) to mitigate
the metaclass conflict (:class:`ImmutableMap` and
:class:`JSONDeSerializable`, parents of :class:`JSONObjectWithFields`,
use :class:`abc.ABCMeta` as its metaclass).
c C s� i } x'