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.3

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.3
File Size Uploaded
ypres-1.1.3.tar.gz 75.9 kB Details

Built distribution (wheel)

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

Total release size: 87.7 kB

Release files / ypres-1.1.3.tar.gz

Download URL ypres-1.1.3.tar.gz
Size 75.9 kB
Tags Source
SHA-256 checksum
How to use checksums
67355411a25e4a81057a568f63fa7faf5b97986b5ce94f21eb8adad78d4f2792
BLAKE2b-256 checksum
How to use checksums
794b775972ede0f947ca9c9a8cadfeaf202a82403827b4ec92c6f77a4aa301f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 16, 2026.

Transparency log

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

Download URL ypres-1.1.3-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d1cca13188400dea8dc24841b2c384f2e46d511bacea8994d90cc47bac77b638
BLAKE2b-256 checksum
How to use checksums
5151eb80d1e864113c8165563219611ec7a8849742110f9ac1aaaf8a89c9443c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 16, 2026.

Transparency log

Release history Release notifications | RSS feed

1.1.4

2 release files

This release

1.1.3 This release

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