No project description provided
Project description
serpyco-rs: a serializer for python dataclasses
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for serpyco_rs-0.15.6-cp312-none-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 211cbd835e4b0d8271392f8700414d251251d55bd8a8e161365af97777d3a066 |
|
MD5 | 850e5292dd817a4ca2fa114bd3cdd9bc |
|
BLAKE2b-256 | 5a5f8b0499e883f4ae4543d0671a67bf34d0dfbf3967053867172db8c673abf9 |
Hashes for serpyco_rs-0.15.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 99bf0d26b4c600419bb2cca4064a1730e5c960722d260e18222a3d7189471295 |
|
MD5 | 83b33c8367724ccb6d39a80fa7d022bb |
|
BLAKE2b-256 | 39d282ede1578a74439bfa20858f8e344891a1eea388456dd71469f22b354cf9 |
Hashes for serpyco_rs-0.15.6-cp312-cp312-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | fec7ccd7401ee2af35763b61fc3033b528a4d6f23994bceba3aac7404f866c83 |
|
MD5 | 1222b1c7e74e9a11c399bbfadf99fe62 |
|
BLAKE2b-256 | 30ccd8125de4e8ad154d5f1e1bac2a71ab567fe58b1a471d5100cb6cb55e207c |
Hashes for serpyco_rs-0.15.6-cp311-none-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c90ed3fa836e7d6f717ae53843e6a8231c8ecfb568cb5abc9f553bbd23bbd0b4 |
|
MD5 | 308215eae3b73be5be153fa8b6c4c4c1 |
|
BLAKE2b-256 | e18f542caf303b6299c4b7c28f1134b3bc0334c064d18199b96000f647de8d26 |
Hashes for serpyco_rs-0.15.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e14c92d7b8479e48a3edde2b23652ae56498d12aba797089c334cf571deccb3e |
|
MD5 | 21c751b92757a527973a94b55fc6354c |
|
BLAKE2b-256 | e4d940642e0990357499d77be9a0d45a29770fec7d78883787919e608e4cdccc |
Hashes for serpyco_rs-0.15.6-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2bbc1d23834c7df043151f12230693d88350f156b1dcd8391ba60b8d0f3944ec |
|
MD5 | 019fba443014f262848b490d98c8aa06 |
|
BLAKE2b-256 | f31acfc62fc4ad8deeb419187f0d941ee1e83daa9e27f7cf51ef4344ddc211fd |
Hashes for serpyco_rs-0.15.6-cp310-none-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 63baccf59a4018d86b49888e857cca9b9aab7db58bd3710c442b45defc0adb1a |
|
MD5 | 981e57318ae98c1eb37ed8d61a7c5153 |
|
BLAKE2b-256 | f637b29e93697db307e6051df9b62c6d4a568f50726f7f2216684300b9de242e |
Hashes for serpyco_rs-0.15.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c0adc7afa68eabf328323f8e44891faa9ab84661a955feb03bda9c6aa31a14d8 |
|
MD5 | 28479e47ff6ee585e4e34df94fcbfcd5 |
|
BLAKE2b-256 | f78a4793e11953d143943514e2d33ee02b16d677629bd43e0354b4e0e5afaf50 |
Hashes for serpyco_rs-0.15.6-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 07f2ae8e1433df2f7d2e9e79b9d7b6e1b6e1f5cde07ebebe553285a303222b08 |
|
MD5 | 724f5bfea889d281c65fadafa7713a33 |
|
BLAKE2b-256 | e6fc3c5d72186f29814ea8cfdab8aaf763458a5ae5b2e067b96391c069c3d321 |
Hashes for serpyco_rs-0.15.6-cp39-none-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 91db445c43b5426ff9c874949fef10e698b019ed8595cff5b2023356cceea8c8 |
|
MD5 | 68ce9a54c9c8852d86f53379222d4576 |
|
BLAKE2b-256 | 0fcdf35ca3d22325980a265ff189b63730d0a9bf0248e6b3a4735645f974f606 |
Hashes for serpyco_rs-0.15.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 416026bc4283a3a98cc9eeedeff4eaf3134bcfc4c9f5a9a0ebf6ce0b6ea77d96 |
|
MD5 | bb7466a13ed340470913253e9a3213bb |
|
BLAKE2b-256 | 33a383c299cdd0a35aebb0e76126e81261c0d949ce493f29eb412bff95fa41b9 |
Hashes for serpyco_rs-0.15.6-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b4aece88c1337ee6deed64d24b35f3ede4bb29cce8988bedfbfeb8ad14e4c0eb |
|
MD5 | a0d89c8609788d6818dafdde3e499736 |
|
BLAKE2b-256 | c681d5973fec64a727ce00e08044d8783055acd9858526180b86343e02481e9a |