Skip to main content
Join the official 2020 Python Developers SurveyStart the survey!

For serializing Python objects to JSON and back

Project description

|PyPI version| |Docs| |Build Status| |Scrutinizer Code Quality| |Maintainability|

jsons

A Python (3.5+) lib for deeply serializing Python objects to dicts or strings and for deserializing dicts or strings to Python objects using type hints.

With jsons, you can serialize/deserialize most objects already. You can also easily extend jsons yourself by defining a custom serializer/deserializer for a certain type. Furthermore, any default serializer/deserializer can be overridden. Some serializers/deserializers accept extra parameters to allow you to tune the serialization/deserialization process to your need.

jsons generates human-readable dicts or JSON strings that are not polluted with metadata.

Why not use __dict__ for serialization? '''''''''''''''''''''''''''''''''''''''''''

  • The __dict__ attribute only creates a shallow dict of an instance. Any contained object is not serialized to a dict.
  • The __dict__ does not take @property methods in account.
  • Not all objects have a __dict__ attribute (e.g. datetime does not).
  • The serialization process of __dict__ cannot easily be tuned.
  • There is no means to deserialize with __dict__.

Installation ''''''''''''

::

pip install jsons

Usage '''''

.. code:: python

import jsons

some_instance = jsons.load(some_dict, SomeClass) # Deserialization some_dict = jsons.dump(some_instance) # Serialization

API overview ''''''''''''

  • dump(obj: object) -> dict: serializes an object to a dict.
  • load(json_obj: dict, cls: type = None) -> object: deserializes a dict to an object of type cls.
  • dumps(obj: object, *args, **kwargs) -> str: serializes an object to a string.
  • loads(s: str, cls: type = None, *args, **kwargs) -> object deserializes a string to an object of type cls.
  • set_serializer(c: callable, cls: type) -> None: sets a custom serialization function for type cls.
  • set_deserializer(c: callable, cls: type) -> None: sets a custom deserialization function for type cls.
  • JsonSerializable: a base class that allows for convenient use of the jsons features.

Examples ''''''''

Example with dataclasses

.. code:: python

from dataclasses import dataclass from typing import List import jsons

You can use dataclasses (since Python3.7). Regular Python classes

(Python3.5+) will work as well as long as type hints are present for

custom classes.

@dataclass class Student: name: str

@dataclass class ClassRoom: students: List[Student]

c = ClassRoom([Student('John'), Student('Mary'), Student('Greg'), Student('Susan')]) dumped_c = jsons.dump(c) print(dumped_c)

Prints:

{'students': [{'name': 'John'}, {'name': 'Mary'},

{'name': 'Greg'}, {'name': 'Susan'}]}

loaded_c = jsons.load(dumped_c, ClassRoom) print(loaded_c)

Prints:

ClassRoom(students=[Student(name='John'), Student(name='Mary'),

Student(name='Greg'), Student(name='Susan')])

Example with regular classes

.. code:: python

from typing import List import jsons

class Student: # Since name is expected to be a string, no type hint is required. def init(self, name): self.name = name

class ClassRoom: # Since Student is a custom class, a type hint must be given. def init(self, students: List[Student]): self.students = students

c = ClassRoom([Student('John'), Student('Mary'), Student('Greg'), Student('Susan')]) dumped_c = jsons.dump(c) print(dumped_c)

Prints:

{'students': [{'name': 'John'}, {'name': 'Mary'},

{'name': 'Greg'}, {'name': 'Susan'}]}

loaded_c = jsons.load(dumped_c, ClassRoom) print(loaded_c)

Prints:

<main.ClassRoom object at 0x0337F9B0>

Example with JsonSerializable

.. code:: python

from jsons import JsonSerializable

class Car(JsonSerializable): def init(self, color): self.color = color

c = Car('red') cj = c.json # You can also do 'c.dump(**kwargs)' print(cj)

Prints:

{'color': 'red'}

c2 = Car.from_json(cj) # You can also do 'Car.load(cj, **kwargs)' print(c2.color)

Prints:

'red'

Advanced features '''''''''''''''''

Overriding the default (de)serialization behavior

You may alter the behavior of the serialization and deserialization processes yourself by defining your own custom serialization/deserialization functions.

.. code:: python

jsons.set_serializer(custom_serializer, datetime) # A custom datetime serializer. jsons.set_deserializer(custom_deserializer, str) # A custom string deserializer.

A custom serializer must have the following form:

.. code:: python

def someclass_serializer(obj: SomeClass, **kwargs) -> dict: # obj is the instance that needs to be serialized. # Make sure to return a type with a JSON equivalent, one of: # (str, int, float, bool, list, dict, None) return obj.dict

A custom deserializer must have the following form:

.. code:: python

def someclass_serializer(obj: object, cls: type = None, **kwargs) -> object: # obj is the instance that needs to be deserialized. # cls is the type that is to be returned. In most cases, this is the # type of the object before it was serialized. return SomeClass(some_arg=obj['some_arg'])

Note that in both cases, if you choose to call any other (de)serializer within your own, you should also pass the **kwargs upon calling.

Transforming the JSON keys

You can have the keys transformed by the serialization or deserialization process by providing a transformer function that takes a string and returns a string.

.. code:: python

result = jsons.dump(some_obj, key_transformer=jsons.KEY_TRANSFORMER_CAMELCASE)

result could be something like: {'thisIsTransformed': 123}

result = jsons.load(some_dict, SomeClass, key_transformer=jsons.KEY_TRANSFORMER_SNAKECASE)

result could be something like: {'this_is_transformed': 123}

The following casing styles are supported:

.. code:: python

KEY_TRANSFORMER_SNAKECASE # snake_case KEY_TRANSFORMER_CAMELCASE # camelCase KEY_TRANSFORMER_PASCALCASE # PascalCase KEY_TRANSFORMER_LISPCASE # lisp-case

Customizing JsonSerializable

You can customize the behavior of the JsonSerializable class or extract a new class from it. This can be useful if you are using jsons extensively throughout your project, especially if you wish to have different (de)serialization styles in different occasions.

.. code:: python

forked = JsonSerializable.fork() forked.set_serializer(custom_serializer, datetime) # A custom serializer.

class Person(forked): def init(self, dt: datetime): self.dt = dt

p = Person('John') p.json # Will contain a serialized dt using 'custom_serializer'.

jsons.dump(datetime.now()) # Still uses the default datetime serializer.

In the above example, a custom serializer is set to a fork of JsonSerializable. The regular jsons.dump does not have this custom serializer and will therefore behave as it used to.

You can also create a fork of a fork. All serializers and deserializers of the type that was forked, are copied.

You can also define default kwargs which are then automatically passed as arguments to the serializing and deserializing methods (dump, load, ...). You can use with_dump and with_load to set default kwargs to the serialization and deserialization process respectively.

.. code:: python

custom_serializable = JsonSerializable
.with_dump(key_transformer=KEY_TRANSFORMER_CAMELCASE)
.with_load(key_transformer=KEY_TRANSFORMER_SNAKECASE)

class Person(custom_serializable): def init(self, my_name): self.my_name = my_name

p = Person('John') p.json # {'myName': 'John'} <-- note the camelCase

p2 = Person.from_json({'myName': 'Mary'}) p2.my_name # 'Mary' <-- note the snake_case in my_name

You can, of course, also do this with a fork of JsonSerializable or you can create a fork in the process by setting fork=True in with_dump or with_load.

.. |PyPI version| image:: https://badge.fury.io/py/jsons.svg :target: https://badge.fury.io/py/jsons

.. |Docs| image:: https://readthedocs.org/projects/jsons/badge/?version=latest :target: https://jsons.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status

.. |Build Status| image:: https://travis-ci.org/ramonhagenaars/geomodels.svg?branch=master :target: https://travis-ci.org/ramonhagenaars/jsons .. |Scrutinizer Code Quality| image:: https://scrutinizer-ci.com/g/ramonhagenaars/jsons/badges/quality-score.png?b=master :target: https://scrutinizer-ci.com/g/ramonhagenaars/jsons/?branch=master .. |Maintainability| image:: https://api.codeclimate.com/v1/badges/17d997068b3387c2f2c3/maintainability :target: https://codeclimate.com/github/ramonhagenaars/jsons/maintainability

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for jsons, version 0.4.0
Filename, size File type Python version Upload date Hashes
Filename, size jsons-0.4.0-py3-none-any.whl (15.0 kB) File type Wheel Python version py3 Upload date Hashes View
Filename, size jsons-0.4.0.tar.gz (13.1 kB) File type Source Python version None Upload date Hashes View

Supported by

Pingdom Pingdom Monitoring Google Google Object Storage and Download Analytics Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page