JSON utilities
JSON (de)serialization framework.
The framework presented here is somewhat based on Go’s “json” package
(especially the omitempty functionality).
- josepy.json_util.field(json_name: str, default: Any = None, omitempty: bool = False, decoder: Callable[[Any], Any] | None = None, encoder: Callable[[Any], Any] | None = None) Any[source]
Convenient function to declare a
Fieldwith proper type annotations.This function allows to write the following code:
import josepy class JSON(josepy.JSONObjectWithFields):
typ: str = josepy.field(‘type’)
- def other_type(self) -> str:
return self.typ
- class josepy.json_util.Field(json_name: str, default: Any = None, omitempty: bool = False, decoder: Callable[[Any], Any] | None = None, encoder: Callable[[Any], Any] | None = None)[source]
JSON object field.
Fieldis meant to be used together withJSONObjectWithFields.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 raiseSerializationError(DeserializationError).Note, that
decodershould 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
Trueand the field value is empty, then it will not be included in the serialized JSON object, anddefaultwill be used for deserialization. Otherwise, ifFalse, field is considered as required, value will always be included in the serialized JSON objected, and it must also be present when deserializing.
- decoder(fdec: Callable[[Any], Any]) Field[source]
Descriptor to change the decoder on JSON object field.
- encoder(fenc: Callable[[Any], Any]) Field[source]
Descriptor to change the encoder on JSON object field.
- classmethod default_decoder(value: Any) Any[source]
Default decoder.
Recursively deserialize into immutable types (
josepy.util.frozendictinstead ofdict(),tuple()instead oflist()).
- class josepy.json_util.JSONObjectWithFieldsMeta(name: str, bases: List[str], namespace: Dict[str, Any])[source]
Metaclass for
JSONObjectWithFieldsand its subclasses.It makes sure that, for any class
clswith__metaclass__set toJSONObjectWithFieldsMeta:All fields (attributes of type
Field) in the class definition are moved to thecls._fieldsdictionary, where keys are field attribute names and values are fields themselves.cls.__slots__is extended by all field attribute names (i.e. notField.json_name). Originalcls.__slots__are stored incls._orig_slots.
In a consequence, for a field attribute name
some_field,cls.some_fieldwill be a slot descriptor and not an instance ofField. For example:some_field = Field('someField', default=()) class Foo: __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 usualtype) to mitigate the metaclass conflict (ImmutableMapandJSONDeSerializable, parents ofJSONObjectWithFields, useabc.ABCMetaas its metaclass).
- class josepy.json_util.JSONObjectWithFields(**kwargs: Any)[source]
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'
- encode(name: str) Any[source]
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
- to_partial_json() Dict[str, Any][source]
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 from_json(jobj: Mapping[str, Any]) GenericJSONObjectWithFields[source]
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: bytes) str[source]
Encode JOSE Base-64 field.
- Parameters:
data (bytes)
- Return type:
str
- josepy.json_util.decode_b64jose(data: str, size: int | None = None, minimum: bool = False) bytes[source]
Decode JOSE Base-64 field.
- Parameters:
data (unicode)
size (int) – Required length (after decoding).
minimum (bool) – If
True, thensizewill be treated as minimum required length, as opposed to exact equality.
- Return type:
bytes
- josepy.json_util.encode_hex16(value: bytes) str[source]
Hexlify.
- Parameters:
value (bytes)
- Return type:
unicode
- josepy.json_util.decode_hex16(value: str, size: int | None = None, minimum: bool = False) bytes[source]
Decode hexlified field.
- Parameters:
value (unicode)
size (int) – Required length (after decoding).
minimum (bool) – If
True, thensizewill be treated as minimum required length, as opposed to exact equality.
- Return type:
bytes
- josepy.json_util.encode_cert(cert: Certificate) str[source]
Encode certificate as JOSE Base-64 DER.
- Return type:
unicode
Changed in version 2.0.0: The
certparameter is nowcryptography.x509.Certificate. Previously this was anjosepy.util.ComparableX509object, which wrapped anOpenSSL.crypto.X509object.
- josepy.json_util.decode_cert(b64der: str) Certificate[source]
Decode JOSE Base-64 DER-encoded certificate.
- Parameters:
b64der (unicode)
- Return type:
cryptography.x509.Certificate
Changed in version 2.0.0: The returned object is now a
cryptography.x509.Certificate. Previously this was anjosepy.util.ComparableX509object, which wrapped anOpenSSL.crypto.X509object.
- josepy.json_util.encode_csr(csr: CertificateSigningRequest) str[source]
Encode CSR as JOSE Base-64 DER.
- Return type:
unicode
Changed in version 2.0.0: The
certparameter is nowcryptography.x509.CertificateSigningRequest. Previously this was anjosepy.util.ComparableX509object, which wrapped anOpenSSL.crypto.X509Reqobject.
- josepy.json_util.decode_csr(b64der: str) CertificateSigningRequest[source]
Decode JOSE Base-64 DER-encoded CSR.
- Parameters:
b64der (unicode)
- Return type:
cryptography.x509.CertificateSigningRequest
Changed in version 2.0.0: The returned object is now a
cryptography.x509.CertificateSigningRequest. Previously this was anjosepy.util.ComparableX509object, which wrapped anOpenSSL.crypto.X509Reqobject.
- class josepy.json_util.TypedJSONObjectWithFields(**kwargs: Any)[source]
JSON object with type.
- typ: str = NotImplemented
Type of the object. Subclasses must override.
- type_field_name: str = 'type'
Field name used to distinguish different object types.
Subclasses will probably have to override this.
- TYPES: Dict[str, Type] = NotImplemented
Types registered for JSON deserialization
- classmethod register(type_cls: Type[GenericTypedJSONObjectWithFields], typ: str | None = None) Type[GenericTypedJSONObjectWithFields][source]
Register class for JSON deserialization.
- classmethod get_type_cls(jobj: Mapping[str, Any]) Type[TypedJSONObjectWithFields][source]
Get the registered class for
jobj.
- to_partial_json() Dict[str, Any][source]
Get JSON serializable object.
- Returns:
Serializable JSON object representing ACME typed object.
validate()will almost certainly not work, due to reasons explained injosepy.interfaces.IJSONSerializable.- Return type:
dict
- classmethod from_json(jobj: Mapping[str, Any]) TypedJSONObjectWithFields[source]
Deserialize ACME object from valid JSON object.
- Raises:
josepy.errors.UnrecognizedTypeError – if type of the ACME object has not been registered.