ypres 1.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ypres-1.1.2/.github/workflows/ci.yml +61 -0
- ypres-1.1.2/.github/workflows/publish.yml +82 -0
- ypres-1.1.2/.gitignore +49 -0
- ypres-1.1.2/.python-version +1 -0
- ypres-1.1.2/LICENSE +22 -0
- ypres-1.1.2/MANIFEST.in +1 -0
- ypres-1.1.2/PKG-INFO +307 -0
- ypres-1.1.2/README.md +260 -0
- ypres-1.1.2/benchmarks/__init__.py +0 -0
- ypres-1.1.2/benchmarks/complex.py +39 -0
- ypres-1.1.2/benchmarks/complex.py.csv +11 -0
- ypres-1.1.2/benchmarks/utils.py +49 -0
- ypres-1.1.2/docs/Makefile +192 -0
- ypres-1.1.2/docs/_static/bm_complex_objects.png +0 -0
- ypres-1.1.2/docs/_static/bm_complex_time.png +0 -0
- ypres-1.1.2/docs/_static/bm_simple_objects.png +0 -0
- ypres-1.1.2/docs/_static/bm_simple_time.png +0 -0
- ypres-1.1.2/docs/_static/theme-overrides.css +9 -0
- ypres-1.1.2/docs/_templates/page.html +9 -0
- ypres-1.1.2/docs/api.rst +38 -0
- ypres-1.1.2/docs/conf.py +288 -0
- ypres-1.1.2/docs/custom-fields.rst +46 -0
- ypres-1.1.2/docs/index.rst +28 -0
- ypres-1.1.2/docs/performance.rst +104 -0
- ypres-1.1.2/pyproject.toml +82 -0
- ypres-1.1.2/tests/__init__.py +0 -0
- ypres-1.1.2/tests/obj.py +4 -0
- ypres-1.1.2/tests/test_async_serializer.py +103 -0
- ypres-1.1.2/tests/test_fields.py +124 -0
- ypres-1.1.2/tests/test_serializer.py +379 -0
- ypres-1.1.2/uv.lock +437 -0
- ypres-1.1.2/ypres/__init__.py +43 -0
- ypres-1.1.2/ypres/fields.py +210 -0
- ypres-1.1.2/ypres/py.typed +0 -0
- ypres-1.1.2/ypres/serializer.py +569 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
tests:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Check out repository
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
|
|
26
|
+
- name: Set up uv
|
|
27
|
+
uses: astral-sh/setup-uv@v4
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: uv sync --group dev
|
|
31
|
+
|
|
32
|
+
- name: Run tests
|
|
33
|
+
run: uv run python -m unittest tests.test_serializer tests.test_async_serializer tests.test_fields
|
|
34
|
+
|
|
35
|
+
build:
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
needs: tests
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- name: Check out repository
|
|
41
|
+
uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
- name: Set up Python
|
|
44
|
+
uses: actions/setup-python@v5
|
|
45
|
+
with:
|
|
46
|
+
python-version: "3.14"
|
|
47
|
+
|
|
48
|
+
- name: Set up uv
|
|
49
|
+
uses: astral-sh/setup-uv@v4
|
|
50
|
+
|
|
51
|
+
- name: Build distributions
|
|
52
|
+
run: uv build
|
|
53
|
+
|
|
54
|
+
- name: Check distributions
|
|
55
|
+
run: uvx twine check dist/*
|
|
56
|
+
|
|
57
|
+
- name: Upload distributions
|
|
58
|
+
uses: actions/upload-artifact@v4
|
|
59
|
+
with:
|
|
60
|
+
name: python-package-distributions
|
|
61
|
+
path: dist/
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
tests:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- name: Check out repository
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
|
|
28
|
+
- name: Set up uv
|
|
29
|
+
uses: astral-sh/setup-uv@v4
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: uv sync --group dev
|
|
33
|
+
|
|
34
|
+
- name: Run tests
|
|
35
|
+
run: uv run python -m unittest tests.test_serializer tests.test_async_serializer tests.test_fields
|
|
36
|
+
|
|
37
|
+
build:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
needs: tests
|
|
40
|
+
|
|
41
|
+
steps:
|
|
42
|
+
- name: Check out repository
|
|
43
|
+
uses: actions/checkout@v4
|
|
44
|
+
|
|
45
|
+
- name: Set up Python
|
|
46
|
+
uses: actions/setup-python@v5
|
|
47
|
+
with:
|
|
48
|
+
python-version: "3.14"
|
|
49
|
+
|
|
50
|
+
- name: Set up uv
|
|
51
|
+
uses: astral-sh/setup-uv@v4
|
|
52
|
+
|
|
53
|
+
- name: Build distributions
|
|
54
|
+
run: uv build
|
|
55
|
+
|
|
56
|
+
- name: Check distributions
|
|
57
|
+
run: uvx twine check dist/*
|
|
58
|
+
|
|
59
|
+
- name: Upload distributions
|
|
60
|
+
uses: actions/upload-artifact@v4
|
|
61
|
+
with:
|
|
62
|
+
name: python-package-distributions
|
|
63
|
+
path: dist/
|
|
64
|
+
|
|
65
|
+
publish:
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
needs: build
|
|
68
|
+
permissions:
|
|
69
|
+
id-token: write
|
|
70
|
+
|
|
71
|
+
environment:
|
|
72
|
+
name: pypi
|
|
73
|
+
|
|
74
|
+
steps:
|
|
75
|
+
- name: Download distributions
|
|
76
|
+
uses: actions/download-artifact@v4
|
|
77
|
+
with:
|
|
78
|
+
name: python-package-distributions
|
|
79
|
+
path: dist/
|
|
80
|
+
|
|
81
|
+
- name: Publish to PyPI
|
|
82
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
ypres-1.1.2/.gitignore
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Backup files
|
|
2
|
+
*.~
|
|
3
|
+
|
|
4
|
+
# Byte-compiled / optimized / DLL files
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
|
|
8
|
+
# C extensions
|
|
9
|
+
*.so
|
|
10
|
+
|
|
11
|
+
# Distribution / packaging
|
|
12
|
+
bin/
|
|
13
|
+
build/
|
|
14
|
+
develop-eggs/
|
|
15
|
+
dist/
|
|
16
|
+
eggs/
|
|
17
|
+
.eggs/
|
|
18
|
+
lib/
|
|
19
|
+
lib64/
|
|
20
|
+
parts/
|
|
21
|
+
sdist/
|
|
22
|
+
var/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
.installed.cfg
|
|
25
|
+
*.egg
|
|
26
|
+
MANIFEST
|
|
27
|
+
|
|
28
|
+
# Installer logs
|
|
29
|
+
pip-log.txt
|
|
30
|
+
pip-delete-this-directory.txt
|
|
31
|
+
|
|
32
|
+
# Unit test / coverage reports
|
|
33
|
+
.tox/
|
|
34
|
+
.coverage
|
|
35
|
+
.cache
|
|
36
|
+
nosetests.xml
|
|
37
|
+
coverage.xml
|
|
38
|
+
|
|
39
|
+
# Translations
|
|
40
|
+
*.mo
|
|
41
|
+
|
|
42
|
+
# Sphinx documentation
|
|
43
|
+
docs/_build/
|
|
44
|
+
|
|
45
|
+
# Vim swap files
|
|
46
|
+
*.swp
|
|
47
|
+
.idea
|
|
48
|
+
|
|
49
|
+
.DS_Store
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
ypres-1.1.2/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Clark DuVall
|
|
4
|
+
Copyright (c) 2023 Andrew Hankinson, RISM Digital Center
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
ypres-1.1.2/MANIFEST.in
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include LICENSE
|
ypres-1.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ypres
|
|
3
|
+
Version: 1.1.2
|
|
4
|
+
Summary: ypres is a simple object serialization framework built for speed.
|
|
5
|
+
Project-URL: Homepage, https://github.com/rism-digital/ypres
|
|
6
|
+
Project-URL: Source, https://github.com/rism-digital/ypres
|
|
7
|
+
Project-URL: Issues, https://github.com/rism-digital/ypres/issues
|
|
8
|
+
Author-email: Andrew Hankinson <andrew.hankinson@gmail.com>
|
|
9
|
+
License: The MIT License (MIT)
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2015 Clark DuVall
|
|
12
|
+
Copyright (c) 2023 Andrew Hankinson, RISM Digital Center
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: asyncio,json,serialization,serializer,typing
|
|
33
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Operating System :: OS Independent
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
42
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
43
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
44
|
+
Classifier: Typing :: Typed
|
|
45
|
+
Requires-Python: <4.0,>=3.11
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# ypres: ridiculously fast object serialization
|
|
49
|
+
|
|
50
|
+
This project started as a fork of the amazing [Serpy serializer](https://github.com/clarkduvall/serpy), which has been
|
|
51
|
+
[marked as feature-complete](https://github.com/clarkduvall/serpy/issues/69) by the original author. This fork
|
|
52
|
+
adds some newer features, such as `asyncio` support so that asynchronous
|
|
53
|
+
methods may be called from within a serializer.
|
|
54
|
+
|
|
55
|
+
It was renamed to "ypres" ("serpy" backwards, pronounced like the [Belgian town
|
|
56
|
+
name](https://en.wikipedia.org/wiki/Ypres)) to avoid confusion with the original.
|
|
57
|
+
|
|
58
|
+
Since forking it has undergone numerous changes and rewrites. The core of it
|
|
59
|
+
is still somewhat recognizable, but there have also been many changes.
|
|
60
|
+
|
|
61
|
+
**ypres** is a simple object serialization framework built for
|
|
62
|
+
speed. **ypres** serializes complex datatypes (Django Models, custom
|
|
63
|
+
classes, ...) to simple native types (dicts, lists, strings, ...). The
|
|
64
|
+
native types can easily be converted to JSON or any other format needed.
|
|
65
|
+
|
|
66
|
+
The goal of **ypres** is to be able to do this *simply*, *reliably*, and
|
|
67
|
+
*quickly*. Since serializers are class based, they can be combined,
|
|
68
|
+
extended and customized with very little code duplication.
|
|
69
|
+
|
|
70
|
+
## Changes from Serpy
|
|
71
|
+
|
|
72
|
+
There are some notable changes from the original Serpy serializer in this fork.
|
|
73
|
+
|
|
74
|
+
### New Serializer classes: AsyncSerializer and AsyncDictSerializer
|
|
75
|
+
|
|
76
|
+
Serpy did not allow for `MethodField` implementations to use async / await methods.
|
|
77
|
+
For those instances where you wish to embed an async / await coroutine in your serializer,
|
|
78
|
+
two new serializer classes, `AsyncSerializer` and `AsyncDictSerializer`, will automatically
|
|
79
|
+
detect whether the method being called is a coroutine and handle it appropriately.
|
|
80
|
+
|
|
81
|
+
### New StaticField class
|
|
82
|
+
|
|
83
|
+
When combining many fields and manipulating output, it is sometimes desirable to have
|
|
84
|
+
a fixed value for certain fields in the output. The new `StaticField` class allows
|
|
85
|
+
you to specify a fixed value for the field, and this will always appear in the output.
|
|
86
|
+
|
|
87
|
+
### Serializers allow a context object
|
|
88
|
+
|
|
89
|
+
Additional context can be passed in to a serializer. This is helpful if you have some context
|
|
90
|
+
that you wish to use when serializing the object. For example, you might pass in a user object
|
|
91
|
+
that could customize the responses in the serializer with their name, or only perform certain
|
|
92
|
+
serialization tasks if they are of a specific class (e.g., admin).
|
|
93
|
+
|
|
94
|
+
### Date and DateTime Serializer Fields
|
|
95
|
+
|
|
96
|
+
Date and DateTime fields can be serialized, based on the implementation from another fork,
|
|
97
|
+
https://github.com/PKharlamov/drf-serpy/blob/master/drf_serpy/fields.py.
|
|
98
|
+
|
|
99
|
+
### Deprecated the `.data` property.
|
|
100
|
+
|
|
101
|
+
Since `.data` can return either a `list` (with `many=True`) or a `dict`, type checkers
|
|
102
|
+
complained when you serialized a single object because the calling code does not handle
|
|
103
|
+
the case of `data` being a list.
|
|
104
|
+
|
|
105
|
+
Instead, two new properties, `serialized` and `serialized_many` are introduced that
|
|
106
|
+
return a dict and a list directly. In the course of doing this work the class structure
|
|
107
|
+
for the serializers was reworked to better implement common checks and data in the superclass.
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
import ypres
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class MySerializer(ypres.Serializer):
|
|
114
|
+
foo = ypres.MethodField()
|
|
115
|
+
blah = ypres.MethodField()
|
|
116
|
+
|
|
117
|
+
def get_foo(self, obj):
|
|
118
|
+
foo_data = obj.foo
|
|
119
|
+
ctx_data = self.context.get("additional", "")
|
|
120
|
+
return f"{foo_data}_{ctx_data}"
|
|
121
|
+
|
|
122
|
+
def get_blah(self, obj):
|
|
123
|
+
blah_data = obj.blah
|
|
124
|
+
ctx_data = self.context.get("additional", "")
|
|
125
|
+
return f"{blah_data}_{ctx_data}"
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class Foo:
|
|
129
|
+
foo = "foo"
|
|
130
|
+
blah = "blah"
|
|
131
|
+
|
|
132
|
+
my_data = MySerializer(Foo(), context={"additional": "bar"}).serialized
|
|
133
|
+
|
|
134
|
+
# {"foo": "foo_bar", "blah": "blah_bar"}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Changed behaviour of None
|
|
138
|
+
|
|
139
|
+
By default, data that evaluates to a value of `None` will **not** be included
|
|
140
|
+
in the output. To explicitly mark that a field should emit a `None` value,
|
|
141
|
+
it should be instantiated with an `emit_none=True` argument.
|
|
142
|
+
|
|
143
|
+
Note that the combination of `emit_none` and `required` deserve special attention.
|
|
144
|
+
|
|
145
|
+
- If `emit_none` is `False` and `required` is `True` (default), then the object
|
|
146
|
+
being serialized must have the matching attribute available, otherwise it will
|
|
147
|
+
raise an error. The only exception is if the field is a `MethodField`, in which
|
|
148
|
+
case the attribute does not need to be present on the object.
|
|
149
|
+
This behaviour is not changed.
|
|
150
|
+
- If `emit_none` is `False` and `required` is `False` then the object being
|
|
151
|
+
serialized will not appear in the output if its value is `None`
|
|
152
|
+
- If `emit_none` is `True` and `required` is `True`, then the object being
|
|
153
|
+
serialized will attempt to return the value. However, it may fail if the `to_value`
|
|
154
|
+
method being used does not accept `None`. An example of this is the `IntField`
|
|
155
|
+
serializer, where the `to_value` method would effectively be calling `int(None)`.
|
|
156
|
+
In this case, a `TypeError` will be raised. (This is the same as trying to serialize
|
|
157
|
+
a string with an `IntField`, for example)
|
|
158
|
+
- If `emit_none` is `True` and `required` is `False`, then the object being
|
|
159
|
+
serialized will actually skip the `to_value` step and simply return `None`.
|
|
160
|
+
|
|
161
|
+
Further to this, the behaviour of the `StrField` and `BoolField` were changed,
|
|
162
|
+
where calling `StrField` on a value of `None` would actually return the string
|
|
163
|
+
`"None"`. Similarly, calling `bool(None)` evaluates to `False`. In both of these
|
|
164
|
+
cases the `to_value` handler has been modified to return `None` if the incoming
|
|
165
|
+
value is `None`.
|
|
166
|
+
|
|
167
|
+
This prevents unexpected type values from appearing in the
|
|
168
|
+
output. For values that cannot be cast to `None` for `IntField` and `FloatField`,
|
|
169
|
+
a `None` input will raise an exception.
|
|
170
|
+
|
|
171
|
+
### Modern Python standards
|
|
172
|
+
|
|
173
|
+
The project uses update Python packaging setups with `pyproject.toml`. It also
|
|
174
|
+
adds configurations for `ruff`, works with `uv`, and fully supports type annotations.
|
|
175
|
+
|
|
176
|
+
## Source
|
|
177
|
+
|
|
178
|
+
Source at: <https://github.com/rism-digital/ypres>
|
|
179
|
+
|
|
180
|
+
If you want a feature, send a pull request!
|
|
181
|
+
|
|
182
|
+
## Installation
|
|
183
|
+
|
|
184
|
+
``` bash
|
|
185
|
+
$ pip install git+https://github.com/rism-digital/ypres
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Examples
|
|
189
|
+
|
|
190
|
+
### Simple Example
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
import ypres
|
|
194
|
+
|
|
195
|
+
class Foo(object):
|
|
196
|
+
"""The object to be serialized."""
|
|
197
|
+
y = 'hello'
|
|
198
|
+
z = 9.5
|
|
199
|
+
|
|
200
|
+
def __init__(self, x):
|
|
201
|
+
self.x = x
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class FooSerializer(ypres.Serializer):
|
|
205
|
+
"""The serializer schema definition."""
|
|
206
|
+
# Use a Field subclass like IntField if you need more validation.
|
|
207
|
+
x = ypres.IntField()
|
|
208
|
+
y = ypres.Field()
|
|
209
|
+
z = ypres.Field()
|
|
210
|
+
|
|
211
|
+
f = Foo(1)
|
|
212
|
+
FooSerializer(f).serialized
|
|
213
|
+
# {'x': 1, 'y': 'hello', 'z': 9.5}
|
|
214
|
+
|
|
215
|
+
fs = [Foo(i) for i in range(100)]
|
|
216
|
+
FooSerializer(fs, many=True).serialized_many
|
|
217
|
+
# [{'x': 0, 'y': 'hello', 'z': 9.5}, {'x': 1, 'y': 'hello', 'z': 9.5}, ...]
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Nested Example
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
import ypres
|
|
224
|
+
|
|
225
|
+
class Nestee(object):
|
|
226
|
+
"""An object nested inside another object."""
|
|
227
|
+
n = 'hi'
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class Foo(object):
|
|
231
|
+
x = 1
|
|
232
|
+
nested = Nestee()
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class NesteeSerializer(ypres.Serializer):
|
|
236
|
+
n = ypres.Field()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class FooSerializer(ypres.Serializer):
|
|
240
|
+
x = ypres.Field()
|
|
241
|
+
# Use another serializer as a field.
|
|
242
|
+
nested = NesteeSerializer()
|
|
243
|
+
|
|
244
|
+
f = Foo()
|
|
245
|
+
FooSerializer(f).serialized
|
|
246
|
+
# {'x': 1, 'nested': {'n': 'hi'}}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Complex Example
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
import ypres
|
|
253
|
+
|
|
254
|
+
class Foo(object):
|
|
255
|
+
y = 1
|
|
256
|
+
z = 2
|
|
257
|
+
super_long_thing = 10
|
|
258
|
+
|
|
259
|
+
def x(self):
|
|
260
|
+
return 5
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class FooSerializer(ypres.Serializer):
|
|
264
|
+
w = ypres.Field(attr='super_long_thing')
|
|
265
|
+
x = ypres.Field(call=True)
|
|
266
|
+
plus = ypres.MethodField()
|
|
267
|
+
|
|
268
|
+
def get_plus(self, obj):
|
|
269
|
+
return obj.y + obj.z
|
|
270
|
+
|
|
271
|
+
f = Foo()
|
|
272
|
+
FooSerializer(f).serialized
|
|
273
|
+
# {'w': 10, 'x': 5, 'plus': 3}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Inheritance Example
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
import ypres
|
|
280
|
+
|
|
281
|
+
class Foo(object):
|
|
282
|
+
a = 1
|
|
283
|
+
b = 2
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class ASerializer(ypres.Serializer):
|
|
287
|
+
a = ypres.Field()
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class ABSerializer(ASerializer):
|
|
291
|
+
"""ABSerializer inherits the 'a' field from ASerializer.
|
|
292
|
+
|
|
293
|
+
This also works with multiple inheritance and mixins.
|
|
294
|
+
"""
|
|
295
|
+
b = ypres.Field()
|
|
296
|
+
|
|
297
|
+
f = Foo()
|
|
298
|
+
ASerializer(f).serialized
|
|
299
|
+
# {'a': 1}
|
|
300
|
+
ABSerializer(f).serialized
|
|
301
|
+
# {'a': 1, 'b': 2}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## License
|
|
305
|
+
|
|
306
|
+
ypres is free software distributed under the terms of the MIT license.
|
|
307
|
+
See the [LICENSE](https://github.com/clarkduvall/serpy/blob/master/LICENSE) file.
|