Skip to main content

No project description provided

Project description

serpyco-rs: a serializer for python dataclasses

PyPI version Python versions CI status

What is serpyco-rs ?

Serpyco is a serialization library for Python 3.9+ dataclasses that works just by defining your dataclasses:

import dataclasses
import serpyco_rs

@dataclasses.dataclass
class Example:
    name: str
    num: int
    tags: list[str]


serializer = serpyco_rs.Serializer(Example)

result = serializer.dump(Example(name="foo", num=2, tags=["hello", "world"]))
print(result)

>> {'name': 'foo', 'num': 2, 'tags': ['hello', 'world']}

Inspired by serpyco.

serpyco-rs works by analysing the dataclass fields and can recognize many types : list, tuple, Optional... You can also embed other dataclasses in a definition.

The main use-case for serpyco-rs is to serialize objects for an API, but it can be helpful whenever you need to transform objects to/from builtin Python types.

Installation

Use pip to install:

$ pip install serpyco-rs

Features

  • Serialization and deserialization of dataclasses
  • Validation of input data
  • Very fast
  • Support recursive schemas
  • Generate JSON Schema Specification (Draft 2020-12)
  • Support custom encoders/decoders for fields

Supported field types

There is support for generic types from the standard typing module:

  • Decimal
  • UUID
  • Time
  • Date
  • DateTime
  • Enum
  • List
  • Dict
  • Bytes (pass through)
  • TypedDict
  • Mapping
  • Sequence
  • Tuple (fixed size)
  • Literal[str, ...]
  • Tagged unions (restricted)

Benchmark

macOS Monterey / Apple M1 Pro / 16GB RAM / Python 3.11.0

dump

Library Median latency (milliseconds) Operations per second Relative (latency)
serpyco_rs 0.05 22188.2 1
serpyco 0.05 20878.5 1.06
mashumaro 0.06 15602.7 1.42
pydantic 2.66 375.6 59
marshmallow 1.05 951.7 23.33

load with validate

Library Median latency (milliseconds) Operations per second Relative (latency)
serpyco_rs 0.23 4400.1 1
serpyco 0.28 3546.4 1.24
mashumaro 0.23 4377.7 1.01
pydantic 2.01 497.3 8.86
marshmallow 4.55 219.9 20.03

load (only serpyco and serpyco_rs supported load without validate)

Library Median latency (milliseconds) Operations per second Relative (latency)
serpyco_rs 0.07 13882.9 1
serpyco 0.08 12424.5 1.12
mashumaro 0.23 4382.9 3.17
pydantic 2.02 494.4 28.09
marshmallow 4.59 217.5 63.8

Supported annotations

serpyco-rs supports changing load/dump behavior with typing.Annotated.

Currently available:

  • Alias
  • FiledFormat (CamelCase / NoFormat)
  • NoneFormat (OmitNone / KeepNone)
  • Discriminator
  • Min / Max
  • MinLength / MaxLength
  • CustomEncoder
  • NoneAsDefaultForOptional (ForceDefaultForOptional)

Alias

Alias is needed to override the field name in the structure used for load / dump.

from dataclasses import dataclass
from typing import Annotated
from serpyco_rs import Serializer
from serpyco_rs.metadata import Alias

@dataclass
class A:
    foo: Annotated[int, Alias('bar')]

ser = Serializer(A)

print(ser.load({'bar': 1}))
>> A(foo=1)

print(ser.dump(A(foo=1)))
>> {'bar': 1}

FiledFormat

Used to have response bodies in camelCase while keeping your python code in snake_case.

from dataclasses import dataclass
from typing import Annotated
from serpyco_rs import Serializer
from serpyco_rs.metadata import CamelCase, NoFormat

@dataclass
class B:
    buz_filed: str

@dataclass
class A:
    foo_filed: int
    bar_filed: Annotated[B, NoFormat]

ser = Serializer(Annotated[A, CamelCase])  # or ser = Serializer(A, camelcase_fields=True)

print(ser.dump(A(foo_filed=1, bar_filed=B(buz_filed='123'))))
>> {'fooFiled': 1, 'barFiled': {'buz_filed': '123'}}

print(ser.load({'fooFiled': 1, 'barFiled': {'buz_filed': '123'}}))
>> A(foo_filed=1, bar_filed=B(buz_filed='123'))

NoneFormat

Via OmitNone we can drop None values for non required fields in the serialized dicts

from dataclasses import dataclass
from serpyco_rs import Serializer

@dataclass
class A:
    required_val: bool | None
    optional_val: bool | None = None

ser = Serializer(A, omit_none=True) # or Serializer(Annotated[A, OmitNone])

print(ser.dump(A(required_val=None, optional_val=None)))
>>> {'required_val': None}

Tagged unions

Supports tagged joins with discriminator field.

All classes in the union must be dataclasses or attrs with discriminator field Literal[str].

The discriminator field is always mandatory.

from typing import Annotated, Literal
from dataclasses import dataclass
from serpyco_rs import Serializer
from serpyco_rs.metadata import Discriminator

@dataclass
class Foo:
    type: Literal['foo']
    value: int

@dataclass(kw_only=True)
class Bar:
    type: Literal['bar'] = 'bar'
    value: str

ser = Serializer(list[Annotated[Foo | Bar, Discriminator('type')]])

print(ser.load([{'type': 'foo', 'value': 1}, {'type': 'bar', 'value': 'buz'}]))
>>> [Foo(type='foo', value=1), Bar(type='bar', value='buz')]

Min / Max

Supported for int / float / Decimal types and only for validation on load.

from typing import Annotated
from serpyco_rs import Serializer
from serpyco_rs.metadata import Min, Max

ser = Serializer(Annotated[int, Min(1), Max(10)])

ser.load(123)
>> SchemaValidationError: [ErrorItem(message='123 is greater than the maximum of 10', instance_path='', schema_path='maximum')]

MinLength / MaxLength

MinLength / MaxLength can be used to restrict the length of loaded strings.

from typing import Annotated
from serpyco_rs import Serializer
from serpyco_rs.metadata import MinLength

ser = Serializer(Annotated[str, MinLength(5)])

ser.load("1234")
>> SchemaValidationError: [ErrorItem(message='"1234" is shorter than 5 characters', instance_path='', schema_path='minLength')]

NoneAsDefaultForOptional

ForceDefaultForOptional / KeepDefaultForOptional can be used to set None as default value for optional (nullable) fields.

from dataclasses import dataclass
from serpyco_rs import Serializer


@dataclass
class Foo:
    val: int                 # not nullable + required
    val1: int | None         # nullable + required
    val2: int | None = None  # nullable + not required

ser_force_default = Serializer(Foo, force_default_for_optional=True)  # or Serializer(Annotated[Foo, ForceDefaultForOptional])
ser = Serializer(Foo)

# all fields except val are optional and nullable
assert ser_force_default.load({'val': 1}) == Foo(val=1, val1=None, val2=None) 

# val1 field is required and nullable and val1 should be present in the dict
ser.load({'val': 1})
>> SchemaValidationError: [ErrorItem(message='"val1" is a required property', instance_path='', schema_path='required')]

Custom encoders for fields

You can provide CustomEncoder with serialize and deserialize functions, or serialize_with and deserialize_with annotations.

from typing import Annotated
from dataclasses import dataclass
from serpyco_rs import Serializer
from serpyco_rs.metadata import CustomEncoder

@dataclass
class Foo:
    val: Annotated[str, CustomEncoder[str, str](serialize=str.upper, deserialize=str.lower)]

ser = Serializer(Foo)
val = ser.dump(Foo(val='bar'))
>> {'val': 'BAR'}
assert ser.load(val) == Foo(val='bar') 

Note: CustomEncoder has no effect to validation and JSON Schema generation.

Bytes fields

serpyco-rs can loads bytes fields as is (without base64 encoding and validation).

from dataclasses import dataclass
from serpyco_rs import Serializer

@dataclass
class Foo:
    val: bytes

ser = Serializer(Foo, pass_through_bytes=True)
ser.load({'val': b'123'}) == Foo(val=b'123')

Load data from raw json

serpyco-rs can load data from raw json string.

Load data from raw json string is faster than [or]json.loads + Serializer.load about 20%+. This is possible because serpyco-rs uses serde_json to load data from a raw json string and avoids unnecessary conversion of python objects to serde_json::Value for validation process.

from dataclasses import dataclass
from serpyco_rs import Serializer

@dataclass
class A:
    foo: int
    bar: str
    
ser = Serializer(A)

print(ser.load_json('{"foo": 1, "bar": "buz"}'))
>> A(foo=1, bar='buz')

Getting JSON Schema

serpyco-rs can generate JSON Schema for your dataclasses (Draft 2020-12).

from dataclasses import dataclass
from serpyco_rs import Serializer

@dataclass
class A:
    """Description of A"""
    foo: int
    bar: str

ser = Serializer(A)

print(ser.get_json_schema())
>> {
    '$schema': 'https://json-schema.org/draft/2020-12/schema', 
    '$ref': '#/components/schemas/A[no_format,keep_nones]', 
    'components': {
        'schemas': {
            'A[no_format,keep_nones]': {
                'properties': {
                    'foo': {'type': 'integer'}, 
                    'bar': {'type': 'string'}
                }, 
                'required': ['foo', 'bar'], 
                'type': 'object', 
                'description': 'Description of A'
            }
        }
    }
}

Project details


Download files

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

Source Distribution

serpyco_rs-0.15.2.tar.gz (55.5 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

serpyco_rs-0.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

serpyco_rs-0.15.2-cp311-none-win_amd64.whl (1.3 MB view details)

Uploaded CPython 3.11Windows x86-64

serpyco_rs-0.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

serpyco_rs-0.15.2-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl (3.0 MB view details)

Uploaded CPython 3.11macOS 10.9+ universal2 (ARM64, x86-64)macOS 10.9+ x86-64macOS 11.0+ ARM64

serpyco_rs-0.15.2-cp310-none-win_amd64.whl (1.3 MB view details)

Uploaded CPython 3.10Windows x86-64

serpyco_rs-0.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

serpyco_rs-0.15.2-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl (3.0 MB view details)

Uploaded CPython 3.10macOS 10.9+ universal2 (ARM64, x86-64)macOS 10.9+ x86-64macOS 11.0+ ARM64

serpyco_rs-0.15.2-cp39-none-win_amd64.whl (1.3 MB view details)

Uploaded CPython 3.9Windows x86-64

serpyco_rs-0.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

serpyco_rs-0.15.2-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl (3.0 MB view details)

Uploaded CPython 3.9macOS 10.9+ universal2 (ARM64, x86-64)macOS 10.9+ x86-64macOS 11.0+ ARM64

File details

Details for the file serpyco_rs-0.15.2.tar.gz.

File metadata

  • Download URL: serpyco_rs-0.15.2.tar.gz
  • Upload date:
  • Size: 55.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.2.0

File hashes

Hashes for serpyco_rs-0.15.2.tar.gz
Algorithm Hash digest
SHA256 684c50d5433216483da798ee1f86e31aabc0bd85745c27eebd7e0c365cd568e0
MD5 515585bad147c8c129679c354282eecc
BLAKE2b-256 231261dc3029e3580573c4d5309153c82cd714392867443fe39f0bbb1c7d1fd6

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e760bfa57a34569fecff92b1b41038681c74d6dea16962483bf34262a7ecb301
MD5 940c9fdfa7a0d539e9e15c7883c94374
BLAKE2b-256 def93b03f8d77f896bcde1aaa3ca47a3bbfa437cd181ba8f314d94402e729837

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp311-none-win_amd64.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp311-none-win_amd64.whl
Algorithm Hash digest
SHA256 a6427355e5b7d7a2c6b250b9e38546e3221d8d59b61e434d4d5ebf029a5be17e
MD5 01702ae2561af0a59ac353693bfb8478
BLAKE2b-256 1a622a666d309b2c41560f3f16c068a6108946bba62b52cb9dd7dbfc4be79ab6

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 63f3ec619c1875545e2c864b1dc1c1937bbdf1e9a64a1d1249a5d5ec8dbeb2b4
MD5 f3423a955ccfc70f7a366ec0c9a0f679
BLAKE2b-256 ddfaa46cabd681ebb3e32372e0e8d7b0285a523b8bb6f7e8e2e258847af6ef19

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 bc2224dcc55ae288258eccf8b1f9545f1706447943800da983c6434246af182a
MD5 e027adc05046aee92c594c5f35481e26
BLAKE2b-256 907e59824e96092b8c4e729ebd1fa2cb38e18a09f29ec35bc041f5a3ad22e91a

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp310-none-win_amd64.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp310-none-win_amd64.whl
Algorithm Hash digest
SHA256 854bc9fc2427e54b7da7294a68fb1030a91f1af10aa0c79563786865c10345d6
MD5 af914e90972c33ac8b199e5cd354aa8e
BLAKE2b-256 7ce7ab19b4f0a63f00fb08b53374aa550468ac8cccbf7f34b0f64d4b3d920bd1

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 251f9105b425905cc6e0164df6c206cb9167f8b563e8e8ab941adb78f8e22e5f
MD5 d41c4da5951e84737e527b5f9b0a71f0
BLAKE2b-256 4a42874a99eacbb965fdf7aaaf9646083731d8de1a293bea29bdcba120b5d02e

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 d99aaa534a2495bfd3868524ff61fb5275f528f8801e5202f19ca7a55bd03f4f
MD5 728b26f4cb7e1e869d9fa0e07b885d31
BLAKE2b-256 d577f6327d0d4ffa6c6cd86fa3d7b630628fc5677fee962bcbb2ca04fc9dec6a

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp39-none-win_amd64.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp39-none-win_amd64.whl
Algorithm Hash digest
SHA256 127ab9a2c6ef4707cf80115f788c8afd869af9f647774a44a4a7fafe2f6e1fb4
MD5 b774152e3430d08ea94bcc0f35571638
BLAKE2b-256 1ffab29f8f1fd0643b995a0a838950fe5af1f124845ceb43bba214a729ee84cb

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9aa1a2da37313716953c34fabe77d2cbfdb4ed56d321173f9af916ae928fc328
MD5 98d0f560786143997c62f7785e27114a
BLAKE2b-256 6856a7d93f908f47c40e0584c2fba861d2874d49951243a7a78ae3087dfedbbf

See more details on using hashes here.

File details

Details for the file serpyco_rs-0.15.2-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for serpyco_rs-0.15.2-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 9b2906faa731c249d4862ad021af38f71e2a157a702b4b9ed735395fdf0c73a6
MD5 0c50e9c041931890d2b947ec62dca9ea
BLAKE2b-256 fb0fa39e611d208c8a0a0dd41ae6ecf5f61698d9ec1071106350384cf39c7428

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page