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 Documentation Status 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

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

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

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

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.

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:

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:

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.

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:

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.

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.

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.

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.1
Filename, size File type Python version Upload date Hashes
Filename, size jsons-0.4.1-py3-none-any.whl (15.0 kB) File type Wheel Python version py3 Upload date Hashes View
Filename, size jsons-0.4.1.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