# JSON utilities

JSON (de)serialization framework.

The framework presented here is somewhat based on Go’s “json” package (especially the `omitempty` functionality).

class `josepy.json_util.``Field`(json_name, default=None, omitempty=False, decoder=None, encoder=None)

  Bases: `object`

  JSON object field.

  `Field` is meant to be used together with `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 `SerializationError` (`DeserializationError`).

  Note, that `decoder` should perform partial serialization only.

  Variables:

  - json_name (str) – Name of the field when encoded to JSON.
  - default – Default value (used when not present in JSON object).
  - omitempty (bool) – 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.

  classmethod `_empty`(value)

    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.

  `omit`(value)

    Omit the value in output?

  `decoder`(fdec)

    Descriptor to change the decoder on JSON object field.

  `encoder`(fenc)

    Descriptor to change the encoder on JSON object field.

  `decode`(value)

    Decode a value, optionally with context JSON object.

  `encode`(value)

    Encode a value, optionally with context JSON object.

  classmethod `default_decoder`(value)

    Default decoder.

    Recursively deserialize into immutable types ( `josepy.util.frozendict` instead of `dict()`, `tuple()` instead of `list()`).

  classmethod `default_encoder`(value)

    Default (passthrough) encoder.

class `josepy.json_util.``JSONObjectWithFieldsMeta`

  Bases: `abc.ABCMeta`

  Metaclass for `JSONObjectWithFields` and its subclasses.

  It makes sure that, for any class `cls` with `__metaclass__` set to `JSONObjectWithFieldsMeta`:

  1. All fields (attributes of type `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 `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 `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 `abc.ABCMeta` (and not the usual `type`) to mitigate the metaclass conflict (`ImmutableMap` and `JSONDeSerializable`, parents of `JSONObjectWithFields`, use `abc.ABCMeta` as its metaclass).

class `josepy.json_util.``JSONObjectWithFields`(**kwargs)

  Bases: `josepy.util.ImmutableMap`, `josepy.interfaces.JSONDeSerializable`

  JSON object with fields.

  Example:

      class Foo(JSONObjectWithFields):
          bar = Field('Bar')
          empty = Field('Empty', omitempty=True)

          @bar.encoder
          def bar(value):
              return value + 'bar'

          @bar.decoder
          def bar(value):
              if not value.endswith('bar'):
                  raise errors.DeserializationError('No bar suffix!')
              return value[:-3]

      assert Foo(bar='baz').to_partial_json() == {'Bar': 'bazbar'}
      assert Foo.from_json({'Bar': 'bazbar'}) == Foo(bar='baz')
      assert (Foo.from_json({'Bar': 'bazbar', 'Empty': '!'})
              == Foo(bar='baz', empty='!'))
      assert Foo(bar='baz').bar == 'baz'

  classmethod `_defaults`()

    Get default fields values.

  `encode`(name)

    Encode a single field.

    Parameters: | name (str) – Name of the field to be encoded.

    Raises:

    - errors.SerializationError – if field cannot be serialized
    - errors.Error – if field could not be found

  `fields_to_partial_json`()

    Serialize fields to JSON.

  `to_partial_json`()

    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.

  classmethod `fields_from_json`(jobj)

    Deserialize fields from JSON.

  classmethod `from_json`(jobj)

    Deserialize a decoded JSON document.

    Parameters: | jobj – Python object, composed of only other basic data types, as decoded from JSON document. Not necessarily `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.

`josepy.json_util.``encode_b64jose`(data)

  Encode JOSE Base-64 field.

  Parameters: | data (bytes) –
  Return type: | `unicode`

`josepy.json_util.``decode_b64jose`(data, size=None, minimum=False)

  Decode JOSE Base-64 field.

  Parameters:

  - data (unicode) –
  - size (int) – Required length (after decoding).
  - minimum (bool) – If `True`, then `size` will be treated as minimum required length, as opposed to exact equality.

  Return type: | bytes

`josepy.json_util.``encode_hex16`(value)

  Hexlify.

  Parameters: | value (bytes) –
  Return type: | unicode

`josepy.json_util.``decode_hex16`(value, size=None, minimum=False)

  Decode hexlified field.

  Parameters:

  - value (unicode) –
  - size (int) – Required length (after decoding).
  - minimum (bool) – If `True`, then `size` will be treated as minimum required length, as opposed to exact equality.

  Return type: | bytes

`josepy.json_util.``encode_cert`(cert)

  Encode certificate as JOSE Base-64 DER.

  Return type: | unicode

`josepy.json_util.``decode_cert`(b64der)

  Decode JOSE Base-64 DER-encoded certificate.

  Parameters: | b64der (unicode) –
  Return type: | `OpenSSL.crypto.X509` wrapped in `ComparableX509`

`josepy.json_util.``encode_csr`(csr)

  Encode CSR as JOSE Base-64 DER.

  Return type: | unicode

`josepy.json_util.``decode_csr`(b64der)

  Decode JOSE Base-64 DER-encoded CSR.

  Parameters: | b64der (unicode) –
  Return type: | `OpenSSL.crypto.X509Req` wrapped in `ComparableX509`

class `josepy.json_util.``TypedJSONObjectWithFields`(**kwargs)

  Bases: `josepy.json_util.JSONObjectWithFields`

  JSON object with type.

  `typ` = NotImplemented

    Type of the object. Subclasses must override.

  `type_field_name` = 'type'

    Field name used to distinguish different object types.

    Subclasses will probably have to override this.

  `TYPES` = NotImplemented

    Types registered for JSON deserialization

  classmethod `register`(type_cls, typ=None)

    Register class for JSON deserialization.

  classmethod `get_type_cls`(jobj)

    Get the registered class for `jobj`.

  `to_partial_json`()

    Get JSON serializable object.

    Returns: | Serializable JSON object representing ACME typed object. `validate()` will almost certainly not work, due to reasons explained in `josepy.interfaces.IJSONSerializable`.
    Return type: | dict

  classmethod `from_json`(jobj)

    Deserialize ACME object from valid JSON object.

    Raises: | josepy.errors.UnrecognizedTypeError – if type of the ACME object has not been registered.