Skip to main content

ypres: ridiculously fast object serialization

This project started as a fork of the amazing Serpy serializer, which has been marked as feature-complete by the original author. This fork adds some newer features, such as asyncio support so that asynchronous methods may be called from within a serializer.

It was renamed to "ypres" ("serpy" backwards, pronounced like the Belgian town name) to avoid confusion with the original.

Since forking it has undergone numerous changes and rewrites. The core of it is still somewhat recognizable, but there have also been many changes.

ypres is a simple object serialization framework built for speed. ypres serializes complex datatypes (Django Models, custom classes, ...) to simple native types (dicts, lists, strings, ...). The native types can easily be converted to JSON or any other format needed.

The goal of ypres is to be able to do this simply, reliably, and quickly. Since serializers are class based, they can be combined, extended and customized with very little code duplication.

Changes from Serpy

There are some notable changes from the original Serpy serializer in this fork.

New Serializer classes: AsyncSerializer and AsyncDictSerializer

Serpy did not allow for MethodField implementations to use async / await methods. For those instances where you wish to embed an async / await coroutine in your serializer, two new serializer classes, AsyncSerializer and AsyncDictSerializer, will automatically detect whether the method being called is a coroutine and handle it appropriately.

New StaticField class

When combining many fields and manipulating output, it is sometimes desirable to have a fixed value for certain fields in the output. The new StaticField class allows you to specify a fixed value for the field, and this will always appear in the output.

Serializers allow a context object

Additional context can be passed in to a serializer. This is helpful if you have some context that you wish to use when serializing the object. For example, you might pass in a user object that could customize the responses in the serializer with their name, or only perform certain serialization tasks if they are of a specific class (e.g., admin).

Date and DateTime Serializer Fields

Date and DateTime fields can be serialized, based on the implementation from another fork, https://github.com/PKharlamov/drf-serpy/blob/master/drf_serpy/fields.py.

Deprecated the .data property.

Since .data can return either a list (with many=True) or a dict, type checkers complained when you serialized a single object because the calling code does not handle the case of data being a list.

Instead, two new properties, serialized and serialized_many are introduced that return a dict and a list directly. In the course of doing this work the class structure for the serializers was reworked to better implement common checks and data in the superclass.

import ypres


class MySerializer(ypres.Serializer):
    foo = ypres.MethodField()
    blah = ypres.MethodField()
    
    def get_foo(self, obj):
        foo_data = obj.foo
        ctx_data = self.context.get("additional", "")
        return f"{foo_data}_{ctx_data}"
    
    def get_blah(self, obj):
        blah_data = obj.blah
        ctx_data = self.context.get("additional", "")
        return f"{blah_data}_{ctx_data}"
    
    
class Foo:
    foo = "foo"
    blah = "blah"

my_data = MySerializer(Foo(), context={"additional": "bar"}).serialized

# {"foo": "foo_bar", "blah": "blah_bar"}

Changed behaviour of None

By default, data that evaluates to a value of None will not be included in the output. To explicitly mark that a field should emit a None value, it should be instantiated with an emit_none=True argument.

Note that the combination of emit_none and required deserve special attention.

  • If emit_none is False and required is True (default), then the object being serialized must have the matching attribute available, otherwise it will raise an error. The only exception is if the field is a MethodField, in which case the attribute does not need to be present on the object. This behaviour is not changed.
  • If emit_none is False and required is False then the object being serialized will not appear in the output if its value is None
  • If emit_none is True and required is True, then the object being serialized will attempt to return the value. However, it may fail if the to_value method being used does not accept None. An example of this is the IntField serializer, where the to_value method would effectively be calling int(None). In this case, a TypeError will be raised. (This is the same as trying to serialize a string with an IntField, for example)
  • If emit_none is True and required is False, then the object being serialized will actually skip the to_value step and simply return None.

Further to this, the behaviour of the StrField and BoolField were changed, where calling StrField on a value of None would actually return the string "None". Similarly, calling bool(None) evaluates to False. In both of these cases the to_value handler has been modified to return None if the incoming value is None.

This prevents unexpected type values from appearing in the output. For values that cannot be cast to None for IntField and FloatField, a None input will raise an exception.

Modern Python standards

The project uses update Python packaging setups with pyproject.toml. It also adds configurations for ruff, works with uv, and fully supports type annotations.

Source

Source at: https://github.com/rism-digital/ypres

If you want a feature, send a pull request!

Installation

$ pip install git+https://github.com/rism-digital/ypres

Examples

Simple Example

import ypres

class Foo(object):
    """The object to be serialized."""
    y = 'hello'
    z = 9.5

    def __init__(self, x):
        self.x = x


class FooSerializer(ypres.Serializer):
    """The serializer schema definition."""
    # Use a Field subclass like IntField if you need more validation.
    x = ypres.IntField()
    y = ypres.Field()
    z = ypres.Field()

f = Foo(1)
FooSerializer(f).serialized
# {'x': 1, 'y': 'hello', 'z': 9.5}

fs = [Foo(i) for i in range(100)]
FooSerializer(fs, many=True).serialized_many
# [{'x': 0, 'y': 'hello', 'z': 9.5}, {'x': 1, 'y': 'hello', 'z': 9.5}, ...]

Nested Example

import ypres

class Nestee(object):
    """An object nested inside another object."""
    n = 'hi'


class Foo(object):
    x = 1
    nested = Nestee()


class NesteeSerializer(ypres.Serializer):
    n = ypres.Field()


class FooSerializer(ypres.Serializer):
    x = ypres.Field()
    # Use another serializer as a field.
    nested = NesteeSerializer()

f = Foo()
FooSerializer(f).serialized
# {'x': 1, 'nested': {'n': 'hi'}}

Complex Example

import ypres

class Foo(object):
    y = 1
    z = 2
    super_long_thing = 10

    def x(self):
        return 5


class FooSerializer(ypres.Serializer):
    w = ypres.Field(attr='super_long_thing')
    x = ypres.Field(call=True)
    plus = ypres.MethodField()

    def get_plus(self, obj):
        return obj.y + obj.z

f = Foo()
FooSerializer(f).serialized
# {'w': 10, 'x': 5, 'plus': 3}

Inheritance Example

import ypres

class Foo(object):
    a = 1
    b = 2


class ASerializer(ypres.Serializer):
    a = ypres.Field()


class ABSerializer(ASerializer):
    """ABSerializer inherits the 'a' field from ASerializer.

    This also works with multiple inheritance and mixins.
    """
    b = ypres.Field()

f = Foo()
ASerializer(f).serialized
# {'a': 1}
ABSerializer(f).serialized
# {'a': 1, 'b': 2}

License

ypres is free software distributed under the terms of the MIT license. See the LICENSE file.

Metadata

Release files for ypres 1.1.4

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

Source distribution (sdist)

Source distribution for ypres 1.1.4
File Size Uploaded
ypres-1.1.4.tar.gz 119.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ypres 1.1.4
File Interpreter ABI Platform
ypres-1.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 131.7 kB

Release files / ypres-1.1.4.tar.gz

Download URL ypres-1.1.4.tar.gz
Size 119.9 kB
Tags Source
SHA-256 checksum
How to use checksums
42cd6e02daf096f5e0795b3fd8fe78fde2a42624968494577323d5f9008e0cf1
BLAKE2b-256 checksum
How to use checksums
094dade1c13d7c748c3124e9e6ea2a6384b3ba114b11bfe72a0b8d1fa7eb08ed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.

Transparency log

Release files / ypres-1.1.4-py3-none-any.whl

Download URL ypres-1.1.4-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
53abf52574d6ce68ae8d667aabb6c0a23d7aa05e01bc3490131e3b76711718fd
BLAKE2b-256 checksum
How to use checksums
c54160080b3bad0f66a42afe20c636a56c5afc700d157b170398dba10faf1099
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.4 This release

2 release files

1.1.3

2 release files

1.1.2

2 release files

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