Jsonable API¶
Module for the jsonable interface
-
class
pheres._jsonable.jsonable(cls: type = None, /, after: Union[str, Iterable[str]] = (), internal: str = None, only_marked: bool = False)¶ Class decorator to make a class jsonable
This decorator adds members to the decorated class to serialize or deserialize instance from JSON format. Class decorated this way are called
jsonableclassess. The members added by this decorator are described inJsonableDummy. Some may not be added by certain usage of this decorator, see below.Jsonable classes are typed. This means the values found in JSON must have the correct types when deserializing. Types are specified in python code by using PEP 526 type annotations. No typecheck occurs on serialization, as python’s type annotations are not binding. Pheres trusts that the code follows the annotations it exposes, but does not enforce it. Ill-implemented code may well crash when deserializing instances that did not abide to their annotations.
@jsonablecan be parametrized by type-hints, much like types from thetypingmodule (e.g.@jsonable[int]). This will produce various types of jsonable classes. Refer to the Usage section below for details.There are four types of jsonable classes: jsonable value, jsonable array, jsonable dict and jsonable object. These jsonable class have different JSON representation and are documented below.
This class decorator is fully compatible with the
dataclassesmodule and theattr.sdecorator, though it must be used as the inner-most decorator (that is, it must be executed first on the class). It will raise an error if this is not the case.- Parameters
after (Union[str, Iterable[str]]) –
Modify the decorated class only after the listed member become available in the class’ module. This allows for circular definitions. When the class is modified, the class object is retrieved again from the module it was defined in. This makes
aftercompatibles with decorators that replace the class object with another one, such asattr.sin certain circumstances.Checks for dependencies are performed after each use of the
@jsonabledecorator. If your class is the last decorated one in the file, calljsonable.decorate_delayedto modify it before usage.internal (str) – For jsonable value, array of dict. Name of the attribute where the JSON value is stored, allowing Pheres to make add the
to_jsonmethod to the decorated classonly_marked (bool) – For jsonable object only. If
True, all annotated attributes are used. IfFalse, only marked attributes are used. See jsonable objects below. Attributes lacking a PEP 526 annotation are always ignored.
- Raises
TypeError – an argument has a wrong type
JsonableError – the decorator is not the innermost with respect to
dataclasses.dataclassorattr.s
- Jsonable values:
Jsonable values are represented by a single JSON value (null, a number, a string). To make a jsonable value by decorating a class with
@jsonable, the class must:have an
__init__method accepting the callClass(value), where value is the JSON value for an instance of the class (this is used for deserialization)implement the
to_json(self)method, that returns the value to represents the instance with in JSON (e.g.None, anintor astr). This is because Pheres cannot know what the class does with the value, like it does with jsonable objects.
See the Usage section below for how to make jsonable values
- Jsonable arrays:
Jsonable arrays are represented by a JSON array. There are two kind of arrays, fixed-length arrays and arbitrary length arrays. To make a jsonable array by decorating a class with
@jsonable, the class must:have an
__init__method that accept the callClass(*array), wherearrayis the python list for the JSON array. This means:For fixed-length array, a signature
__init__(self, v1, v2, ...)with a fixed number of arguments is acceptedFor arbitrary length array, the number of arguments is not known in advance, so the signature must be similar to
__init__(self, *array)(this signature is also valid for fixed-length arrays as it does accept the call above).
implement the
to_json(self)method, that returns the pythonlistthat represents the instance in JSON. This is because Pheres cannot know what the class does with the values like it does with jsonable objects.
See the Usage section below for how to make jsonable arrays
- Jsonable dicts:
Jsonable dicts are represented by a JSON Object with arbitrary key-value pairs. For JSON object with known key-value pairs, see jsonable objects below. To make a jsonable dict by decorating a class with
@jsonable, the class must:have an
__init__method that accept the callClass(**object), whereobjectis the python dict representing the instance in JSON. The only signature that supports that in python is of the sort__init__(self, **object)(the actual name of theobjectparameter can vary). Optional arguments may be added, but all key-value pairs found in the deserialized JSON will be passed as keyword arguments. This is used for deserialization.implement the
to_json(self)method, that returns a pythondictthat represents the instance in JSON. This is because Pheres cannot know what the class does with the key-value pairs like it does with jsonable objects.
See the Usage section below for how to make jsonable dicts
- Jsonable objects:
Jsonable objects are represented by a JSON Object with known key-value pairs. The key-value paires are obtained from the class by inspecting PEP 526 annotations. Attributes must be annotated to be considered by Pheres, then:
If
only_markedisFalse(the default), all annotated attributes are usedIf
only_markedisFalse, attributes must be marked for use (seeMarkedandmarked)
Irrespective of the value of
only_marked,Markedandmarkedcan always be used for refined control (see their documentation).If an attribute has a value in the class body, it is taken to be the default value of this attribute. The attribute becomes optional in the JSON representation. Defaults are always deep-copied when instantiating the class from a JSON representation, so
listanddictare safe to use.To make a jsonable object by decorating a class with
@jsonable, the class must:have an
__init__method that accept the callClass(attr1=val1, attr2=val2, ...)where attributes values are passed as keyword arguments. This is automatically the case if you useddataclasses.dataclassorattr.sand is the intended usage for this functuonality.
In particular, jsonable object do not need to implement a
to_json(self)method, as Pheres knows exactly what attributes to use. This is in contrast with other jsonable classes.See the Usage section below for how to make jsonable objects
- Usages:
There are several usage of this decorator.
- Type parametrization:
To produce jsonable values, arrays or dict, the decorator must be parametrized by a type-hint. Any valid type-hint in JSON context can be used. The following syntax may be used:
@jsonable[T] @jsonable.Value[T] @jsonable.Array[T] @jsonable.Dict[T]
The first forms encompasses the following three: If the passed type
Tis a JSON value, it will produce a jsonable value after decorating the class. IfTistyping.Listortyping.Tuple(orlistortuplesince python 3.9), it will produce a jsonable array. Finally, ifTistyping.Dict(ordict), it will produce a jsonable dict. If you wish to produce a jsonable object, do not parametrize the decorator.The type must be fully parametrized, to provide the type of the JSON representation down to the last value.
typing.Unioncan be used. This means that:@jsonable[List] # not valid @jsonable[List[int]] # valid @jsonable[List[Union[int, str]]] # valid
For jsonable arrays,
typing.Listwill produce an arbitrary-length array, whiletyping.Tuplewill produce a fixed-length array, unless an ellipsis is used (e.g.jsonable[Tuple[int, Ellipsis]]). The literal ellipsis...may be used, but this is avoided in this documentation to prevent confusion with the meaning that more arguments can be provided.@jsonable.Value[T, ...]is equivalent tojsonable[Union[T, ...]](The...here is not python ellipsis but indicates that more than one types may be passed).@jsonable.Array[T, ...]is equivalent tojsonable[Tuple[T, ...]](where the...indicates that more than one argument may be passed). This produces a fixed-length array – useEllispisin second position to procude an arbitrary-length array.@jsonable.Dict[T, ...]is equivalent to@jsonable[dict[str, Union[T, ...]]]and produces a jsonable dict. To produce a jsonable object, do not parametrize the decorator.- Arguments:
If specified, arguments must be provided after the type parametrization.
aftercan be used for all jsonable classes, butonly_markedonly has an effect on jsonable objects.
Notes
@jsonableonly add members that are not explicitely defined by the decorated class (inherited implementation are ignored). This means you can overwrite the default behavior if necessary.When parametrized by a type or passed arguments, this decorator returns an object that may be re-used. This means that the following code is valid:
from pheres import jsonable, Marked my_decorator = jsonable(only_marked=True) @my_decorator class MyClass: python: int json: Marked[int]
-
Value[T, ...] Shortcut for
jsonable[Union[T, ...]]
-
Array[T, ...] Shortcut for
jsonable[Tuple[T, ...]]
-
Dict[T, ...] Shortcut for
jsonable[Dict[str, Union[T, ...]]]
-
class
pheres._jsonable.JsonableDummy¶ Bases:
objectDummy class providing dummy members for all members added by
@jsonable. Allows type checkers and linters to detect said attributes-
Decoder¶ alias of
pheres._datatypes.UsableDecoder
-
classmethod
from_json(obj: Any) → AnyClass¶ Converts a JSON file, string or object to an instance of that class
-
to_json() → JSONType¶ Converts an instance of that class to a JSON object
-
-
class
pheres._jsonable.JsonMark(key: Optional[str] = None, json_only: bool = MISSING)¶ Bases:
objectAnnotation for jsonized arguments that provides more control on the jsonized attribute behavior. All arguments are optional.
- Parameters
key – Set the name of the key in JSON for that attribute. Defaults to the name of the attribute in python
json_only – Make the attribute only present in JSON. The attribute must have a default value or be a
typing.Literalof a single value. The attribute is removed from the class’ annotations at runtime Defaults toTruefor Literals of a single value;Falsefor all other types
-
pheres._jsonable.Marked¶ Simple type alias to quickly mark an attribute as jsonized
Marked[T]is equivalent toAnnotated[T, JsonMark()]alias of TypeT
-
pheres._jsonable.marked(tp: TypeHint, /, **kwargs) → TypeHint¶ Shortcut for
Annotated[T, JsonMark(**kwargs)]See
JsonMarkfor a list of supported keyword arguments.markedmay not be compatible with type checkers due to being a runtime definition- Parameters
tp – Type hint to mark
**kwargs – additional info to pass to
JsonMark
See also
-
class
pheres._jsonable.JSONableEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)¶ Bases:
json.encoder.JSONEncoderJSONEncoder subclass that supports jsonable classes
-
default(obj: object)¶ Overrides
json.JSONEncoder.defaultto support jsonable classes
-
-
pheres._jsonable.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)¶ Simple wrapper around
json.dumpthat usesJSONableEncoderas the default encoder.- Wrapped function docstring:
Serialize
objas a JSON formatted stream tofp(a.write()-supporting file-like object).If
skipkeysis true thendictkeys that are not basic types (str,int,float,bool,None) will be skipped instead of raising aTypeError.If
ensure_asciiis false, then the strings written tofpcan contain non-ASCII characters if they appear in strings contained inobj. Otherwise, all such characters are escaped in JSON strings.If
check_circularis false, then the circular reference check for container types will be skipped and a circular reference will result in anOverflowError(or worse).If
allow_nanis false, then it will be aValueErrorto serialize out of rangefloatvalues (nan,inf,-inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN,Infinity,-Infinity).If
indentis a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines.Noneis the most compact representation.If specified,
separatorsshould be an(item_separator, key_separator)tuple. The default is(', ', ': ')if indent isNoneand(',', ': ')otherwise. To get the most compact JSON representation, you should specify(',', ':')to eliminate whitespace.default(obj)is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError.If sort_keys is true (default:
False), then the output of dictionaries will be sorted by key.To use a custom
JSONEncodersubclass (e.g. one that overrides the.default()method to serialize additional types), specify it with theclskwarg; otherwiseJSONEncoderis used.
-
pheres._jsonable.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)¶ Simple wrapper around
json.dumpsthat usesJSONableEncoderas the default encoder.- Wrapped function docstring:
Serialize
objto a JSON formattedstr.If
skipkeysis true thendictkeys that are not basic types (str,int,float,bool,None) will be skipped instead of raising aTypeError.If
ensure_asciiis false, then the return value can contain non-ASCII characters if they appear in strings contained inobj. Otherwise, all such characters are escaped in JSON strings.If
check_circularis false, then the circular reference check for container types will be skipped and a circular reference will result in anOverflowError(or worse).If
allow_nanis false, then it will be aValueErrorto serialize out of rangefloatvalues (nan,inf,-inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN,Infinity,-Infinity).If
indentis a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines.Noneis the most compact representation.If specified,
separatorsshould be an(item_separator, key_separator)tuple. The default is(', ', ': ')if indent isNoneand(',', ': ')otherwise. To get the most compact JSON representation, you should specify(',', ':')to eliminate whitespace.default(obj)is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError.If sort_keys is true (default:
False), then the output of dictionaries will be sorted by key.To use a custom
JSONEncodersubclass (e.g. one that overrides the.default()method to serialize additional types), specify it with theclskwarg; otherwiseJSONEncoderis used.