Extending json-five¶
The json way¶
json5.load and json5.loads support a similar interface to the stdlib json module. Specifically,
you can provide the following arguments that have the same meaning as in json.load:
parse_intparse_floatparse_constantobject_hookobject_pairs_hook
This is convenient if you have existing code that uses these arguments with the json module, but want to also
support JSON5. These options are also useful as a simple way to customize parsing of json types.
Additionally, a new hook keyword argument, parse_json5_identifiers, is available to help users control the
output of parsing identifiers. By default, JSON5 Identifiers in object keys are returned as a JsonIdentifier object,
which is a subclass of str (meaning it’s compatible anywhere str is accepted).
This helps keep keys the same round-trip, rather than converting unquoted identifiers into quoted strings, such that
dumps(loads(text)) == text (in this case).
You can change this behavior with the parse_json5_identifiers keyword argument with a callable that receives the JsonIdentifier object
and its return value is used instead. For example, you can specify parse_json5_identifiers=str to convert identifiers
to normal strings, such that dumps(loads('{foo: "bar"}')) == '{"foo": "bar"}'.
However, this package does not support the cls keyword found in the standard library json module.
If you want to implement custom serializers/deserializers, read on about custom loaders/dumpers.
Custom Loaders and Dumpers¶
This package uses “Loaders” as part of the deserialization of JSON text to Python. “Dumpers” are used to serialize Python objects to JSON text.
The entry points for loaders and dumpers are the load and dump methods, respectively.
You can override these methods to implement custom loading of models or dumping of objects.
Extending the default loader¶
The default loader takes in a model and produces, in the default case, Python objects.
As a simple example, you can extend the default loader with your own to customize loading of lists. Here,
I’ll create a custom loader that, when it encounters an array (json5.model.JSONArray) with with only one value, it will return
the single value, rather than a single-item array.
from json5.loader import DefaultLoader, loads
from json5.model import JSONArray
class MyCustomLoader(DefaultLoader):
def load(self, node):
if isinstance(node, JSONArray):
return self.json_array_to_python(node)
else:
return super().load(node)
def json_array_to_python(self, node):
if len(node.values) == 1:
return self.load(node.values[0])
else:
return super().json_array_to_python(node)
The loads function accepts a loader keyword argument, where the custom loader can be passed in.
json_string = "{foo: ['bar', 'baz'], bacon: ['eggs']}"
loads(json_string) # Using the regular default loader
# {'foo': ['bar', 'baz'], 'bacon': ['eggs']}
loads(json_string, loader=MyCustomLoader()) # use the custom loader instead
# {'foo': ['bar', 'baz'], 'bacon': 'eggs'}
Extending the default dumper¶
Extending the dumper follows a similar principle as extending the loader.
As an example, I’ll make a custom dumper that dumps booleans True and False to integers instead of the
JSON true or false.
from json5.dumper import DefaultDumper, dumps
class MyCustomDumper(DefaultDumper):
def dump(self, node):
if isinstance(node, bool):
return self.bool_to_json(node)
else:
return super().dump(node)
def bool_to_json(self, node):
super().dump(int(node.value))
And you can see the effects
>>> dumps([True, False])
'[true, false]'
>>> dumps([True, False], dumper=MyCustomDumper())
'[1, 2]'
Other loaders/dumpers and tools¶
Besides the default loader, there is also the ModelLoader which simply returns the raw model
with no additional processing.
Besides the default dumper, there is also the ModelDumper which takes a model and serializes it to JSON.
The json5.dumper.modelize function can take python objects and convert them to a model.
from json5.dumper import modelize
obj = ['foo', 123, True]
modelize(obj)
The resulting model:
JSONArray(
values=[
SingleQuotedString(characters='foo', raw_value="'foo'"),
Integer(raw_value='123', value=123, is_hex=False),
BooleanLiteral(value=True),
],
trailing_comma=None,
)