Skip to main content

simple-serialize

simple-serialize is a small Python library for serializing Python objects to and from JSON. Classes must be registered to be participate, either by using the @serializable decorator (simplest), or the register function (for types you don't control). Use serialize/deserialize for converting to and from JSON strings, or save/load for writing and reading those strings to disk.

Requires Python 3.10 or later.

Installation

Install the published package from PyPI:

python -m pip install simple-serialize

To install from a local checkout instead:

python -m pip install .

Quick start

Decorate a class to make it serializable. Ordinary classes are serialized from their instance attributes. Dataclasses are serialized from their fields.

from dataclasses import dataclass
from simple_serialize import deserialize, serializable, serialize

@serializable
@dataclass
class Person:
    name: str
    age: int

person = Person("Ada", 36)
json_text = serialize(person)
print(json_text)

restored = deserialize(json_text)
assert restored == person

Registered objects are represented in JSON by a type name and serialized data.

{
    "__type__": "Person",
    "__data__": {
        "name": "Ada",
        "age": 36
    }
}

Passing a string argument to @serializable will use that string instead of the class name as the value of the __type__ key. Use an explicit name when the JSON type name should remain stable if the Python class is renamed.

For a class you can't decorate, use the register function, and supply serializer and deserializer functions. For example:

from simple_serialize import register

class ExternalValue: # Some externally defined class you don't control
    def __init__(self, value):
        self.value = value

# Functions you define to handle serialization and deserialization

def serialize_external(obj: ExternalValue, options, ctx):
    return {"value": obj.value}

def deserialize_external(cls, data, options, ctx):
    return cls(data["value"])

# Register the class and its handler functions

register(
    ExternalValue,
    serialize_external,
    deserialize_external,
    json_name="ExternalValue",
    units="meters",
)

The class must be registered in the current Python process before its serialized value can be deserialized.

Serializer callbacks receive the instance, an options dictionary, and an opaque context context object (see below). They should return JSON-compatible data. Deserializers receive the class, decoded data, options dictionary, and context object. They should return a reconstructed instance. Additional keyword arguments to register become the options dictionary; json_name continues to select the JSON type name.

JSON strings and files

serialize(obj, ctx=None) returns an indented JSON string, and deserialize(json_text, ctx=None) returns the decoded value. The file helpers use UTF-8; save creates missing parent directories.

from simple_serialize import load, save

save(person, "data/person.json")
restored = load("data/person.json")

Both operations accept an optional opaque ctx value, which is passed to custom serialization and deserialization callbacks unchanged.

from simple_serialize import deserialize, serialize

ctx = {"offset": 10}
json_text = serialize(person, ctx)
restored = deserialize(json_text, ctx)

The library does not inspect or modify ctx; define and interpret its structure in your own callbacks.

Registration options

Keyword arguments passed to @serializable or register are collected into an options dictionary passed to the serializer and deserializer. The default serializers for ordinary classes and dataclasses recognize three keywords:

  • exclude: a list of attribute or field names omitted from serialized data.
  • select: a list of the only attribute or field names to serialize (overrides exclude).
  • rename: a mapping from Python attribute or field names to JSON names. Renamed names are mapped back during deserialization. Attribute names not in this mapping remain unchanged.

For example:

@serializable(
    exclude=["password"],
    rename={"first_name": "firstName"},
)
@dataclass
class Account:
    first_name: str
    password: str

Names in select and exclude refer to Python attribute or field names, before any renaming. An excluded or unselected value is not present in the JSON data. It therefore needs a suitable default or otherwise compatible constructor if the object is to be deserialized.

Custom serialization callbacks receive these options in their options dictionary and remain responsible for applying them. The exported mapping_serializer and mapping_deserializer callbacks apply them to mapping keys when you register those callbacks for a mapping class. Native dictionaries are serialized as ordinary JSON objects and are not filtered or renamed.

Custom serialization

For a decorated class, define _serialize(self, options, ctx) and _deserialize(cls, data, options, ctx) methods to define custom conversions to and from JSON. Decorator keyword arguments are available in the options dictionary:

from simple_serialize import serializable

@serializable(scale=1.8)
class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius

    def _serialize(self, options, ctx):
        return {"fahrenheit": self.celsius * options["scale"] + 32}

    @classmethod
    def _deserialize(cls, data, options, ctx):
        return cls((data["fahrenheit"] - 32) / options["scale"])

If thse custom methods are omitted, enums use their member values, dataclasses use their fields, and other classes use their instance attributes, including initialized __slots__. The default deserializer for an ordinary class calls its constructor without arguments, so such classes must support Class().

Supported types

JSON-native types (None, booleans, numbers, strings, lists, and dictionaries) can be serialized directly. The library also has built-in handlers for:

  • tuple, set, and frozenset (encoded as JSON arrays; set iteration order is not guaranteed)
  • complex (real and imaginary components)
  • fractions.Fraction (exact numerator and denominator)
  • decimal.Decimal (text representation, preserving precision and exponent)
  • uuid.UUID (canonical hyphenated string)
  • ipaddress address, network, and interface values (canonical text)
  • collections.Counter, collections.OrderedDict, and collections.deque (including non-string keys, order, and deque.maxlen)
  • bytes and bytearray (base64 encoded)
  • memoryview (contents, format, shape, and read-only state; only contiguous views are supported, and the original backing buffer is not retained)
  • range and slice (start, stop, and step values)
  • pathlib.Path
  • datetime.datetime, datetime.date, datetime.time, and datetime.timedelta (datetime.timezone offsets/names and keyed zoneinfo.ZoneInfo values are preserved for datetimes and times)
  • datetime.timezone and keyed zoneinfo.ZoneInfo values
  • Compiled regular expressions (re.Pattern) and re.RegexFlag

Other Python classes, including enum and dataclass types, must be registered before use. Restoring a ZoneInfo value requires the corresponding IANA timezone database entry to be available on the receiving system. Arbitrary custom tzinfo implementations are represented by their ISO offset rather than reconstructed as the original timezone object.

Format and limitations

  • The reserved JSON keys __type__ and __data__ identify registered values. Any dictionary containing __type__ is treated as serialization metadata when deserialized, so avoid using that key for ordinary dictionary data.
  • Registered objects cannot be dictionary keys.
  • Circular references raise ValueError. Repeated references that are not circular are serialized as independent values; object identity is not kept.
  • Only deserialize JSON from sources you trust. Deserialization invokes the registered callbacks and constructors in your process.

Running the tests

Install the test dependency and run pytest:

python -m pip install '.[test]'
python -m pytest

AI Usage

This project was developed with the assistance of Github Copilot, mostly using the GPT-6 Luna model.

License

MIT

Metadata

Release files for simple-serialize 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for simple-serialize 0.5.0
File Size Uploaded Provenance Actions
simple_serialize-0.5.0.tar.gz 25.6 kB Without provenance Details for simple_serialize-0.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for simple-serialize 0.5.0
File Interpreter ABI Platform Actions
simple_serialize-0.5.0-py3-none-any.whl Python 3 none any Details for simple_serialize-0.5.0-py3-none-any.whl

Total release size: 47.6 kB

Release files / simple_serialize-0.5.0.tar.gz

Download URL simple_serialize-0.5.0.tar.gz
Size 25.6 kB
Tags Source
SHA-256 checksum
How to use checksums
7a876b6009f4fd64afa9abb8eb73bd9a5da197150f1ee6a9115168195ed10329
BLAKE2b-256 checksum
How to use checksums
52442a81969f0389300219059d5acee0e026407d526bdd734f6083b7cf8dc5c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.9

Release files / simple_serialize-0.5.0-py3-none-any.whl

Download URL simple_serialize-0.5.0-py3-none-any.whl
Size 22.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1b913fd3c1be9d4dc3c6679b32f5f31c2f3d92ea669a2685e7863dfc0e7b2137
BLAKE2b-256 checksum
How to use checksums
e72bd93d2303da31d80971fc7ae1d5b82c65630c2eda034c46b7c338da44ab1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.9

Security for simple-serialize 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page