marshmallow 3.26.0__py3-none-any.whl → 4.0.0__py3-none-any.whl
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.
- marshmallow/__init__.py +1 -51
- marshmallow/constants.py +22 -0
- marshmallow/decorators.py +56 -40
- marshmallow/exceptions.py +3 -3
- marshmallow/experimental/__init__.py +5 -0
- marshmallow/experimental/context.py +73 -0
- marshmallow/fields.py +379 -452
- marshmallow/schema.py +140 -199
- marshmallow/types.py +14 -6
- marshmallow/utils.py +17 -226
- marshmallow/validate.py +2 -16
- {marshmallow-3.26.0.dist-info → marshmallow-4.0.0.dist-info}/METADATA +8 -6
- marshmallow-4.0.0.dist-info/RECORD +19 -0
- {marshmallow-3.26.0.dist-info → marshmallow-4.0.0.dist-info}/WHEEL +1 -1
- marshmallow/base.py +0 -61
- marshmallow/warnings.py +0 -10
- marshmallow-3.26.0.dist-info/RECORD +0 -18
- {marshmallow-3.26.0.dist-info → marshmallow-4.0.0.dist-info/licenses}/LICENSE +0 -0
marshmallow/__init__.py
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
import importlib.metadata
|
|
4
|
-
import typing
|
|
5
|
-
|
|
6
|
-
from packaging.version import Version
|
|
7
|
-
|
|
1
|
+
from marshmallow.constants import EXCLUDE, INCLUDE, RAISE, missing
|
|
8
2
|
from marshmallow.decorators import (
|
|
9
3
|
post_dump,
|
|
10
4
|
post_load,
|
|
@@ -15,53 +9,9 @@ from marshmallow.decorators import (
|
|
|
15
9
|
)
|
|
16
10
|
from marshmallow.exceptions import ValidationError
|
|
17
11
|
from marshmallow.schema import Schema, SchemaOpts
|
|
18
|
-
from marshmallow.utils import EXCLUDE, INCLUDE, RAISE, missing, pprint
|
|
19
12
|
|
|
20
13
|
from . import fields
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
def __getattr__(name: str) -> typing.Any:
|
|
24
|
-
import warnings
|
|
25
|
-
|
|
26
|
-
if name == "__version__":
|
|
27
|
-
warnings.warn(
|
|
28
|
-
"The '__version__' attribute is deprecated and will be removed in"
|
|
29
|
-
" in a future version. Use feature detection or"
|
|
30
|
-
" 'importlib.metadata.version(\"marshmallow\")' instead.",
|
|
31
|
-
DeprecationWarning,
|
|
32
|
-
stacklevel=2,
|
|
33
|
-
)
|
|
34
|
-
return importlib.metadata.version("marshmallow")
|
|
35
|
-
|
|
36
|
-
if name == "__parsed_version__":
|
|
37
|
-
warnings.warn(
|
|
38
|
-
"The '__parsed_version__' attribute is deprecated and will be removed in"
|
|
39
|
-
" in a future version. Use feature detection or"
|
|
40
|
-
" 'packaging.Version(importlib.metadata.version(\"marshmallow\"))' instead.",
|
|
41
|
-
DeprecationWarning,
|
|
42
|
-
stacklevel=2,
|
|
43
|
-
)
|
|
44
|
-
return Version(importlib.metadata.version("marshmallow"))
|
|
45
|
-
|
|
46
|
-
if name == "__version_info__":
|
|
47
|
-
warnings.warn(
|
|
48
|
-
"The '__version_info__' attribute is deprecated and will be removed in"
|
|
49
|
-
" in a future version. Use feature detection or"
|
|
50
|
-
" 'packaging.Version(importlib.metadata.version(\"marshmallow\")).release' instead.",
|
|
51
|
-
DeprecationWarning,
|
|
52
|
-
stacklevel=2,
|
|
53
|
-
)
|
|
54
|
-
__parsed_version__ = Version(importlib.metadata.version("marshmallow"))
|
|
55
|
-
__version_info__: tuple[int, int, int] | tuple[int, int, int, str, int] = (
|
|
56
|
-
__parsed_version__.release # type: ignore[assignment]
|
|
57
|
-
)
|
|
58
|
-
if __parsed_version__.pre:
|
|
59
|
-
__version_info__ += __parsed_version__.pre # type: ignore[assignment]
|
|
60
|
-
return __version_info__
|
|
61
|
-
|
|
62
|
-
raise AttributeError(name)
|
|
63
|
-
|
|
64
|
-
|
|
65
15
|
__all__ = [
|
|
66
16
|
"EXCLUDE",
|
|
67
17
|
"INCLUDE",
|
marshmallow/constants.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
EXCLUDE: typing.Final = "exclude"
|
|
4
|
+
INCLUDE: typing.Final = "include"
|
|
5
|
+
RAISE: typing.Final = "raise"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _Missing:
|
|
9
|
+
def __bool__(self):
|
|
10
|
+
return False
|
|
11
|
+
|
|
12
|
+
def __copy__(self):
|
|
13
|
+
return self
|
|
14
|
+
|
|
15
|
+
def __deepcopy__(self, _):
|
|
16
|
+
return self
|
|
17
|
+
|
|
18
|
+
def __repr__(self):
|
|
19
|
+
return "<marshmallow.missing>"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
missing: typing.Final = _Missing()
|
marshmallow/decorators.py
CHANGED
|
@@ -35,12 +35,12 @@ Example: ::
|
|
|
35
35
|
item["email"] = item["email"].lower().strip()
|
|
36
36
|
return item
|
|
37
37
|
|
|
38
|
-
@pre_load(
|
|
38
|
+
@pre_load(pass_collection=True)
|
|
39
39
|
def remove_envelope(self, data, many, **kwargs):
|
|
40
40
|
namespace = "results" if many else "result"
|
|
41
41
|
return data[namespace]
|
|
42
42
|
|
|
43
|
-
@post_dump(
|
|
43
|
+
@post_dump(pass_collection=True)
|
|
44
44
|
def add_envelope(self, data, many, **kwargs):
|
|
45
45
|
namespace = "results" if many else "result"
|
|
46
46
|
return {namespace: data}
|
|
@@ -83,25 +83,29 @@ class MarshmallowHook:
|
|
|
83
83
|
__marshmallow_hook__: dict[str, list[tuple[bool, Any]]] | None = None
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
def validates(
|
|
87
|
-
"""Register a field
|
|
86
|
+
def validates(*field_names: str) -> Callable[..., Any]:
|
|
87
|
+
"""Register a validator method for field(s).
|
|
88
88
|
|
|
89
|
-
:param
|
|
89
|
+
:param field_names: Names of the fields that the method validates.
|
|
90
|
+
|
|
91
|
+
.. versionchanged:: 4.0.0 Accepts multiple field names as positional arguments.
|
|
92
|
+
.. versionchanged:: 4.0.0 Decorated methods receive ``data_key`` as a keyword argument.
|
|
90
93
|
"""
|
|
91
|
-
return set_hook(None, VALIDATES,
|
|
94
|
+
return set_hook(None, VALIDATES, field_names=field_names)
|
|
92
95
|
|
|
93
96
|
|
|
94
97
|
def validates_schema(
|
|
95
98
|
fn: Callable[..., Any] | None = None,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
*,
|
|
100
|
+
pass_collection: bool = False,
|
|
101
|
+
pass_original: bool = False,
|
|
102
|
+
skip_on_field_errors: bool = True,
|
|
99
103
|
) -> Callable[..., Any]:
|
|
100
104
|
"""Register a schema-level validator.
|
|
101
105
|
|
|
102
106
|
By default it receives a single object at a time, transparently handling the ``many``
|
|
103
107
|
argument passed to the `Schema <marshmallow.Schema>`'s :func:`~marshmallow.Schema.validate` call.
|
|
104
|
-
If ``
|
|
108
|
+
If ``pass_collection=True``, the raw data (which may be a collection) is passed.
|
|
105
109
|
|
|
106
110
|
If ``pass_original=True``, the original data (before unmarshalling) will be passed as
|
|
107
111
|
an additional argument to the method.
|
|
@@ -109,17 +113,18 @@ def validates_schema(
|
|
|
109
113
|
If ``skip_on_field_errors=True``, this validation method will be skipped whenever
|
|
110
114
|
validation errors have been detected when validating fields.
|
|
111
115
|
|
|
112
|
-
.. versionchanged:: 3.0.0b1
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
.. versionchanged:: 3.0.0
|
|
116
|
-
``partial`` and ``many`` are always passed as keyword arguments to
|
|
116
|
+
.. versionchanged:: 3.0.0b1 ``skip_on_field_errors`` defaults to `True`.
|
|
117
|
+
.. versionchanged:: 3.0.0 ``partial`` and ``many`` are always passed as keyword arguments to
|
|
117
118
|
the decorated method.
|
|
119
|
+
.. versionchanged:: 4.0.0 ``unknown`` is passed as a keyword argument to the decorated method.
|
|
120
|
+
.. versionchanged:: 4.0.0 ``pass_many`` is renamed to ``pass_collection``.
|
|
121
|
+
.. versionchanged:: 4.0.0 ``pass_collection``, ``pass_original``, and ``skip_on_field_errors``
|
|
122
|
+
are keyword-only arguments.
|
|
118
123
|
"""
|
|
119
124
|
return set_hook(
|
|
120
125
|
fn,
|
|
121
126
|
VALIDATES_SCHEMA,
|
|
122
|
-
many=
|
|
127
|
+
many=pass_collection,
|
|
123
128
|
pass_original=pass_original,
|
|
124
129
|
skip_on_field_errors=skip_on_field_errors,
|
|
125
130
|
)
|
|
@@ -127,86 +132,97 @@ def validates_schema(
|
|
|
127
132
|
|
|
128
133
|
def pre_dump(
|
|
129
134
|
fn: Callable[..., Any] | None = None,
|
|
130
|
-
|
|
135
|
+
*,
|
|
136
|
+
pass_collection: bool = False,
|
|
131
137
|
) -> Callable[..., Any]:
|
|
132
138
|
"""Register a method to invoke before serializing an object. The method
|
|
133
139
|
receives the object to be serialized and returns the processed object.
|
|
134
140
|
|
|
135
141
|
By default it receives a single object at a time, transparently handling the ``many``
|
|
136
142
|
argument passed to the `Schema <marshmallow.Schema>`'s :func:`~marshmallow.Schema.dump` call.
|
|
137
|
-
If ``
|
|
143
|
+
If ``pass_collection=True``, the raw data (which may be a collection) is passed.
|
|
138
144
|
|
|
139
|
-
.. versionchanged:: 3.0.0
|
|
140
|
-
|
|
145
|
+
.. versionchanged:: 3.0.0 ``many`` is always passed as a keyword arguments to the decorated method.
|
|
146
|
+
.. versionchanged:: 4.0.0 ``pass_many`` is renamed to ``pass_collection``.
|
|
147
|
+
.. versionchanged:: 4.0.0 ``pass_collection`` is a keyword-only argument.
|
|
141
148
|
"""
|
|
142
|
-
return set_hook(fn, PRE_DUMP, many=
|
|
149
|
+
return set_hook(fn, PRE_DUMP, many=pass_collection)
|
|
143
150
|
|
|
144
151
|
|
|
145
152
|
def post_dump(
|
|
146
153
|
fn: Callable[..., Any] | None = None,
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
*,
|
|
155
|
+
pass_collection: bool = False,
|
|
156
|
+
pass_original: bool = False,
|
|
149
157
|
) -> Callable[..., Any]:
|
|
150
158
|
"""Register a method to invoke after serializing an object. The method
|
|
151
159
|
receives the serialized object and returns the processed object.
|
|
152
160
|
|
|
153
161
|
By default it receives a single object at a time, transparently handling the ``many``
|
|
154
162
|
argument passed to the `Schema <marshmallow.Schema>`'s :func:`~marshmallow.Schema.dump` call.
|
|
155
|
-
If ``
|
|
163
|
+
If ``pass_collection=True``, the raw data (which may be a collection) is passed.
|
|
156
164
|
|
|
157
165
|
If ``pass_original=True``, the original data (before serializing) will be passed as
|
|
158
166
|
an additional argument to the method.
|
|
159
167
|
|
|
160
|
-
.. versionchanged:: 3.0.0
|
|
161
|
-
|
|
168
|
+
.. versionchanged:: 3.0.0 ``many`` is always passed as a keyword arguments to the decorated method.
|
|
169
|
+
.. versionchanged:: 4.0.0 ``pass_many`` is renamed to ``pass_collection``.
|
|
170
|
+
.. versionchanged:: 4.0.0 ``pass_collection`` and ``pass_original`` are keyword-only arguments.
|
|
162
171
|
"""
|
|
163
|
-
return set_hook(fn, POST_DUMP, many=
|
|
172
|
+
return set_hook(fn, POST_DUMP, many=pass_collection, pass_original=pass_original)
|
|
164
173
|
|
|
165
174
|
|
|
166
175
|
def pre_load(
|
|
167
176
|
fn: Callable[..., Any] | None = None,
|
|
168
|
-
|
|
177
|
+
*,
|
|
178
|
+
pass_collection: bool = False,
|
|
169
179
|
) -> Callable[..., Any]:
|
|
170
180
|
"""Register a method to invoke before deserializing an object. The method
|
|
171
181
|
receives the data to be deserialized and returns the processed data.
|
|
172
182
|
|
|
173
183
|
By default it receives a single object at a time, transparently handling the ``many``
|
|
174
184
|
argument passed to the `Schema <marshmallow.Schema>`'s :func:`~marshmallow.Schema.load` call.
|
|
175
|
-
If ``
|
|
185
|
+
If ``pass_collection=True``, the raw data (which may be a collection) is passed.
|
|
176
186
|
|
|
177
|
-
.. versionchanged:: 3.0.0
|
|
178
|
-
``partial`` and ``many`` are always passed as keyword arguments to
|
|
187
|
+
.. versionchanged:: 3.0.0 ``partial`` and ``many`` are always passed as keyword arguments to
|
|
179
188
|
the decorated method.
|
|
189
|
+
.. versionchanged:: 4.0.0 ``pass_many`` is renamed to ``pass_collection``.
|
|
190
|
+
.. versionchanged:: 4.0.0 ``pass_collection`` is a keyword-only argument.
|
|
191
|
+
.. versionchanged:: 4.0.0 ``unknown`` is passed as a keyword argument to the decorated method.
|
|
180
192
|
"""
|
|
181
|
-
return set_hook(fn, PRE_LOAD, many=
|
|
193
|
+
return set_hook(fn, PRE_LOAD, many=pass_collection)
|
|
182
194
|
|
|
183
195
|
|
|
184
196
|
def post_load(
|
|
185
197
|
fn: Callable[..., Any] | None = None,
|
|
186
|
-
|
|
187
|
-
|
|
198
|
+
*,
|
|
199
|
+
pass_collection: bool = False,
|
|
200
|
+
pass_original: bool = False,
|
|
188
201
|
) -> Callable[..., Any]:
|
|
189
202
|
"""Register a method to invoke after deserializing an object. The method
|
|
190
203
|
receives the deserialized data and returns the processed data.
|
|
191
204
|
|
|
192
205
|
By default it receives a single object at a time, transparently handling the ``many``
|
|
193
206
|
argument passed to the `Schema <marshmallow.Schema>`'s :func:`~marshmallow.Schema.load` call.
|
|
194
|
-
If ``
|
|
207
|
+
If ``pass_collection=True``, the raw data (which may be a collection) is passed.
|
|
195
208
|
|
|
196
209
|
If ``pass_original=True``, the original data (before deserializing) will be passed as
|
|
197
210
|
an additional argument to the method.
|
|
198
211
|
|
|
199
|
-
.. versionchanged:: 3.0.0
|
|
200
|
-
``partial`` and ``many`` are always passed as keyword arguments to
|
|
212
|
+
.. versionchanged:: 3.0.0 ``partial`` and ``many`` are always passed as keyword arguments to
|
|
201
213
|
the decorated method.
|
|
214
|
+
.. versionchanged:: 4.0.0 ``pass_many`` is renamed to ``pass_collection``.
|
|
215
|
+
.. versionchanged:: 4.0.0 ``pass_collection`` and ``pass_original`` are keyword-only arguments.
|
|
216
|
+
.. versionchanged:: 4.0.0 ``unknown`` is passed as a keyword argument to the decorated method.
|
|
202
217
|
"""
|
|
203
|
-
return set_hook(fn, POST_LOAD, many=
|
|
218
|
+
return set_hook(fn, POST_LOAD, many=pass_collection, pass_original=pass_original)
|
|
204
219
|
|
|
205
220
|
|
|
206
221
|
def set_hook(
|
|
207
222
|
fn: Callable[..., Any] | None,
|
|
208
223
|
tag: str,
|
|
209
|
-
|
|
224
|
+
*,
|
|
225
|
+
many: bool = False,
|
|
210
226
|
**kwargs: Any,
|
|
211
227
|
) -> Callable[..., Any]:
|
|
212
228
|
"""Mark decorated function as a hook to be picked up later.
|
|
@@ -225,7 +241,7 @@ def set_hook(
|
|
|
225
241
|
|
|
226
242
|
# Set a __marshmallow_hook__ attribute instead of wrapping in some class,
|
|
227
243
|
# because I still want this to end up as a normal (unbound) method.
|
|
228
|
-
function = cast(MarshmallowHook, fn)
|
|
244
|
+
function = cast("MarshmallowHook", fn)
|
|
229
245
|
try:
|
|
230
246
|
hook_config = function.__marshmallow_hook__
|
|
231
247
|
except AttributeError:
|
marshmallow/exceptions.py
CHANGED
|
@@ -32,7 +32,7 @@ class ValidationError(MarshmallowError):
|
|
|
32
32
|
data: typing.Mapping[str, typing.Any]
|
|
33
33
|
| typing.Iterable[typing.Mapping[str, typing.Any]]
|
|
34
34
|
| None = None,
|
|
35
|
-
valid_data: list[
|
|
35
|
+
valid_data: list[typing.Any] | dict[str, typing.Any] | None = None,
|
|
36
36
|
**kwargs,
|
|
37
37
|
):
|
|
38
38
|
self.messages = [message] if isinstance(message, (str, bytes)) else message
|
|
@@ -67,5 +67,5 @@ class StringNotCollectionError(MarshmallowError, TypeError):
|
|
|
67
67
|
"""Raised when a string is passed when a list of strings is expected."""
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
class
|
|
71
|
-
"""Raised when
|
|
70
|
+
class _FieldInstanceResolutionError(MarshmallowError, TypeError):
|
|
71
|
+
"""Raised when an argument is passed to a field class that cannot be resolved to a Field instance."""
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Helper API for setting serialization/deserialization context.
|
|
2
|
+
|
|
3
|
+
Example usage:
|
|
4
|
+
|
|
5
|
+
.. code-block:: python
|
|
6
|
+
|
|
7
|
+
import typing
|
|
8
|
+
|
|
9
|
+
from marshmallow import Schema, fields
|
|
10
|
+
from marshmallow.experimental.context import Context
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class UserContext(typing.TypedDict):
|
|
14
|
+
suffix: str
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
UserSchemaContext = Context[UserContext]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class UserSchema(Schema):
|
|
21
|
+
name_suffixed = fields.Function(
|
|
22
|
+
lambda user: user["name"] + UserSchemaContext.get()["suffix"]
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
with UserSchemaContext({"suffix": "bar"}):
|
|
27
|
+
print(UserSchema().dump({"name": "foo"}))
|
|
28
|
+
# {'name_suffixed': 'foobar'}
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import contextlib
|
|
34
|
+
import contextvars
|
|
35
|
+
import typing
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
from types import EllipsisType
|
|
39
|
+
except ImportError: # Python<3.10
|
|
40
|
+
EllipsisType = type(Ellipsis) # type: ignore[misc]
|
|
41
|
+
|
|
42
|
+
_ContextT = typing.TypeVar("_ContextT")
|
|
43
|
+
_DefaultT = typing.TypeVar("_DefaultT")
|
|
44
|
+
_CURRENT_CONTEXT: contextvars.ContextVar = contextvars.ContextVar("context")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Context(contextlib.AbstractContextManager, typing.Generic[_ContextT]):
|
|
48
|
+
"""Context manager for setting and retrieving context.
|
|
49
|
+
|
|
50
|
+
:param context: The context to use within the context manager scope.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(self, context: _ContextT) -> None:
|
|
54
|
+
self.context = context
|
|
55
|
+
self.token: contextvars.Token | None = None
|
|
56
|
+
|
|
57
|
+
def __enter__(self) -> Context[_ContextT]:
|
|
58
|
+
self.token = _CURRENT_CONTEXT.set(self.context)
|
|
59
|
+
return self
|
|
60
|
+
|
|
61
|
+
def __exit__(self, *args, **kwargs) -> None:
|
|
62
|
+
_CURRENT_CONTEXT.reset(typing.cast("contextvars.Token", self.token))
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def get(cls, default: _DefaultT | EllipsisType = ...) -> _ContextT | _DefaultT:
|
|
66
|
+
"""Get the current context.
|
|
67
|
+
|
|
68
|
+
:param default: Default value to return if no context is set.
|
|
69
|
+
If not provided and no context is set, a :exc:`LookupError` is raised.
|
|
70
|
+
"""
|
|
71
|
+
if default is not ...:
|
|
72
|
+
return _CURRENT_CONTEXT.get(default)
|
|
73
|
+
return _CURRENT_CONTEXT.get()
|