marshmallow 3.25.0__py3-none-any.whl → 3.26.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 +6 -6
- marshmallow/class_registry.py +8 -9
- marshmallow/decorators.py +16 -11
- marshmallow/error_store.py +3 -3
- marshmallow/fields.py +98 -81
- marshmallow/orderedset.py +1 -1
- marshmallow/schema.py +191 -101
- marshmallow/types.py +29 -0
- marshmallow/utils.py +20 -18
- marshmallow/validate.py +37 -23
- {marshmallow-3.25.0.dist-info → marshmallow-3.26.0.dist-info}/METADATA +16 -7
- marshmallow-3.26.0.dist-info/RECORD +18 -0
- marshmallow-3.25.0.dist-info/RECORD +0 -18
- {marshmallow-3.25.0.dist-info → marshmallow-3.26.0.dist-info}/LICENSE +0 -0
- {marshmallow-3.25.0.dist-info → marshmallow-3.26.0.dist-info}/WHEEL +0 -0
marshmallow/schema.py
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
"""The
|
|
1
|
+
"""The `Schema <marshmallow.Schema>` class, including its metaclass and options (`class Meta <marshmallow.Schema.Meta>`)."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import copy
|
|
6
6
|
import datetime as dt
|
|
7
7
|
import decimal
|
|
8
|
+
import functools
|
|
8
9
|
import inspect
|
|
9
10
|
import json
|
|
11
|
+
import operator
|
|
10
12
|
import typing
|
|
11
13
|
import uuid
|
|
12
14
|
import warnings
|
|
13
15
|
from abc import ABCMeta
|
|
14
16
|
from collections import OrderedDict, defaultdict
|
|
15
17
|
from collections.abc import Mapping
|
|
18
|
+
from itertools import zip_longest
|
|
16
19
|
|
|
17
20
|
from marshmallow import base, class_registry, types
|
|
18
21
|
from marshmallow import fields as ma_fields
|
|
@@ -25,7 +28,7 @@ from marshmallow.decorators import (
|
|
|
25
28
|
VALIDATES_SCHEMA,
|
|
26
29
|
)
|
|
27
30
|
from marshmallow.error_store import ErrorStore
|
|
28
|
-
from marshmallow.exceptions import StringNotCollectionError, ValidationError
|
|
31
|
+
from marshmallow.exceptions import SCHEMA, StringNotCollectionError, ValidationError
|
|
29
32
|
from marshmallow.orderedset import OrderedSet
|
|
30
33
|
from marshmallow.utils import (
|
|
31
34
|
EXCLUDE,
|
|
@@ -40,8 +43,11 @@ from marshmallow.utils import (
|
|
|
40
43
|
)
|
|
41
44
|
from marshmallow.warnings import RemovedInMarshmallow4Warning
|
|
42
45
|
|
|
46
|
+
if typing.TYPE_CHECKING:
|
|
47
|
+
from marshmallow.fields import Field
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
|
|
50
|
+
def _get_fields(attrs) -> list[tuple[str, Field]]:
|
|
45
51
|
"""Get fields from a class
|
|
46
52
|
|
|
47
53
|
:param attrs: Mapping of class attributes
|
|
@@ -60,11 +66,14 @@ def _get_fields_by_mro(klass: SchemaMeta):
|
|
|
60
66
|
class itself is excluded from the search; only its parents are checked. Get
|
|
61
67
|
fields from ``_declared_fields`` if available, else use ``__dict__``.
|
|
62
68
|
|
|
63
|
-
:param
|
|
69
|
+
:param klass: Class whose fields to retrieve
|
|
64
70
|
"""
|
|
65
71
|
mro = inspect.getmro(klass)
|
|
72
|
+
# Combine fields from all parents
|
|
73
|
+
# functools.reduce(operator.iadd, list_of_lists) is faster than sum(list_of_lists, [])
|
|
66
74
|
# Loop over mro in reverse to maintain correct order of fields
|
|
67
|
-
return
|
|
75
|
+
return functools.reduce(
|
|
76
|
+
operator.iadd,
|
|
68
77
|
(
|
|
69
78
|
_get_fields(
|
|
70
79
|
getattr(base, "_declared_fields", base.__dict__),
|
|
@@ -79,10 +88,20 @@ class SchemaMeta(ABCMeta):
|
|
|
79
88
|
"""Metaclass for the Schema class. Binds the declared fields to
|
|
80
89
|
a ``_declared_fields`` attribute, which is a dictionary mapping attribute
|
|
81
90
|
names to field objects. Also sets the ``opts`` class attribute, which is
|
|
82
|
-
the Schema class's
|
|
91
|
+
the Schema class's `class Meta <marshmallow.Schema.Meta>` options.
|
|
83
92
|
"""
|
|
84
93
|
|
|
85
|
-
|
|
94
|
+
Meta: type
|
|
95
|
+
opts: typing.Any
|
|
96
|
+
OPTIONS_CLASS: type
|
|
97
|
+
_declared_fields: dict[str, Field]
|
|
98
|
+
|
|
99
|
+
def __new__(
|
|
100
|
+
mcs, # noqa: N804
|
|
101
|
+
name: str,
|
|
102
|
+
bases: tuple[type, ...],
|
|
103
|
+
attrs: dict[str, typing.Any],
|
|
104
|
+
) -> SchemaMeta:
|
|
86
105
|
meta = attrs.get("Meta")
|
|
87
106
|
ordered = getattr(meta, "ordered", False)
|
|
88
107
|
if not ordered:
|
|
@@ -112,7 +131,7 @@ class SchemaMeta(ABCMeta):
|
|
|
112
131
|
cls_fields += list(klass.opts.include.items())
|
|
113
132
|
|
|
114
133
|
# Assign _declared_fields on class
|
|
115
|
-
klass._declared_fields = mcs.get_declared_fields(
|
|
134
|
+
klass._declared_fields = mcs.get_declared_fields( # noqa: SLF001
|
|
116
135
|
klass=klass,
|
|
117
136
|
cls_fields=cls_fields,
|
|
118
137
|
inherited_fields=inherited_fields,
|
|
@@ -122,19 +141,19 @@ class SchemaMeta(ABCMeta):
|
|
|
122
141
|
|
|
123
142
|
@classmethod
|
|
124
143
|
def get_declared_fields(
|
|
125
|
-
mcs,
|
|
144
|
+
mcs, # noqa: N804
|
|
126
145
|
klass: SchemaMeta,
|
|
127
|
-
cls_fields: list[tuple[str,
|
|
128
|
-
inherited_fields: list[tuple[str,
|
|
146
|
+
cls_fields: list[tuple[str, Field]],
|
|
147
|
+
inherited_fields: list[tuple[str, Field]],
|
|
129
148
|
dict_cls: type[dict] = dict,
|
|
130
|
-
) -> dict[str,
|
|
149
|
+
) -> dict[str, Field]:
|
|
131
150
|
"""Returns a dictionary of field_name => `Field` pairs declared on the class.
|
|
132
151
|
This is exposed mainly so that plugins can add additional fields, e.g. fields
|
|
133
|
-
computed from class Meta options.
|
|
152
|
+
computed from `class Meta <marshmallow.Schema.Meta>` options.
|
|
134
153
|
|
|
135
154
|
:param klass: The class object.
|
|
136
155
|
:param cls_fields: The fields declared on the class, including those added
|
|
137
|
-
by the ``include`` class Meta option.
|
|
156
|
+
by the ``include`` `class Meta <marshmallow.Schema.Meta>` option.
|
|
138
157
|
:param inherited_fields: Inherited fields.
|
|
139
158
|
:param dict_cls: dict-like class to use for dict output Default to ``dict``.
|
|
140
159
|
"""
|
|
@@ -191,9 +210,9 @@ class SchemaMeta(ABCMeta):
|
|
|
191
210
|
|
|
192
211
|
|
|
193
212
|
class SchemaOpts:
|
|
194
|
-
"""
|
|
213
|
+
"""Defines defaults for `marshmallow.Schema.Meta`."""
|
|
195
214
|
|
|
196
|
-
def __init__(self, meta, ordered: bool = False):
|
|
215
|
+
def __init__(self, meta: type, ordered: bool = False): # noqa: FBT001, FBT002
|
|
197
216
|
self.fields = getattr(meta, "fields", ())
|
|
198
217
|
if not isinstance(self.fields, (list, tuple)):
|
|
199
218
|
raise ValueError("`fields` option must be a list or tuple.")
|
|
@@ -202,8 +221,7 @@ class SchemaOpts:
|
|
|
202
221
|
raise ValueError("`additional` option must be a list or tuple.")
|
|
203
222
|
if self.fields and self.additional:
|
|
204
223
|
raise ValueError(
|
|
205
|
-
"Cannot set both `fields` and `additional` options"
|
|
206
|
-
" for the same Schema."
|
|
224
|
+
"Cannot set both `fields` and `additional` options for the same Schema."
|
|
207
225
|
)
|
|
208
226
|
self.exclude = getattr(meta, "exclude", ())
|
|
209
227
|
if not isinstance(self.exclude, (list, tuple)):
|
|
@@ -221,6 +239,14 @@ class SchemaOpts:
|
|
|
221
239
|
else:
|
|
222
240
|
render_module = json
|
|
223
241
|
self.render_module = getattr(meta, "render_module", render_module)
|
|
242
|
+
if hasattr(meta, "ordered"):
|
|
243
|
+
warnings.warn(
|
|
244
|
+
"The `ordered` `class Meta` option is deprecated. "
|
|
245
|
+
"Field order is already preserved by default. "
|
|
246
|
+
"Set `Schema.dict_class` to OrderedDict to maintain the previous behavior.",
|
|
247
|
+
RemovedInMarshmallow4Warning,
|
|
248
|
+
stacklevel=2,
|
|
249
|
+
)
|
|
224
250
|
self.ordered = getattr(meta, "ordered", ordered)
|
|
225
251
|
self.index_errors = getattr(meta, "index_errors", True)
|
|
226
252
|
self.include = getattr(meta, "include", {})
|
|
@@ -232,7 +258,7 @@ class SchemaOpts:
|
|
|
232
258
|
|
|
233
259
|
|
|
234
260
|
class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
235
|
-
"""Base schema class with which to define
|
|
261
|
+
"""Base schema class with which to define schemas.
|
|
236
262
|
|
|
237
263
|
Example usage:
|
|
238
264
|
|
|
@@ -284,7 +310,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
284
310
|
`prefix` parameter removed.
|
|
285
311
|
"""
|
|
286
312
|
|
|
287
|
-
TYPE_MAPPING: dict[type, type[
|
|
313
|
+
TYPE_MAPPING: dict[type, type[Field]] = {
|
|
288
314
|
str: ma_fields.String,
|
|
289
315
|
bytes: ma_fields.String,
|
|
290
316
|
dt.datetime: ma_fields.DateTime,
|
|
@@ -314,7 +340,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
314
340
|
|
|
315
341
|
# These get set by SchemaMeta
|
|
316
342
|
opts: typing.Any
|
|
317
|
-
_declared_fields: dict[str,
|
|
343
|
+
_declared_fields: dict[str, Field] = {}
|
|
318
344
|
_hooks: dict[str, list[tuple[str, bool, dict]]] = {}
|
|
319
345
|
|
|
320
346
|
class Meta:
|
|
@@ -322,39 +348,87 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
322
348
|
|
|
323
349
|
Example usage: ::
|
|
324
350
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
351
|
+
from marshmallow import Schema
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class MySchema(Schema):
|
|
355
|
+
class Meta:
|
|
356
|
+
fields = ("id", "email", "date_created")
|
|
357
|
+
exclude = ("password", "secret_attribute")
|
|
358
|
+
|
|
359
|
+
.. admonition:: A note on type checking
|
|
360
|
+
|
|
361
|
+
Type checkers will only check the attributes of the `Meta <marshmallow.Schema.Meta>`
|
|
362
|
+
class if you explicitly subclass `marshmallow.Schema.Meta`.
|
|
363
|
+
|
|
364
|
+
.. code-block:: python
|
|
365
|
+
|
|
366
|
+
from marshmallow import Schema
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class MySchema(Schema):
|
|
370
|
+
# Not checked by type checkers
|
|
371
|
+
class Meta:
|
|
372
|
+
additional = True
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class MySchema2(Schema):
|
|
376
|
+
# Type checkers will check attributes
|
|
377
|
+
class Meta(Schema.Opts):
|
|
378
|
+
additional = True # Incompatible types in assignment
|
|
379
|
+
|
|
380
|
+
.. versionremoved:: 3.0.0b7 Remove ``strict``.
|
|
381
|
+
.. versionadded:: 3.0.0b12 Add `unknown`.
|
|
382
|
+
.. versionchanged:: 3.0.0b17 Rename ``dateformat`` to `datetimeformat`.
|
|
383
|
+
.. versionadded:: 3.9.0 Add `timeformat`.
|
|
384
|
+
.. versionchanged:: 3.26.0 Deprecate `ordered`. Field order is preserved by default.
|
|
385
|
+
"""
|
|
386
|
+
|
|
387
|
+
fields: typing.ClassVar[tuple[Field] | list[Field]]
|
|
388
|
+
"""Fields to include in the (de)serialized result"""
|
|
389
|
+
additional: typing.ClassVar[tuple[Field] | list[Field]]
|
|
390
|
+
"""Fields to include in addition to the explicitly declared fields.
|
|
391
|
+
`additional <marshmallow.Schema.Meta.additional>` and `fields <marshmallow.Schema.Meta.fields>`
|
|
392
|
+
are mutually-exclusive options.
|
|
393
|
+
"""
|
|
394
|
+
include: typing.ClassVar[dict[str, Field]]
|
|
395
|
+
"""Dictionary of additional fields to include in the schema. It is
|
|
396
|
+
usually better to define fields as class variables, but you may need to
|
|
397
|
+
use this option, e.g., if your fields are Python keywords.
|
|
398
|
+
"""
|
|
399
|
+
exclude: typing.ClassVar[tuple[Field] | list[Field]]
|
|
400
|
+
"""Fields to exclude in the serialized result.
|
|
401
|
+
Nested fields can be represented with dot delimiters.
|
|
402
|
+
"""
|
|
403
|
+
many: typing.ClassVar[bool]
|
|
404
|
+
"""Whether data should be (de)serialized as a collection by default."""
|
|
405
|
+
dateformat: typing.ClassVar[str]
|
|
406
|
+
"""Default format for `Date <marshmallow.fields.Date>` fields."""
|
|
407
|
+
datetimeformat: typing.ClassVar[str]
|
|
408
|
+
"""Default format for `DateTime <marshmallow.fields.DateTime>` fields."""
|
|
409
|
+
timeformat: typing.ClassVar[str]
|
|
410
|
+
"""Default format for `Time <marshmallow.fields.Time>` fields."""
|
|
411
|
+
render_module: typing.ClassVar[types.RenderModule]
|
|
412
|
+
""" Module to use for `loads <marshmallow.Schema.loads>` and `dumps <marshmallow.Schema.dumps>`.
|
|
413
|
+
Defaults to `json` from the standard library.
|
|
414
|
+
"""
|
|
415
|
+
ordered: typing.ClassVar[bool]
|
|
416
|
+
"""If `True`, `Schema.dump <marshmallow.Schema.dump>` is a `collections.OrderedDict`."""
|
|
417
|
+
index_errors: typing.ClassVar[bool]
|
|
418
|
+
"""If `True`, errors dictionaries will include the index of invalid items in a collection."""
|
|
419
|
+
load_only: typing.ClassVar[tuple[Field] | list[Field]]
|
|
420
|
+
"""Fields to exclude from serialized results"""
|
|
421
|
+
dump_only: typing.ClassVar[tuple[Field] | list[Field]]
|
|
422
|
+
"""Fields to exclude from serialized results"""
|
|
423
|
+
unknown: typing.ClassVar[str]
|
|
424
|
+
"""Whether to exclude, include, or raise an error for unknown fields in the data.
|
|
425
|
+
Use `EXCLUDE`, `INCLUDE` or `RAISE`.
|
|
426
|
+
"""
|
|
427
|
+
register: typing.ClassVar[bool]
|
|
428
|
+
"""Whether to register the `Schema <marshmallow.Schema>` with marshmallow's internal
|
|
429
|
+
class registry. Must be `True` if you intend to refer to this `Schema <marshmallow.Schema>`
|
|
430
|
+
by class name in `Nested` fields. Only set this to `False` when memory
|
|
431
|
+
usage is critical. Defaults to `True`.
|
|
358
432
|
"""
|
|
359
433
|
|
|
360
434
|
def __init__(
|
|
@@ -400,9 +474,9 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
400
474
|
self.context = context or {}
|
|
401
475
|
self._normalize_nested_options()
|
|
402
476
|
#: Dictionary mapping field_names -> :class:`Field` objects
|
|
403
|
-
self.fields: dict[str,
|
|
404
|
-
self.load_fields: dict[str,
|
|
405
|
-
self.dump_fields: dict[str,
|
|
477
|
+
self.fields: dict[str, Field] = {}
|
|
478
|
+
self.load_fields: dict[str, Field] = {}
|
|
479
|
+
self.dump_fields: dict[str, Field] = {}
|
|
406
480
|
self._init_fields()
|
|
407
481
|
messages = {}
|
|
408
482
|
messages.update(self._default_error_messages)
|
|
@@ -416,15 +490,15 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
416
490
|
|
|
417
491
|
@property
|
|
418
492
|
def dict_class(self) -> type[dict]:
|
|
493
|
+
"""`dict` type to return when serializing."""
|
|
419
494
|
if self.ordered:
|
|
420
495
|
return OrderedDict
|
|
421
|
-
|
|
422
|
-
return dict
|
|
496
|
+
return dict
|
|
423
497
|
|
|
424
498
|
@classmethod
|
|
425
499
|
def from_dict(
|
|
426
500
|
cls,
|
|
427
|
-
fields: dict[str,
|
|
501
|
+
fields: dict[str, Field],
|
|
428
502
|
*,
|
|
429
503
|
name: str = "GeneratedSchema",
|
|
430
504
|
) -> type[Schema]:
|
|
@@ -440,8 +514,9 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
440
514
|
Generated schemas are not added to the class registry and therefore cannot
|
|
441
515
|
be referred to by name in `Nested` fields.
|
|
442
516
|
|
|
443
|
-
|
|
444
|
-
:param
|
|
517
|
+
|
|
518
|
+
:param fields: Dictionary mapping field names to field instances.
|
|
519
|
+
:param name: Optional name for the class, which will appear in
|
|
445
520
|
the ``repr`` for the class.
|
|
446
521
|
|
|
447
522
|
.. versionadded:: 3.0.0
|
|
@@ -449,8 +524,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
449
524
|
Meta = type(
|
|
450
525
|
"GeneratedMeta", (getattr(cls, "Meta", object),), {"register": False}
|
|
451
526
|
)
|
|
452
|
-
|
|
453
|
-
return schema_cls
|
|
527
|
+
return type(name, (cls,), {**fields.copy(), "Meta": Meta})
|
|
454
528
|
|
|
455
529
|
##### Override-able methods #####
|
|
456
530
|
|
|
@@ -467,7 +541,6 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
467
541
|
.. versionchanged:: 3.0.0rc9
|
|
468
542
|
Receives `many` and `partial` (on deserialization) as keyword arguments.
|
|
469
543
|
"""
|
|
470
|
-
pass
|
|
471
544
|
|
|
472
545
|
def get_attribute(self, obj: typing.Any, attr: str, default: typing.Any):
|
|
473
546
|
"""Defines how to pull values from an object to serialize.
|
|
@@ -483,11 +556,11 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
483
556
|
def _call_and_store(getter_func, data, *, field_name, error_store, index=None):
|
|
484
557
|
"""Call ``getter_func`` with ``data`` as its argument, and store any `ValidationErrors`.
|
|
485
558
|
|
|
486
|
-
:param
|
|
559
|
+
:param getter_func: Function for getting the serialized/deserialized
|
|
487
560
|
value from ``data``.
|
|
488
561
|
:param data: The data passed to ``getter_func``.
|
|
489
|
-
:param
|
|
490
|
-
:param
|
|
562
|
+
:param field_name: Field name.
|
|
563
|
+
:param index: Index of the item being validated, if validating a collection,
|
|
491
564
|
otherwise `None`.
|
|
492
565
|
"""
|
|
493
566
|
try:
|
|
@@ -503,7 +576,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
503
576
|
"""Serialize ``obj``.
|
|
504
577
|
|
|
505
578
|
:param obj: The object(s) to serialize.
|
|
506
|
-
:param
|
|
579
|
+
:param many: `True` if ``data`` should be serialized as a collection.
|
|
507
580
|
:return: A dictionary of the serialized data
|
|
508
581
|
"""
|
|
509
582
|
if many and obj is not None:
|
|
@@ -583,16 +656,16 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
583
656
|
) -> typing.Any | list[typing.Any]:
|
|
584
657
|
"""Deserialize ``data``.
|
|
585
658
|
|
|
586
|
-
:param
|
|
587
|
-
:param
|
|
588
|
-
:param
|
|
589
|
-
:param
|
|
659
|
+
:param data: The data to deserialize.
|
|
660
|
+
:param error_store: Structure to store errors.
|
|
661
|
+
:param many: `True` if ``data`` should be deserialized as a collection.
|
|
662
|
+
:param partial: Whether to ignore missing fields and not require
|
|
590
663
|
any fields declared. Propagates down to ``Nested`` fields as well. If
|
|
591
664
|
its value is an iterable, only missing fields listed in that iterable
|
|
592
665
|
will be ignored. Use dot delimiters to specify nested fields.
|
|
593
666
|
:param unknown: Whether to exclude, include, or raise an error for unknown
|
|
594
667
|
fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
|
|
595
|
-
:param
|
|
668
|
+
:param index: Index of the item being serialized (for storing errors) if
|
|
596
669
|
serializing a collection, otherwise `None`.
|
|
597
670
|
:return: The deserialized data as `dict_class` instance or list of `dict_class`
|
|
598
671
|
instances if `many` is `True`.
|
|
@@ -719,16 +792,17 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
719
792
|
|
|
720
793
|
def loads(
|
|
721
794
|
self,
|
|
722
|
-
json_data: str,
|
|
795
|
+
json_data: str | bytes | bytearray,
|
|
723
796
|
*,
|
|
724
797
|
many: bool | None = None,
|
|
725
798
|
partial: bool | types.StrSequenceOrSet | None = None,
|
|
726
799
|
unknown: str | None = None,
|
|
727
800
|
**kwargs,
|
|
728
801
|
):
|
|
729
|
-
"""Same as :meth:`load`, except it
|
|
802
|
+
"""Same as :meth:`load`, except it uses `marshmallow.Schema.Meta.render_module` to deserialize
|
|
803
|
+
the passed string before passing data to :meth:`load`.
|
|
730
804
|
|
|
731
|
-
:param json_data: A
|
|
805
|
+
:param json_data: A string of the data to deserialize.
|
|
732
806
|
:param many: Whether to deserialize `obj` as a collection. If `None`, the
|
|
733
807
|
value for `self.many` is used.
|
|
734
808
|
:param partial: Whether to ignore missing fields and not require
|
|
@@ -751,15 +825,15 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
751
825
|
|
|
752
826
|
def _run_validator(
|
|
753
827
|
self,
|
|
754
|
-
validator_func,
|
|
828
|
+
validator_func: types.SchemaValidator,
|
|
755
829
|
output,
|
|
756
830
|
*,
|
|
757
831
|
original_data,
|
|
758
|
-
error_store,
|
|
759
|
-
many,
|
|
760
|
-
partial,
|
|
761
|
-
pass_original,
|
|
762
|
-
index=None,
|
|
832
|
+
error_store: ErrorStore,
|
|
833
|
+
many: bool,
|
|
834
|
+
partial: bool | types.StrSequenceOrSet | None,
|
|
835
|
+
pass_original: bool,
|
|
836
|
+
index: int | None = None,
|
|
763
837
|
):
|
|
764
838
|
try:
|
|
765
839
|
if pass_original: # Pass original, raw data (before unmarshalling)
|
|
@@ -767,7 +841,26 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
767
841
|
else:
|
|
768
842
|
validator_func(output, partial=partial, many=many)
|
|
769
843
|
except ValidationError as err:
|
|
770
|
-
|
|
844
|
+
field_name = err.field_name
|
|
845
|
+
data_key: str
|
|
846
|
+
if field_name == SCHEMA:
|
|
847
|
+
data_key = SCHEMA
|
|
848
|
+
else:
|
|
849
|
+
field_obj: Field | None = None
|
|
850
|
+
try:
|
|
851
|
+
field_obj = self.fields[field_name]
|
|
852
|
+
except KeyError:
|
|
853
|
+
if field_name in self.declared_fields:
|
|
854
|
+
field_obj = self.declared_fields[field_name]
|
|
855
|
+
if field_obj:
|
|
856
|
+
data_key = (
|
|
857
|
+
field_obj.data_key
|
|
858
|
+
if field_obj.data_key is not None
|
|
859
|
+
else field_name
|
|
860
|
+
)
|
|
861
|
+
else:
|
|
862
|
+
data_key = field_name
|
|
863
|
+
error_store.store_error(err.messages, data_key, index=index)
|
|
771
864
|
|
|
772
865
|
def validate(
|
|
773
866
|
self,
|
|
@@ -1015,26 +1108,26 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
1015
1108
|
self.dump_fields = dump_fields
|
|
1016
1109
|
self.load_fields = load_fields
|
|
1017
1110
|
|
|
1018
|
-
def on_bind_field(self, field_name: str, field_obj:
|
|
1111
|
+
def on_bind_field(self, field_name: str, field_obj: Field) -> None:
|
|
1019
1112
|
"""Hook to modify a field when it is bound to the `Schema <marshmallow.Schema>`.
|
|
1020
1113
|
|
|
1021
1114
|
No-op by default.
|
|
1022
1115
|
"""
|
|
1023
|
-
return
|
|
1116
|
+
return
|
|
1024
1117
|
|
|
1025
|
-
def _bind_field(self, field_name: str, field_obj:
|
|
1118
|
+
def _bind_field(self, field_name: str, field_obj: Field) -> None:
|
|
1026
1119
|
"""Bind field to the schema, setting any necessary attributes on the
|
|
1027
1120
|
field (e.g. parent and name).
|
|
1028
1121
|
|
|
1029
1122
|
Also set field load_only and dump_only values if field_name was
|
|
1030
|
-
specified in
|
|
1123
|
+
specified in `class Meta <marshmallow.Schema.Meta>`.
|
|
1031
1124
|
"""
|
|
1032
1125
|
if field_name in self.load_only:
|
|
1033
1126
|
field_obj.load_only = True
|
|
1034
1127
|
if field_name in self.dump_only:
|
|
1035
1128
|
field_obj.dump_only = True
|
|
1036
1129
|
try:
|
|
1037
|
-
field_obj._bind_to_schema(field_name, self)
|
|
1130
|
+
field_obj._bind_to_schema(field_name, self) # noqa: SLF001
|
|
1038
1131
|
except TypeError as error:
|
|
1039
1132
|
# Field declared as a class, not an instance. Ignore type checking because
|
|
1040
1133
|
# we handle unsupported arg types, i.e. this is dead code from
|
|
@@ -1043,10 +1136,10 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
1043
1136
|
msg = (
|
|
1044
1137
|
f'Field for "{field_name}" must be declared as a '
|
|
1045
1138
|
"Field instance, not a class. "
|
|
1046
|
-
f'Did you mean "fields.{field_obj.__name__}()"?' # type: ignore
|
|
1139
|
+
f'Did you mean "fields.{field_obj.__name__}()"?' # type: ignore[attr-defined]
|
|
1047
1140
|
)
|
|
1048
1141
|
raise TypeError(msg) from error
|
|
1049
|
-
raise
|
|
1142
|
+
raise
|
|
1050
1143
|
self.on_bind_field(field_name, field_obj)
|
|
1051
1144
|
|
|
1052
1145
|
def _invoke_dump_processors(
|
|
@@ -1058,10 +1151,9 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
1058
1151
|
data = self._invoke_processors(
|
|
1059
1152
|
tag, pass_many=False, data=data, many=many, original_data=original_data
|
|
1060
1153
|
)
|
|
1061
|
-
|
|
1154
|
+
return self._invoke_processors(
|
|
1062
1155
|
tag, pass_many=True, data=data, many=many, original_data=original_data
|
|
1063
1156
|
)
|
|
1064
|
-
return data
|
|
1065
1157
|
|
|
1066
1158
|
def _invoke_load_processors(
|
|
1067
1159
|
self,
|
|
@@ -1082,7 +1174,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
1082
1174
|
original_data=original_data,
|
|
1083
1175
|
partial=partial,
|
|
1084
1176
|
)
|
|
1085
|
-
|
|
1177
|
+
return self._invoke_processors(
|
|
1086
1178
|
tag,
|
|
1087
1179
|
pass_many=False,
|
|
1088
1180
|
data=data,
|
|
@@ -1090,7 +1182,6 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
1090
1182
|
original_data=original_data,
|
|
1091
1183
|
partial=partial,
|
|
1092
1184
|
)
|
|
1093
|
-
return data
|
|
1094
1185
|
|
|
1095
1186
|
def _invoke_field_validators(self, *, error_store: ErrorStore, data, many: bool):
|
|
1096
1187
|
for attr_name, _, validator_kwargs in self._hooks[VALIDATES]:
|
|
@@ -1122,7 +1213,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
1122
1213
|
index=(idx if self.opts.index_errors else None),
|
|
1123
1214
|
)
|
|
1124
1215
|
if validated_value is missing:
|
|
1125
|
-
|
|
1216
|
+
item.pop(field_name, None)
|
|
1126
1217
|
else:
|
|
1127
1218
|
try:
|
|
1128
1219
|
value = data[field_obj.attribute or field_name]
|
|
@@ -1201,15 +1292,14 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
1201
1292
|
if pass_original:
|
|
1202
1293
|
data = [
|
|
1203
1294
|
processor(item, original, many=many, **kwargs)
|
|
1204
|
-
for item, original in
|
|
1295
|
+
for item, original in zip_longest(data, original_data)
|
|
1205
1296
|
]
|
|
1206
1297
|
else:
|
|
1207
1298
|
data = [processor(item, many=many, **kwargs) for item in data]
|
|
1299
|
+
elif pass_original:
|
|
1300
|
+
data = processor(data, original_data, many=many, **kwargs)
|
|
1208
1301
|
else:
|
|
1209
|
-
|
|
1210
|
-
data = processor(data, original_data, many=many, **kwargs)
|
|
1211
|
-
else:
|
|
1212
|
-
data = processor(data, many=many, **kwargs)
|
|
1302
|
+
data = processor(data, many=many, **kwargs)
|
|
1213
1303
|
return data
|
|
1214
1304
|
|
|
1215
1305
|
|
marshmallow/types.py
CHANGED
|
@@ -5,7 +5,36 @@
|
|
|
5
5
|
This module is provisional. Types may be modified, added, and removed between minor releases.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
8
10
|
import typing
|
|
9
11
|
|
|
12
|
+
#: A type that can be either a sequence of strings or a set of strings
|
|
10
13
|
StrSequenceOrSet = typing.Union[typing.Sequence[str], typing.AbstractSet[str]]
|
|
14
|
+
|
|
15
|
+
#: Type for validator functions
|
|
11
16
|
Validator = typing.Callable[[typing.Any], typing.Any]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SchemaValidator(typing.Protocol):
|
|
20
|
+
def __call__(
|
|
21
|
+
self,
|
|
22
|
+
output: typing.Any,
|
|
23
|
+
original_data: typing.Any = ...,
|
|
24
|
+
*,
|
|
25
|
+
partial: bool | StrSequenceOrSet | None = None,
|
|
26
|
+
many: bool = False,
|
|
27
|
+
) -> None: ...
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class RenderModule(typing.Protocol):
|
|
31
|
+
def dumps(
|
|
32
|
+
self, obj: typing.Any, *args: typing.Any, **kwargs: typing.Any
|
|
33
|
+
) -> str: ...
|
|
34
|
+
|
|
35
|
+
def loads(
|
|
36
|
+
self,
|
|
37
|
+
json_data: str | bytes | bytearray,
|
|
38
|
+
*args: typing.Any,
|
|
39
|
+
**kwargs: typing.Any,
|
|
40
|
+
) -> typing.Any: ...
|