marshmallow 3.23.2__py3-none-any.whl → 3.24.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/base.py +0 -32
- marshmallow/class_registry.py +10 -0
- marshmallow/fields.py +129 -109
- marshmallow/schema.py +29 -35
- marshmallow/utils.py +1 -1
- marshmallow/validate.py +17 -9
- marshmallow/warnings.py +9 -1
- {marshmallow-3.23.2.dist-info → marshmallow-3.24.0.dist-info}/METADATA +1 -2
- marshmallow-3.24.0.dist-info/RECORD +18 -0
- marshmallow-3.23.2.dist-info/RECORD +0 -18
- {marshmallow-3.23.2.dist-info → marshmallow-3.24.0.dist-info}/LICENSE +0 -0
- {marshmallow-3.23.2.dist-info → marshmallow-3.24.0.dist-info}/WHEEL +0 -0
marshmallow/base.py
CHANGED
|
@@ -16,10 +16,6 @@ from abc import ABC, abstractmethod
|
|
|
16
16
|
class FieldABC(ABC):
|
|
17
17
|
"""Abstract base class from which all Field classes inherit."""
|
|
18
18
|
|
|
19
|
-
parent = None
|
|
20
|
-
name = None
|
|
21
|
-
root = None
|
|
22
|
-
|
|
23
19
|
@abstractmethod
|
|
24
20
|
def serialize(self, attr, obj, accessor=None):
|
|
25
21
|
pass
|
|
@@ -35,31 +31,3 @@ class FieldABC(ABC):
|
|
|
35
31
|
@abstractmethod
|
|
36
32
|
def _deserialize(self, value, attr, data, **kwargs):
|
|
37
33
|
pass
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class SchemaABC(ABC):
|
|
41
|
-
"""Abstract base class from which all Schemas inherit."""
|
|
42
|
-
|
|
43
|
-
@abstractmethod
|
|
44
|
-
def dump(self, obj, *, many: bool | None = None):
|
|
45
|
-
pass
|
|
46
|
-
|
|
47
|
-
@abstractmethod
|
|
48
|
-
def dumps(self, obj, *, many: bool | None = None):
|
|
49
|
-
pass
|
|
50
|
-
|
|
51
|
-
@abstractmethod
|
|
52
|
-
def load(self, data, *, many: bool | None = None, partial=None, unknown=None):
|
|
53
|
-
pass
|
|
54
|
-
|
|
55
|
-
@abstractmethod
|
|
56
|
-
def loads(
|
|
57
|
-
self,
|
|
58
|
-
json_data,
|
|
59
|
-
*,
|
|
60
|
-
many: bool | None = None,
|
|
61
|
-
partial=None,
|
|
62
|
-
unknown=None,
|
|
63
|
-
**kwargs,
|
|
64
|
-
):
|
|
65
|
-
pass
|
marshmallow/class_registry.py
CHANGED
|
@@ -69,6 +69,16 @@ def register(classname: str, cls: SchemaType) -> None:
|
|
|
69
69
|
return None
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
@typing.overload
|
|
73
|
+
def get_class(classname: str, all: typing.Literal[False]) -> SchemaType: ...
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@typing.overload
|
|
77
|
+
def get_class(
|
|
78
|
+
classname: str, all: typing.Literal[True]
|
|
79
|
+
) -> list[SchemaType] | SchemaType: ...
|
|
80
|
+
|
|
81
|
+
|
|
72
82
|
def get_class(classname: str, all: bool = False) -> list[SchemaType] | SchemaType:
|
|
73
83
|
"""Retrieve a class from the registry.
|
|
74
84
|
|
marshmallow/fields.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
"""Field classes for various types of data."""
|
|
2
|
-
|
|
3
1
|
from __future__ import annotations
|
|
4
2
|
|
|
5
3
|
import collections
|
|
@@ -16,7 +14,7 @@ from collections.abc import Mapping as _Mapping
|
|
|
16
14
|
from enum import Enum as EnumType
|
|
17
15
|
|
|
18
16
|
from marshmallow import class_registry, types, utils, validate
|
|
19
|
-
from marshmallow.base import FieldABC
|
|
17
|
+
from marshmallow.base import FieldABC
|
|
20
18
|
from marshmallow.exceptions import (
|
|
21
19
|
FieldInstanceResolutionError,
|
|
22
20
|
StringNotCollectionError,
|
|
@@ -31,10 +29,13 @@ from marshmallow.utils import (
|
|
|
31
29
|
missing as missing_,
|
|
32
30
|
)
|
|
33
31
|
from marshmallow.validate import And, Length
|
|
34
|
-
from marshmallow.warnings import
|
|
32
|
+
from marshmallow.warnings import (
|
|
33
|
+
ChangedInMarshmallow4Warning,
|
|
34
|
+
RemovedInMarshmallow4Warning,
|
|
35
|
+
)
|
|
35
36
|
|
|
36
37
|
if typing.TYPE_CHECKING:
|
|
37
|
-
from marshmallow.schema import SchemaMeta
|
|
38
|
+
from marshmallow.schema import Schema, SchemaMeta
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
__all__ = [
|
|
@@ -77,14 +78,11 @@ __all__ = [
|
|
|
77
78
|
"Pluck",
|
|
78
79
|
]
|
|
79
80
|
|
|
80
|
-
_T = typing.TypeVar("_T")
|
|
81
|
-
|
|
82
81
|
|
|
83
82
|
class Field(FieldABC):
|
|
84
83
|
"""Basic field from which other fields should extend. It applies no
|
|
85
84
|
formatting by default, and should only be used in cases where
|
|
86
85
|
data does not need to be formatted before being serialized or deserialized.
|
|
87
|
-
On error, the name of the field will be returned.
|
|
88
86
|
|
|
89
87
|
:param dump_default: If set, this value will be used during serialization if the
|
|
90
88
|
input value is missing. If not set, the field will be excluded from the
|
|
@@ -108,8 +106,9 @@ class Field(FieldABC):
|
|
|
108
106
|
:param required: Raise a :exc:`ValidationError` if the field value
|
|
109
107
|
is not supplied during deserialization.
|
|
110
108
|
:param allow_none: Set this to `True` if `None` should be considered a valid value during
|
|
111
|
-
validation/deserialization. If
|
|
112
|
-
|
|
109
|
+
validation/deserialization. If set to `False` (the default), `None` is considered invalid input.
|
|
110
|
+
If ``load_default`` is explicitly set to `None` and ``allow_none`` is unset,
|
|
111
|
+
`allow_none` is implicitly set to ``True``.
|
|
113
112
|
:param load_only: If `True` skip this field during serialization, otherwise
|
|
114
113
|
its value will be present in the serialized data.
|
|
115
114
|
:param dump_only: If `True` skip this field during deserialization, otherwise
|
|
@@ -118,28 +117,12 @@ class Field(FieldABC):
|
|
|
118
117
|
:param dict error_messages: Overrides for `Field.default_error_messages`.
|
|
119
118
|
:param metadata: Extra information to be stored as field metadata.
|
|
120
119
|
|
|
121
|
-
.. versionchanged:: 2.0.0
|
|
122
|
-
Removed `error` parameter. Use ``error_messages`` instead.
|
|
123
|
-
|
|
124
|
-
.. versionchanged:: 2.0.0
|
|
125
|
-
Added `allow_none` parameter, which makes validation/deserialization of `None`
|
|
126
|
-
consistent across fields.
|
|
127
|
-
|
|
128
|
-
.. versionchanged:: 2.0.0
|
|
129
|
-
Added `load_only` and `dump_only` parameters, which allow field skipping
|
|
130
|
-
during the (de)serialization process.
|
|
131
|
-
|
|
132
|
-
.. versionchanged:: 2.0.0
|
|
133
|
-
Added `missing` parameter, which indicates the value for a field if the field
|
|
134
|
-
is not found during deserialization.
|
|
135
|
-
|
|
136
|
-
.. versionchanged:: 2.0.0
|
|
137
|
-
``default`` value is only used if explicitly set. Otherwise, missing values
|
|
138
|
-
inputs are excluded from serialized output.
|
|
139
|
-
|
|
140
120
|
.. versionchanged:: 3.0.0b8
|
|
141
121
|
Add ``data_key`` parameter for the specifying the key in the input and
|
|
142
122
|
output data. This parameter replaced both ``load_from`` and ``dump_to``.
|
|
123
|
+
|
|
124
|
+
.. versionchanged:: 3.13.0
|
|
125
|
+
Replace ``missing`` and ``default`` parameters with ``load_default`` and ``dump_default``.
|
|
143
126
|
"""
|
|
144
127
|
|
|
145
128
|
# Some fields, such as Method fields and Function fields, are not expected
|
|
@@ -150,12 +133,22 @@ class Field(FieldABC):
|
|
|
150
133
|
#: Default error messages for various kinds of errors. The keys in this dictionary
|
|
151
134
|
#: are passed to `Field.make_error`. The values are error messages passed to
|
|
152
135
|
#: :exc:`marshmallow.exceptions.ValidationError`.
|
|
153
|
-
default_error_messages = {
|
|
136
|
+
default_error_messages: dict[str, str] = {
|
|
154
137
|
"required": "Missing data for required field.",
|
|
155
138
|
"null": "Field may not be null.",
|
|
156
139
|
"validator_failed": "Invalid value.",
|
|
157
140
|
}
|
|
158
141
|
|
|
142
|
+
def __new__(cls, *args, **kwargs):
|
|
143
|
+
if cls is Field:
|
|
144
|
+
warnings.warn(
|
|
145
|
+
"`Field` should not be instantiated. Use `fields.Raw` or "
|
|
146
|
+
"another field subclass instead.",
|
|
147
|
+
ChangedInMarshmallow4Warning,
|
|
148
|
+
stacklevel=2,
|
|
149
|
+
)
|
|
150
|
+
return super().__new__(cls)
|
|
151
|
+
|
|
159
152
|
def __init__(
|
|
160
153
|
self,
|
|
161
154
|
*,
|
|
@@ -236,12 +229,16 @@ class Field(FieldABC):
|
|
|
236
229
|
)
|
|
237
230
|
|
|
238
231
|
# Collect default error message from self and parent classes
|
|
239
|
-
messages
|
|
232
|
+
messages: dict[str, str] = {}
|
|
240
233
|
for cls in reversed(self.__class__.__mro__):
|
|
241
234
|
messages.update(getattr(cls, "default_error_messages", {}))
|
|
242
235
|
messages.update(error_messages or {})
|
|
243
236
|
self.error_messages = messages
|
|
244
237
|
|
|
238
|
+
self.parent: Field | Schema | None = None
|
|
239
|
+
self.name: str | None = None
|
|
240
|
+
self.root: Schema | None = None
|
|
241
|
+
|
|
245
242
|
def __repr__(self) -> str:
|
|
246
243
|
return (
|
|
247
244
|
f"<fields.{self.__class__.__name__}(dump_default={self.dump_default!r}, "
|
|
@@ -255,7 +252,15 @@ class Field(FieldABC):
|
|
|
255
252
|
def __deepcopy__(self, memo):
|
|
256
253
|
return copy.copy(self)
|
|
257
254
|
|
|
258
|
-
def get_value(
|
|
255
|
+
def get_value(
|
|
256
|
+
self,
|
|
257
|
+
obj: typing.Any,
|
|
258
|
+
attr: str,
|
|
259
|
+
accessor: (
|
|
260
|
+
typing.Callable[[typing.Any, str, typing.Any], typing.Any] | None
|
|
261
|
+
) = None,
|
|
262
|
+
default: typing.Any = missing_,
|
|
263
|
+
):
|
|
259
264
|
"""Return the value for a given key from an object.
|
|
260
265
|
|
|
261
266
|
:param object obj: The object to get the value from.
|
|
@@ -267,14 +272,14 @@ class Field(FieldABC):
|
|
|
267
272
|
check_key = attr if self.attribute is None else self.attribute
|
|
268
273
|
return accessor_func(obj, check_key, default)
|
|
269
274
|
|
|
270
|
-
def _validate(self, value):
|
|
275
|
+
def _validate(self, value: typing.Any):
|
|
271
276
|
"""Perform validation on ``value``. Raise a :exc:`ValidationError` if validation
|
|
272
277
|
does not succeed.
|
|
273
278
|
"""
|
|
274
279
|
self._validate_all(value)
|
|
275
280
|
|
|
276
281
|
@property
|
|
277
|
-
def _validate_all(self):
|
|
282
|
+
def _validate_all(self) -> typing.Callable[[typing.Any], None]:
|
|
278
283
|
return And(*self.validators, error=self.error_messages["validator_failed"])
|
|
279
284
|
|
|
280
285
|
def make_error(self, key: str, **kwargs) -> ValidationError:
|
|
@@ -308,7 +313,7 @@ class Field(FieldABC):
|
|
|
308
313
|
)
|
|
309
314
|
raise self.make_error(key=key, **kwargs)
|
|
310
315
|
|
|
311
|
-
def _validate_missing(self, value):
|
|
316
|
+
def _validate_missing(self, value: typing.Any) -> None:
|
|
312
317
|
"""Validate missing values. Raise a :exc:`ValidationError` if
|
|
313
318
|
`value` should be considered missing.
|
|
314
319
|
"""
|
|
@@ -375,7 +380,7 @@ class Field(FieldABC):
|
|
|
375
380
|
|
|
376
381
|
# Methods for concrete classes to override.
|
|
377
382
|
|
|
378
|
-
def _bind_to_schema(self, field_name, schema):
|
|
383
|
+
def _bind_to_schema(self, field_name: str, schema: Schema | Field) -> None:
|
|
379
384
|
"""Update field with values from its parent schema. Called by
|
|
380
385
|
:meth:`Schema._bind_field <marshmallow.Schema._bind_field>`.
|
|
381
386
|
|
|
@@ -390,7 +395,7 @@ class Field(FieldABC):
|
|
|
390
395
|
|
|
391
396
|
def _serialize(
|
|
392
397
|
self, value: typing.Any, attr: str | None, obj: typing.Any, **kwargs
|
|
393
|
-
):
|
|
398
|
+
) -> typing.Any:
|
|
394
399
|
"""Serializes ``value`` to a basic Python datatype. Noop by default.
|
|
395
400
|
Concrete :class:`Field` classes should implement this method.
|
|
396
401
|
|
|
@@ -416,7 +421,7 @@ class Field(FieldABC):
|
|
|
416
421
|
attr: str | None,
|
|
417
422
|
data: typing.Mapping[str, typing.Any] | None,
|
|
418
423
|
**kwargs,
|
|
419
|
-
):
|
|
424
|
+
) -> typing.Any:
|
|
420
425
|
"""Deserialize value. Concrete :class:`Field` classes should implement this method.
|
|
421
426
|
|
|
422
427
|
:param value: The value to be deserialized.
|
|
@@ -426,9 +431,6 @@ class Field(FieldABC):
|
|
|
426
431
|
:raise ValidationError: In case of formatting or validation failure.
|
|
427
432
|
:return: The deserialized value.
|
|
428
433
|
|
|
429
|
-
.. versionchanged:: 2.0.0
|
|
430
|
-
Added ``attr`` and ``data`` parameters.
|
|
431
|
-
|
|
432
434
|
.. versionchanged:: 3.0.0
|
|
433
435
|
Added ``**kwargs`` to signature.
|
|
434
436
|
"""
|
|
@@ -437,9 +439,11 @@ class Field(FieldABC):
|
|
|
437
439
|
# Properties
|
|
438
440
|
|
|
439
441
|
@property
|
|
440
|
-
def context(self):
|
|
442
|
+
def context(self) -> dict | None:
|
|
441
443
|
"""The context dictionary for the parent :class:`Schema`."""
|
|
442
|
-
|
|
444
|
+
if self.parent:
|
|
445
|
+
return self.parent.context
|
|
446
|
+
return None
|
|
443
447
|
|
|
444
448
|
# the default and missing properties are provided for compatibility and
|
|
445
449
|
# emit warnings when they are accessed and set
|
|
@@ -540,13 +544,11 @@ class Nested(Field):
|
|
|
540
544
|
def __init__(
|
|
541
545
|
self,
|
|
542
546
|
nested: (
|
|
543
|
-
|
|
547
|
+
Schema
|
|
544
548
|
| SchemaMeta
|
|
545
549
|
| str
|
|
546
|
-
| dict[str, Field
|
|
547
|
-
| typing.Callable[
|
|
548
|
-
[], SchemaABC | SchemaMeta | dict[str, Field | type[Field]]
|
|
549
|
-
]
|
|
550
|
+
| dict[str, Field]
|
|
551
|
+
| typing.Callable[[], Schema | SchemaMeta | dict[str, Field]]
|
|
550
552
|
),
|
|
551
553
|
*,
|
|
552
554
|
dump_default: typing.Any = missing_,
|
|
@@ -576,11 +578,11 @@ class Nested(Field):
|
|
|
576
578
|
self.exclude = exclude
|
|
577
579
|
self.many = many
|
|
578
580
|
self.unknown = unknown
|
|
579
|
-
self._schema = None # Cached Schema instance
|
|
581
|
+
self._schema: Schema | None = None # Cached Schema instance
|
|
580
582
|
super().__init__(default=default, dump_default=dump_default, **kwargs)
|
|
581
583
|
|
|
582
584
|
@property
|
|
583
|
-
def schema(self):
|
|
585
|
+
def schema(self) -> Schema:
|
|
584
586
|
"""The nested Schema object.
|
|
585
587
|
|
|
586
588
|
.. versionchanged:: 1.0.0
|
|
@@ -592,18 +594,18 @@ class Nested(Field):
|
|
|
592
594
|
if callable(self.nested) and not isinstance(self.nested, type):
|
|
593
595
|
nested = self.nested()
|
|
594
596
|
else:
|
|
595
|
-
nested = self.nested
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
from marshmallow.schema import Schema
|
|
597
|
+
nested = typing.cast("Schema", self.nested)
|
|
598
|
+
# defer the import of `marshmallow.schema` to avoid circular imports
|
|
599
|
+
from marshmallow.schema import Schema
|
|
599
600
|
|
|
601
|
+
if isinstance(nested, dict):
|
|
600
602
|
nested = Schema.from_dict(nested)
|
|
601
603
|
|
|
602
|
-
if isinstance(nested,
|
|
604
|
+
if isinstance(nested, Schema):
|
|
603
605
|
self._schema = copy.copy(nested)
|
|
604
606
|
self._schema.context.update(context)
|
|
605
607
|
# Respect only and exclude passed from parent and re-initialize fields
|
|
606
|
-
set_class = self._schema.set_class
|
|
608
|
+
set_class = typing.cast(type[set], self._schema.set_class)
|
|
607
609
|
if self.only is not None:
|
|
608
610
|
if self._schema.only is not None:
|
|
609
611
|
original = self._schema.only
|
|
@@ -615,17 +617,17 @@ class Nested(Field):
|
|
|
615
617
|
self._schema.exclude = set_class(self.exclude) | set_class(original)
|
|
616
618
|
self._schema._init_fields()
|
|
617
619
|
else:
|
|
618
|
-
if isinstance(nested, type) and issubclass(nested,
|
|
619
|
-
schema_class = nested
|
|
620
|
+
if isinstance(nested, type) and issubclass(nested, Schema):
|
|
621
|
+
schema_class: type[Schema] = nested
|
|
620
622
|
elif not isinstance(nested, (str, bytes)):
|
|
621
623
|
raise ValueError(
|
|
622
624
|
"`Nested` fields must be passed a "
|
|
623
625
|
f"`Schema`, not {nested.__class__}."
|
|
624
626
|
)
|
|
625
627
|
elif nested == "self":
|
|
626
|
-
schema_class = self.root.__class__
|
|
628
|
+
schema_class = typing.cast(Schema, self.root).__class__
|
|
627
629
|
else:
|
|
628
|
-
schema_class = class_registry.get_class(nested)
|
|
630
|
+
schema_class = class_registry.get_class(nested, all=False)
|
|
629
631
|
self._schema = schema_class(
|
|
630
632
|
many=self.many,
|
|
631
633
|
only=self.only,
|
|
@@ -653,12 +655,14 @@ class Nested(Field):
|
|
|
653
655
|
many = schema.many or self.many
|
|
654
656
|
return schema.dump(nested_obj, many=many)
|
|
655
657
|
|
|
656
|
-
def _test_collection(self, value):
|
|
658
|
+
def _test_collection(self, value: typing.Any) -> None:
|
|
657
659
|
many = self.schema.many or self.many
|
|
658
660
|
if many and not utils.is_collection(value):
|
|
659
661
|
raise self.make_error("type", input=value, type=value.__class__.__name__)
|
|
660
662
|
|
|
661
|
-
def _load(
|
|
663
|
+
def _load(
|
|
664
|
+
self, value: typing.Any, partial: bool | types.StrSequenceOrSet | None = None
|
|
665
|
+
):
|
|
662
666
|
try:
|
|
663
667
|
valid_data = self.schema.load(value, unknown=self.unknown, partial=partial)
|
|
664
668
|
except ValidationError as error:
|
|
@@ -667,7 +671,14 @@ class Nested(Field):
|
|
|
667
671
|
) from error
|
|
668
672
|
return valid_data
|
|
669
673
|
|
|
670
|
-
def _deserialize(
|
|
674
|
+
def _deserialize(
|
|
675
|
+
self,
|
|
676
|
+
value: typing.Any,
|
|
677
|
+
attr: str | None,
|
|
678
|
+
data: typing.Mapping[str, typing.Any] | None = None,
|
|
679
|
+
partial: bool | types.StrSequenceOrSet | None = None,
|
|
680
|
+
**kwargs,
|
|
681
|
+
) -> typing.Any:
|
|
671
682
|
"""Same as :meth:`Field._deserialize` with additional ``partial`` argument.
|
|
672
683
|
|
|
673
684
|
:param bool|tuple partial: For nested schemas, the ``partial``
|
|
@@ -677,7 +688,7 @@ class Nested(Field):
|
|
|
677
688
|
Add ``partial`` parameter.
|
|
678
689
|
"""
|
|
679
690
|
self._test_collection(value)
|
|
680
|
-
return self._load(value,
|
|
691
|
+
return self._load(value, partial=partial)
|
|
681
692
|
|
|
682
693
|
|
|
683
694
|
class Pluck(Nested):
|
|
@@ -709,7 +720,7 @@ class Pluck(Nested):
|
|
|
709
720
|
|
|
710
721
|
def __init__(
|
|
711
722
|
self,
|
|
712
|
-
nested:
|
|
723
|
+
nested: Schema | SchemaMeta | str | typing.Callable[[], Schema],
|
|
713
724
|
field_name: str,
|
|
714
725
|
**kwargs,
|
|
715
726
|
):
|
|
@@ -717,7 +728,7 @@ class Pluck(Nested):
|
|
|
717
728
|
self.field_name = field_name
|
|
718
729
|
|
|
719
730
|
@property
|
|
720
|
-
def _field_data_key(self):
|
|
731
|
+
def _field_data_key(self) -> str:
|
|
721
732
|
only_field = self.schema.fields[self.field_name]
|
|
722
733
|
return only_field.data_key or self.field_name
|
|
723
734
|
|
|
@@ -735,7 +746,7 @@ class Pluck(Nested):
|
|
|
735
746
|
value = [{self._field_data_key: v} for v in value]
|
|
736
747
|
else:
|
|
737
748
|
value = {self._field_data_key: value}
|
|
738
|
-
return self._load(value,
|
|
749
|
+
return self._load(value, partial=partial)
|
|
739
750
|
|
|
740
751
|
|
|
741
752
|
class List(Field):
|
|
@@ -749,10 +760,6 @@ class List(Field):
|
|
|
749
760
|
:param cls_or_instance: A field class or instance.
|
|
750
761
|
:param kwargs: The same keyword arguments that :class:`Field` receives.
|
|
751
762
|
|
|
752
|
-
.. versionchanged:: 2.0.0
|
|
753
|
-
The ``allow_none`` parameter now applies to deserialization and
|
|
754
|
-
has the same semantics as the other fields.
|
|
755
|
-
|
|
756
763
|
.. versionchanged:: 3.0.0rc9
|
|
757
764
|
Does not serialize scalar values to single-item lists.
|
|
758
765
|
"""
|
|
@@ -773,7 +780,7 @@ class List(Field):
|
|
|
773
780
|
self.only = self.inner.only
|
|
774
781
|
self.exclude = self.inner.exclude
|
|
775
782
|
|
|
776
|
-
def _bind_to_schema(self, field_name, schema):
|
|
783
|
+
def _bind_to_schema(self, field_name: str, schema: Schema | Field) -> None:
|
|
777
784
|
super()._bind_to_schema(field_name, schema)
|
|
778
785
|
self.inner = copy.deepcopy(self.inner)
|
|
779
786
|
self.inner._bind_to_schema(field_name, self)
|
|
@@ -817,7 +824,7 @@ class Tuple(Field):
|
|
|
817
824
|
`typing.NamedTuple`, using a Schema within a Nested field for them is
|
|
818
825
|
more appropriate than using a `Tuple` field.
|
|
819
826
|
|
|
820
|
-
:param
|
|
827
|
+
:param tuple_fields: An iterable of field classes or
|
|
821
828
|
instances.
|
|
822
829
|
:param kwargs: The same keyword arguments that :class:`Field` receives.
|
|
823
830
|
|
|
@@ -827,7 +834,7 @@ class Tuple(Field):
|
|
|
827
834
|
#: Default error messages.
|
|
828
835
|
default_error_messages = {"invalid": "Not a valid tuple."}
|
|
829
836
|
|
|
830
|
-
def __init__(self, tuple_fields, *args, **kwargs):
|
|
837
|
+
def __init__(self, tuple_fields: typing.Iterable[Field], *args, **kwargs):
|
|
831
838
|
super().__init__(*args, **kwargs)
|
|
832
839
|
if not utils.is_collection(tuple_fields):
|
|
833
840
|
raise ValueError(
|
|
@@ -847,7 +854,7 @@ class Tuple(Field):
|
|
|
847
854
|
|
|
848
855
|
self.validate_length = Length(equal=len(self.tuple_fields))
|
|
849
856
|
|
|
850
|
-
def _bind_to_schema(self, field_name, schema):
|
|
857
|
+
def _bind_to_schema(self, field_name: str, schema: Schema | Field) -> None:
|
|
851
858
|
super()._bind_to_schema(field_name, schema)
|
|
852
859
|
new_tuple_fields = []
|
|
853
860
|
for field in self.tuple_fields:
|
|
@@ -937,14 +944,17 @@ class UUID(String):
|
|
|
937
944
|
return self._validated(value)
|
|
938
945
|
|
|
939
946
|
|
|
940
|
-
|
|
947
|
+
_NumType = typing.TypeVar("_NumType")
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
class Number(Field, typing.Generic[_NumType]):
|
|
941
951
|
"""Base class for number fields.
|
|
942
952
|
|
|
943
953
|
:param bool as_string: If `True`, format the serialized value as a string.
|
|
944
954
|
:param kwargs: The same keyword arguments that :class:`Field` receives.
|
|
945
955
|
"""
|
|
946
956
|
|
|
947
|
-
num_type = float
|
|
957
|
+
num_type: type = float
|
|
948
958
|
|
|
949
959
|
#: Default error messages.
|
|
950
960
|
default_error_messages = {
|
|
@@ -952,18 +962,25 @@ class Number(Field):
|
|
|
952
962
|
"too_large": "Number too large.",
|
|
953
963
|
}
|
|
954
964
|
|
|
965
|
+
def __new__(cls, *args, **kwargs):
|
|
966
|
+
if cls is Number:
|
|
967
|
+
warnings.warn(
|
|
968
|
+
"`Number` field should not be instantiated. Use `Integer`, `Float`, or `Decimal` instead.",
|
|
969
|
+
ChangedInMarshmallow4Warning,
|
|
970
|
+
stacklevel=2,
|
|
971
|
+
)
|
|
972
|
+
return super().__new__(cls)
|
|
973
|
+
|
|
955
974
|
def __init__(self, *, as_string: bool = False, **kwargs):
|
|
956
975
|
self.as_string = as_string
|
|
957
976
|
super().__init__(**kwargs)
|
|
958
977
|
|
|
959
|
-
def _format_num(self, value) ->
|
|
978
|
+
def _format_num(self, value) -> _NumType:
|
|
960
979
|
"""Return the number value for value, given this field's `num_type`."""
|
|
961
980
|
return self.num_type(value)
|
|
962
981
|
|
|
963
|
-
def _validated(self, value) ->
|
|
982
|
+
def _validated(self, value: typing.Any) -> _NumType:
|
|
964
983
|
"""Format the value or raise a :exc:`ValidationError` if an error occurs."""
|
|
965
|
-
if value is None:
|
|
966
|
-
return None
|
|
967
984
|
# (value is True or value is False) is ~5x faster than isinstance(value, bool)
|
|
968
985
|
if value is True or value is False:
|
|
969
986
|
raise self.make_error("invalid", input=value)
|
|
@@ -974,21 +991,21 @@ class Number(Field):
|
|
|
974
991
|
except OverflowError as error:
|
|
975
992
|
raise self.make_error("too_large", input=value) from error
|
|
976
993
|
|
|
977
|
-
def _to_string(self, value) -> str:
|
|
994
|
+
def _to_string(self, value: _NumType) -> str:
|
|
978
995
|
return str(value)
|
|
979
996
|
|
|
980
|
-
def _serialize(self, value, attr, obj, **kwargs) -> str |
|
|
997
|
+
def _serialize(self, value, attr, obj, **kwargs) -> str | _NumType | None:
|
|
981
998
|
"""Return a string if `self.as_string=True`, otherwise return this field's `num_type`."""
|
|
982
999
|
if value is None:
|
|
983
1000
|
return None
|
|
984
|
-
ret = self._format_num(value)
|
|
1001
|
+
ret: _NumType = self._format_num(value)
|
|
985
1002
|
return self._to_string(ret) if self.as_string else ret
|
|
986
1003
|
|
|
987
|
-
def _deserialize(self, value, attr, data, **kwargs) ->
|
|
1004
|
+
def _deserialize(self, value, attr, data, **kwargs) -> _NumType | None:
|
|
988
1005
|
return self._validated(value)
|
|
989
1006
|
|
|
990
1007
|
|
|
991
|
-
class Integer(Number):
|
|
1008
|
+
class Integer(Number[int]):
|
|
992
1009
|
"""An integer field.
|
|
993
1010
|
|
|
994
1011
|
:param strict: If `True`, only integer types are valid.
|
|
@@ -1006,13 +1023,13 @@ class Integer(Number):
|
|
|
1006
1023
|
super().__init__(**kwargs)
|
|
1007
1024
|
|
|
1008
1025
|
# override Number
|
|
1009
|
-
def _validated(self, value):
|
|
1026
|
+
def _validated(self, value: typing.Any) -> int:
|
|
1010
1027
|
if self.strict and not isinstance(value, numbers.Integral):
|
|
1011
1028
|
raise self.make_error("invalid", input=value)
|
|
1012
1029
|
return super()._validated(value)
|
|
1013
1030
|
|
|
1014
1031
|
|
|
1015
|
-
class Float(Number):
|
|
1032
|
+
class Float(Number[float]):
|
|
1016
1033
|
"""A double as an IEEE-754 double precision string.
|
|
1017
1034
|
|
|
1018
1035
|
:param bool allow_nan: If `True`, `NaN`, `Infinity` and `-Infinity` are allowed,
|
|
@@ -1032,7 +1049,7 @@ class Float(Number):
|
|
|
1032
1049
|
self.allow_nan = allow_nan
|
|
1033
1050
|
super().__init__(as_string=as_string, **kwargs)
|
|
1034
1051
|
|
|
1035
|
-
def _validated(self, value):
|
|
1052
|
+
def _validated(self, value: typing.Any) -> float:
|
|
1036
1053
|
num = super()._validated(value)
|
|
1037
1054
|
if self.allow_nan is False:
|
|
1038
1055
|
if math.isnan(num) or num == float("inf") or num == float("-inf"):
|
|
@@ -1040,7 +1057,7 @@ class Float(Number):
|
|
|
1040
1057
|
return num
|
|
1041
1058
|
|
|
1042
1059
|
|
|
1043
|
-
class Decimal(Number):
|
|
1060
|
+
class Decimal(Number[decimal.Decimal]):
|
|
1044
1061
|
"""A field that (de)serializes to the Python ``decimal.Decimal`` type.
|
|
1045
1062
|
It's safe to use when dealing with money values, percentages, ratios
|
|
1046
1063
|
or other numbers where precision is critical.
|
|
@@ -1111,7 +1128,7 @@ class Decimal(Number):
|
|
|
1111
1128
|
return num
|
|
1112
1129
|
|
|
1113
1130
|
# override Number
|
|
1114
|
-
def _validated(self, value):
|
|
1131
|
+
def _validated(self, value: typing.Any) -> decimal.Decimal:
|
|
1115
1132
|
try:
|
|
1116
1133
|
num = super()._validated(value)
|
|
1117
1134
|
except decimal.InvalidOperation as error:
|
|
@@ -1121,7 +1138,7 @@ class Decimal(Number):
|
|
|
1121
1138
|
return num
|
|
1122
1139
|
|
|
1123
1140
|
# override Number
|
|
1124
|
-
def _to_string(self, value):
|
|
1141
|
+
def _to_string(self, value: decimal.Decimal) -> str:
|
|
1125
1142
|
return format(value, "f")
|
|
1126
1143
|
|
|
1127
1144
|
|
|
@@ -1195,7 +1212,9 @@ class Boolean(Field):
|
|
|
1195
1212
|
if falsy is not None:
|
|
1196
1213
|
self.falsy = set(falsy)
|
|
1197
1214
|
|
|
1198
|
-
def _serialize(
|
|
1215
|
+
def _serialize(
|
|
1216
|
+
self, value: typing.Any, attr: str | None, obj: typing.Any, **kwargs
|
|
1217
|
+
):
|
|
1199
1218
|
if value is None:
|
|
1200
1219
|
return None
|
|
1201
1220
|
|
|
@@ -1238,23 +1257,23 @@ class DateTime(Field):
|
|
|
1238
1257
|
Add timestamp as a format.
|
|
1239
1258
|
"""
|
|
1240
1259
|
|
|
1241
|
-
SERIALIZATION_FUNCS = {
|
|
1260
|
+
SERIALIZATION_FUNCS: dict[str, typing.Callable[[typing.Any], str | float]] = {
|
|
1242
1261
|
"iso": utils.isoformat,
|
|
1243
1262
|
"iso8601": utils.isoformat,
|
|
1244
1263
|
"rfc": utils.rfcformat,
|
|
1245
1264
|
"rfc822": utils.rfcformat,
|
|
1246
1265
|
"timestamp": utils.timestamp,
|
|
1247
1266
|
"timestamp_ms": utils.timestamp_ms,
|
|
1248
|
-
}
|
|
1267
|
+
}
|
|
1249
1268
|
|
|
1250
|
-
DESERIALIZATION_FUNCS = {
|
|
1269
|
+
DESERIALIZATION_FUNCS: dict[str, typing.Callable[[str], typing.Any]] = {
|
|
1251
1270
|
"iso": utils.from_iso_datetime,
|
|
1252
1271
|
"iso8601": utils.from_iso_datetime,
|
|
1253
1272
|
"rfc": utils.from_rfc,
|
|
1254
1273
|
"rfc822": utils.from_rfc,
|
|
1255
1274
|
"timestamp": utils.from_timestamp,
|
|
1256
1275
|
"timestamp_ms": utils.from_timestamp_ms,
|
|
1257
|
-
}
|
|
1276
|
+
}
|
|
1258
1277
|
|
|
1259
1278
|
DEFAULT_FORMAT = "iso"
|
|
1260
1279
|
|
|
@@ -1464,9 +1483,6 @@ class TimeDelta(Field):
|
|
|
1464
1483
|
will always be truncated to microseconds.
|
|
1465
1484
|
For example, `1.12345` interpreted as microseconds will result in `timedelta(microseconds=1)`.
|
|
1466
1485
|
|
|
1467
|
-
.. versionchanged:: 2.0.0
|
|
1468
|
-
Always serializes to an integer value to avoid rounding errors.
|
|
1469
|
-
Add `precision` parameter.
|
|
1470
1486
|
.. versionchanged:: 3.17.0
|
|
1471
1487
|
Allow (de)serialization to `float` through use of a new `serialization_type` parameter.
|
|
1472
1488
|
`int` is the default to retain previous behaviour.
|
|
@@ -1562,6 +1578,15 @@ class Mapping(Field):
|
|
|
1562
1578
|
#: Default error messages.
|
|
1563
1579
|
default_error_messages = {"invalid": "Not a valid mapping type."}
|
|
1564
1580
|
|
|
1581
|
+
def __new__(cls, *args, **kwargs):
|
|
1582
|
+
if cls is Mapping:
|
|
1583
|
+
warnings.warn(
|
|
1584
|
+
"`Mapping` field should not be instantiated. Use `Dict` instead.",
|
|
1585
|
+
ChangedInMarshmallow4Warning,
|
|
1586
|
+
stacklevel=2,
|
|
1587
|
+
)
|
|
1588
|
+
return super().__new__(cls)
|
|
1589
|
+
|
|
1565
1590
|
def __init__(
|
|
1566
1591
|
self,
|
|
1567
1592
|
keys: Field | type[Field] | None = None,
|
|
@@ -1760,7 +1785,7 @@ class IP(Field):
|
|
|
1760
1785
|
|
|
1761
1786
|
default_error_messages = {"invalid_ip": "Not a valid IP address."}
|
|
1762
1787
|
|
|
1763
|
-
DESERIALIZATION_CLASS
|
|
1788
|
+
DESERIALIZATION_CLASS: type | None = None
|
|
1764
1789
|
|
|
1765
1790
|
def __init__(self, *args, exploded=False, **kwargs):
|
|
1766
1791
|
super().__init__(*args, **kwargs)
|
|
@@ -1824,7 +1849,7 @@ class IPInterface(Field):
|
|
|
1824
1849
|
|
|
1825
1850
|
default_error_messages = {"invalid_ip_interface": "Not a valid IP interface."}
|
|
1826
1851
|
|
|
1827
|
-
DESERIALIZATION_CLASS
|
|
1852
|
+
DESERIALIZATION_CLASS: type | None = None
|
|
1828
1853
|
|
|
1829
1854
|
def __init__(self, *args, exploded: bool = False, **kwargs):
|
|
1830
1855
|
super().__init__(*args, **kwargs)
|
|
@@ -1874,7 +1899,7 @@ class Enum(Field):
|
|
|
1874
1899
|
or Field class or instance to use to (de)serialize by value. Defaults to False.
|
|
1875
1900
|
|
|
1876
1901
|
If `by_value` is `False` (default), enum members are (de)serialized by symbol (name).
|
|
1877
|
-
If it is `True`, they are (de)serialized by value using :class:`
|
|
1902
|
+
If it is `True`, they are (de)serialized by value using :class:`Raw`.
|
|
1878
1903
|
If it is a field instance or class, they are (de)serialized by value using this field.
|
|
1879
1904
|
|
|
1880
1905
|
.. versionadded:: 3.18.0
|
|
@@ -1904,7 +1929,7 @@ class Enum(Field):
|
|
|
1904
1929
|
# Serialization by value
|
|
1905
1930
|
else:
|
|
1906
1931
|
if by_value is True:
|
|
1907
|
-
self.field =
|
|
1932
|
+
self.field = Raw()
|
|
1908
1933
|
else:
|
|
1909
1934
|
try:
|
|
1910
1935
|
self.field = resolve_field_instance(by_value)
|
|
@@ -1949,9 +1974,6 @@ class Method(Field):
|
|
|
1949
1974
|
a value The method must take a single argument ``value``, which is the
|
|
1950
1975
|
value to deserialize.
|
|
1951
1976
|
|
|
1952
|
-
.. versionchanged:: 2.0.0
|
|
1953
|
-
Removed optional ``context`` parameter on methods. Use ``self.context`` instead.
|
|
1954
|
-
|
|
1955
1977
|
.. versionchanged:: 2.3.0
|
|
1956
1978
|
Deprecated ``method_name`` parameter in favor of ``serialize`` and allow
|
|
1957
1979
|
``serialize`` to not be passed at all.
|
|
@@ -2070,8 +2092,6 @@ class Constant(Field):
|
|
|
2070
2092
|
``dump_only=True`` or ``load_only=True`` respectively.
|
|
2071
2093
|
|
|
2072
2094
|
:param constant: The constant to return for the field attribute.
|
|
2073
|
-
|
|
2074
|
-
.. versionadded:: 2.0.0
|
|
2075
2095
|
"""
|
|
2076
2096
|
|
|
2077
2097
|
_CHECK_ATTRIBUTE = False
|
marshmallow/schema.py
CHANGED
|
@@ -154,7 +154,7 @@ class SchemaMeta(ABCMeta):
|
|
|
154
154
|
"""
|
|
155
155
|
mro = inspect.getmro(cls)
|
|
156
156
|
|
|
157
|
-
hooks
|
|
157
|
+
hooks: dict[str, list[tuple[str, bool, dict]]] = defaultdict(list)
|
|
158
158
|
|
|
159
159
|
for attr_name in dir(cls):
|
|
160
160
|
# Need to look up the actual descriptor, not whatever might be
|
|
@@ -174,7 +174,9 @@ class SchemaMeta(ABCMeta):
|
|
|
174
174
|
continue
|
|
175
175
|
|
|
176
176
|
try:
|
|
177
|
-
hook_config
|
|
177
|
+
hook_config: dict[str, list[tuple[bool, dict]]] = (
|
|
178
|
+
attr.__marshmallow_hook__
|
|
179
|
+
)
|
|
178
180
|
except AttributeError:
|
|
179
181
|
pass
|
|
180
182
|
else:
|
|
@@ -229,7 +231,7 @@ class SchemaOpts:
|
|
|
229
231
|
self.many = getattr(meta, "many", False)
|
|
230
232
|
|
|
231
233
|
|
|
232
|
-
class Schema(
|
|
234
|
+
class Schema(metaclass=SchemaMeta):
|
|
233
235
|
"""Base schema class with which to define custom schemas.
|
|
234
236
|
|
|
235
237
|
Example usage:
|
|
@@ -280,16 +282,9 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
280
282
|
|
|
281
283
|
.. versionchanged:: 3.0.0
|
|
282
284
|
`prefix` parameter removed.
|
|
283
|
-
|
|
284
|
-
.. versionchanged:: 2.0.0
|
|
285
|
-
`__validators__`, `__preprocessors__`, and `__data_handlers__` are removed in favor of
|
|
286
|
-
`marshmallow.decorators.validates_schema`,
|
|
287
|
-
`marshmallow.decorators.pre_load` and `marshmallow.decorators.post_dump`.
|
|
288
|
-
`__accessor__` and `__error_handler__` are deprecated. Implement the
|
|
289
|
-
`handle_error` and `get_attribute` methods instead.
|
|
290
285
|
"""
|
|
291
286
|
|
|
292
|
-
TYPE_MAPPING = {
|
|
287
|
+
TYPE_MAPPING: dict[type, type[ma_fields.Field]] = {
|
|
293
288
|
str: ma_fields.String,
|
|
294
289
|
bytes: ma_fields.String,
|
|
295
290
|
dt.datetime: ma_fields.DateTime,
|
|
@@ -304,23 +299,23 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
304
299
|
dt.date: ma_fields.Date,
|
|
305
300
|
dt.timedelta: ma_fields.TimeDelta,
|
|
306
301
|
decimal.Decimal: ma_fields.Decimal,
|
|
307
|
-
}
|
|
302
|
+
}
|
|
308
303
|
#: Overrides for default schema-level error messages
|
|
309
|
-
error_messages
|
|
304
|
+
error_messages: dict[str, str] = {}
|
|
310
305
|
|
|
311
|
-
_default_error_messages = {
|
|
306
|
+
_default_error_messages: dict[str, str] = {
|
|
312
307
|
"type": "Invalid input type.",
|
|
313
308
|
"unknown": "Unknown field.",
|
|
314
|
-
}
|
|
309
|
+
}
|
|
315
310
|
|
|
316
|
-
OPTIONS_CLASS = SchemaOpts
|
|
311
|
+
OPTIONS_CLASS: type = SchemaOpts
|
|
317
312
|
|
|
318
313
|
set_class = OrderedSet
|
|
319
314
|
|
|
320
315
|
# These get set by SchemaMeta
|
|
321
|
-
opts
|
|
322
|
-
_declared_fields
|
|
323
|
-
_hooks
|
|
316
|
+
opts: SchemaOpts
|
|
317
|
+
_declared_fields: dict[str, ma_fields.Field] = {}
|
|
318
|
+
_hooks: dict[str, list[tuple[str, bool, dict]]] = {}
|
|
324
319
|
|
|
325
320
|
class Meta:
|
|
326
321
|
"""Options object for a Schema.
|
|
@@ -395,12 +390,19 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
395
390
|
if unknown is None
|
|
396
391
|
else validate_unknown_parameter_value(unknown)
|
|
397
392
|
)
|
|
393
|
+
if context:
|
|
394
|
+
warnings.warn(
|
|
395
|
+
"The `context` parameter is deprecated and will be removed in marshmallow 4.0. "
|
|
396
|
+
"Use `contextvars.ContextVar` to pass context instead.",
|
|
397
|
+
RemovedInMarshmallow4Warning,
|
|
398
|
+
stacklevel=2,
|
|
399
|
+
)
|
|
398
400
|
self.context = context or {}
|
|
399
401
|
self._normalize_nested_options()
|
|
400
402
|
#: Dictionary mapping field_names -> :class:`Field` objects
|
|
401
|
-
self.fields
|
|
402
|
-
self.load_fields
|
|
403
|
-
self.dump_fields
|
|
403
|
+
self.fields: dict[str, ma_fields.Field] = {}
|
|
404
|
+
self.load_fields: dict[str, ma_fields.Field] = {}
|
|
405
|
+
self.dump_fields: dict[str, ma_fields.Field] = {}
|
|
404
406
|
self._init_fields()
|
|
405
407
|
messages = {}
|
|
406
408
|
messages.update(self._default_error_messages)
|
|
@@ -422,7 +424,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
422
424
|
@classmethod
|
|
423
425
|
def from_dict(
|
|
424
426
|
cls,
|
|
425
|
-
fields: dict[str, ma_fields.Field
|
|
427
|
+
fields: dict[str, ma_fields.Field],
|
|
426
428
|
*,
|
|
427
429
|
name: str = "GeneratedSchema",
|
|
428
430
|
) -> type[Schema]:
|
|
@@ -444,11 +446,10 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
444
446
|
|
|
445
447
|
.. versionadded:: 3.0.0
|
|
446
448
|
"""
|
|
447
|
-
|
|
448
|
-
attrs["Meta"] = type(
|
|
449
|
+
Meta = type(
|
|
449
450
|
"GeneratedMeta", (getattr(cls, "Meta", object),), {"register": False}
|
|
450
451
|
)
|
|
451
|
-
schema_cls = type(name, (cls,),
|
|
452
|
+
schema_cls = type(name, (cls,), {**fields.copy(), "Meta": Meta})
|
|
452
453
|
return schema_cls
|
|
453
454
|
|
|
454
455
|
##### Override-able methods #####
|
|
@@ -463,8 +464,6 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
463
464
|
:param many: Value of ``many`` on dump or load.
|
|
464
465
|
:param partial: Value of ``partial`` on load.
|
|
465
466
|
|
|
466
|
-
.. versionadded:: 2.0.0
|
|
467
|
-
|
|
468
467
|
.. versionchanged:: 3.0.0rc9
|
|
469
468
|
Receives `many` and `partial` (on deserialization) as keyword arguments.
|
|
470
469
|
"""
|
|
@@ -473,8 +472,6 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
473
472
|
def get_attribute(self, obj: typing.Any, attr: str, default: typing.Any):
|
|
474
473
|
"""Defines how to pull values from an object to serialize.
|
|
475
474
|
|
|
476
|
-
.. versionadded:: 2.0.0
|
|
477
|
-
|
|
478
475
|
.. versionchanged:: 3.0.0a1
|
|
479
476
|
Changed position of ``obj`` and ``attr``.
|
|
480
477
|
"""
|
|
@@ -508,9 +505,6 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
508
505
|
:param obj: The object(s) to serialize.
|
|
509
506
|
:param bool many: `True` if ``data`` should be serialized as a collection.
|
|
510
507
|
:return: A dictionary of the serialized data
|
|
511
|
-
|
|
512
|
-
.. versionchanged:: 1.0.0
|
|
513
|
-
Renamed from ``marshal``.
|
|
514
508
|
"""
|
|
515
509
|
if many and obj is not None:
|
|
516
510
|
return [self._serialize(d, many=False) for d in obj]
|
|
@@ -836,7 +830,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
836
830
|
:return: Deserialized data
|
|
837
831
|
"""
|
|
838
832
|
error_store = ErrorStore()
|
|
839
|
-
errors
|
|
833
|
+
errors: dict[str, list[str]] = {}
|
|
840
834
|
many = self.many if many is None else bool(many)
|
|
841
835
|
unknown = (
|
|
842
836
|
self.unknown
|
|
@@ -853,7 +847,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
|
|
|
853
847
|
)
|
|
854
848
|
except ValidationError as err:
|
|
855
849
|
errors = err.normalized_messages()
|
|
856
|
-
result
|
|
850
|
+
result: list | dict | None = None
|
|
857
851
|
else:
|
|
858
852
|
processed_data = data
|
|
859
853
|
if not errors:
|
marshmallow/utils.py
CHANGED
|
@@ -138,7 +138,7 @@ def get_fixed_timezone(offset: int | float | dt.timedelta) -> dt.timezone:
|
|
|
138
138
|
if isinstance(offset, dt.timedelta):
|
|
139
139
|
offset = offset.total_seconds() // 60
|
|
140
140
|
sign = "-" if offset < 0 else "+"
|
|
141
|
-
hhmm = "
|
|
141
|
+
hhmm = "{:02d}{:02d}".format(*divmod(abs(offset), 60))
|
|
142
142
|
name = sign + hhmm
|
|
143
143
|
return dt.timezone(dt.timedelta(minutes=offset), name)
|
|
144
144
|
|
marshmallow/validate.py
CHANGED
|
@@ -4,12 +4,14 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
6
|
import typing
|
|
7
|
+
import warnings
|
|
7
8
|
from abc import ABC, abstractmethod
|
|
8
9
|
from itertools import zip_longest
|
|
9
10
|
from operator import attrgetter
|
|
10
11
|
|
|
11
12
|
from marshmallow import types
|
|
12
13
|
from marshmallow.exceptions import ValidationError
|
|
14
|
+
from marshmallow.warnings import ChangedInMarshmallow4Warning
|
|
13
15
|
|
|
14
16
|
_T = typing.TypeVar("_T")
|
|
15
17
|
|
|
@@ -22,7 +24,7 @@ class Validator(ABC):
|
|
|
22
24
|
add a useful `__repr__` implementation for validators.
|
|
23
25
|
"""
|
|
24
26
|
|
|
25
|
-
error
|
|
27
|
+
error: str | None = None
|
|
26
28
|
|
|
27
29
|
def __repr__(self) -> str:
|
|
28
30
|
args = self._repr_args()
|
|
@@ -65,7 +67,7 @@ class And(Validator):
|
|
|
65
67
|
|
|
66
68
|
def __init__(self, *validators: types.Validator, error: str | None = None):
|
|
67
69
|
self.validators = tuple(validators)
|
|
68
|
-
self.error = error or self.default_error_message
|
|
70
|
+
self.error: str = error or self.default_error_message
|
|
69
71
|
|
|
70
72
|
def _repr_args(self) -> str:
|
|
71
73
|
return f"validators={self.validators!r}"
|
|
@@ -77,6 +79,12 @@ class And(Validator):
|
|
|
77
79
|
try:
|
|
78
80
|
r = validator(value)
|
|
79
81
|
if not isinstance(validator, Validator) and r is False:
|
|
82
|
+
warnings.warn(
|
|
83
|
+
"Returning `False` from a validator is deprecated. "
|
|
84
|
+
"Raise a `ValidationError` instead.",
|
|
85
|
+
ChangedInMarshmallow4Warning,
|
|
86
|
+
stacklevel=2,
|
|
87
|
+
)
|
|
80
88
|
raise ValidationError(self.error)
|
|
81
89
|
except ValidationError as err:
|
|
82
90
|
kwargs.update(err.kwargs)
|
|
@@ -191,7 +199,7 @@ class URL(Validator):
|
|
|
191
199
|
)
|
|
192
200
|
self.relative = relative
|
|
193
201
|
self.absolute = absolute
|
|
194
|
-
self.error = error or self.default_message
|
|
202
|
+
self.error: str = error or self.default_message
|
|
195
203
|
self.schemes = schemes or self.default_schemes
|
|
196
204
|
self.require_tld = require_tld
|
|
197
205
|
|
|
@@ -250,7 +258,7 @@ class Email(Validator):
|
|
|
250
258
|
default_message = "Not a valid email address."
|
|
251
259
|
|
|
252
260
|
def __init__(self, *, error: str | None = None):
|
|
253
|
-
self.error = error or self.default_message
|
|
261
|
+
self.error: str = error or self.default_message
|
|
254
262
|
|
|
255
263
|
def _format_error(self, value: str) -> str:
|
|
256
264
|
return self.error.format(input=value)
|
|
@@ -436,7 +444,7 @@ class Equal(Validator):
|
|
|
436
444
|
|
|
437
445
|
def __init__(self, comparable, *, error: str | None = None):
|
|
438
446
|
self.comparable = comparable
|
|
439
|
-
self.error = error or self.default_message
|
|
447
|
+
self.error: str = error or self.default_message
|
|
440
448
|
|
|
441
449
|
def _repr_args(self) -> str:
|
|
442
450
|
return f"comparable={self.comparable!r}"
|
|
@@ -477,7 +485,7 @@ class Regexp(Validator):
|
|
|
477
485
|
self.regex = (
|
|
478
486
|
re.compile(regex, flags) if isinstance(regex, (str, bytes)) else regex
|
|
479
487
|
)
|
|
480
|
-
self.error = error or self.default_message
|
|
488
|
+
self.error: str = error or self.default_message
|
|
481
489
|
|
|
482
490
|
def _repr_args(self) -> str:
|
|
483
491
|
return f"regex={self.regex!r}"
|
|
@@ -514,7 +522,7 @@ class Predicate(Validator):
|
|
|
514
522
|
|
|
515
523
|
def __init__(self, method: str, *, error: str | None = None, **kwargs):
|
|
516
524
|
self.method = method
|
|
517
|
-
self.error = error or self.default_message
|
|
525
|
+
self.error: str = error or self.default_message
|
|
518
526
|
self.kwargs = kwargs
|
|
519
527
|
|
|
520
528
|
def _repr_args(self) -> str:
|
|
@@ -545,7 +553,7 @@ class NoneOf(Validator):
|
|
|
545
553
|
def __init__(self, iterable: typing.Iterable, *, error: str | None = None):
|
|
546
554
|
self.iterable = iterable
|
|
547
555
|
self.values_text = ", ".join(str(each) for each in self.iterable)
|
|
548
|
-
self.error = error or self.default_message
|
|
556
|
+
self.error: str = error or self.default_message
|
|
549
557
|
|
|
550
558
|
def _repr_args(self) -> str:
|
|
551
559
|
return f"iterable={self.iterable!r}"
|
|
@@ -585,7 +593,7 @@ class OneOf(Validator):
|
|
|
585
593
|
self.choices_text = ", ".join(str(choice) for choice in self.choices)
|
|
586
594
|
self.labels = labels if labels is not None else []
|
|
587
595
|
self.labels_text = ", ".join(str(label) for label in self.labels)
|
|
588
|
-
self.error = error or self.default_message
|
|
596
|
+
self.error: str = error or self.default_message
|
|
589
597
|
|
|
590
598
|
def _repr_args(self) -> str:
|
|
591
599
|
return f"choices={self.choices!r}, labels={self.labels!r}"
|
marshmallow/warnings.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: marshmallow
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.24.0
|
|
4
4
|
Summary: A lightweight library for converting complex datatypes to and from native Python datatypes.
|
|
5
5
|
Author-email: Steven Loria <sloria1@gmail.com>
|
|
6
6
|
Maintainer-email: Steven Loria <sloria1@gmail.com>, Jérôme Lafréchoux <jerome@jolimont.fr>, Jared Deckard <jared@shademaps.com>
|
|
@@ -22,7 +22,6 @@ Requires-Dist: pre-commit>=3.5,<5.0 ; extra == "dev"
|
|
|
22
22
|
Requires-Dist: sphinx==8.1.3 ; extra == "docs"
|
|
23
23
|
Requires-Dist: sphinx-issues==5.0.0 ; extra == "docs"
|
|
24
24
|
Requires-Dist: alabaster==1.0.0 ; extra == "docs"
|
|
25
|
-
Requires-Dist: sphinx-version-warning==1.1.2 ; extra == "docs"
|
|
26
25
|
Requires-Dist: autodocsumm==0.2.14 ; extra == "docs"
|
|
27
26
|
Requires-Dist: pytest ; extra == "tests"
|
|
28
27
|
Requires-Dist: simplejson ; extra == "tests"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
marshmallow/__init__.py,sha256=C-zbaQJ9dlJLJxotIqTa5OOaD6ojGNRqW8moGrMsGr8,2387
|
|
2
|
+
marshmallow/base.py,sha256=ty-JhN__qqlJHaFVrFjMJTM5hQH6pG3xeo82Zu0sweY,719
|
|
3
|
+
marshmallow/class_registry.py,sha256=3k485ifxO4ilctvG3ICeuEx8CRuRmw8Ka_3V-Qjgq9o,3020
|
|
4
|
+
marshmallow/decorators.py,sha256=vmQFgBgdV0s1Fw8ySyZyQKvjKBTNf5JB3SCldEIl29o,8385
|
|
5
|
+
marshmallow/error_store.py,sha256=A7AxgLMw9ffSmaxRH4x3wcBWibx-DuGH4LwSDpVn50I,2223
|
|
6
|
+
marshmallow/exceptions.py,sha256=DuARdOcirCdJxmlp16V97hQKAXOokvdW12jXtYOlGyk,2326
|
|
7
|
+
marshmallow/fields.py,sha256=BSqVSDWFWt0T-N477YHYCeGzQHBpiuEtTZPJ5ULPsQ8,74073
|
|
8
|
+
marshmallow/orderedset.py,sha256=C2aAG6w1faIL1phinbAltbe3AUAnF5MN6n7fzESNDhI,2922
|
|
9
|
+
marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
marshmallow/schema.py,sha256=FIwUiCJfdz9EMNMj9w__UIuTx0Ik_quFL_QqSWuzJ2s,48445
|
|
11
|
+
marshmallow/types.py,sha256=RDS4IfasIehvH2rGWh9e4RTBtsMp-JFFtjApajV22zc,283
|
|
12
|
+
marshmallow/utils.py,sha256=-6jOnkuqFvb0DLeTVVifAPOklD_IdHC4LanhClCO0Hc,11897
|
|
13
|
+
marshmallow/validate.py,sha256=t5-4Qg_XlSQgcCujf_pimKIdZE0QT63jHyQP-miJNK0,24151
|
|
14
|
+
marshmallow/warnings.py,sha256=YHC0kQQBbTKCiA1FuwnbnXqrph7oKuU9BjTV4cxwnzE,192
|
|
15
|
+
marshmallow-3.24.0.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
|
|
16
|
+
marshmallow-3.24.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
|
|
17
|
+
marshmallow-3.24.0.dist-info/METADATA,sha256=bXLTvb7NO1z9CmSvghsh8UrrppbbrT2WUu64rRxNShE,7084
|
|
18
|
+
marshmallow-3.24.0.dist-info/RECORD,,
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
marshmallow/__init__.py,sha256=C-zbaQJ9dlJLJxotIqTa5OOaD6ojGNRqW8moGrMsGr8,2387
|
|
2
|
-
marshmallow/base.py,sha256=jZ68DZxxSCvRg2GTcxQcf2JjTxqEn-xFNrBEMK3CinU,1346
|
|
3
|
-
marshmallow/class_registry.py,sha256=kT_kv9KT0EUclIluLD5734ms9P0e65t5aky8y3lipFI,2804
|
|
4
|
-
marshmallow/decorators.py,sha256=vmQFgBgdV0s1Fw8ySyZyQKvjKBTNf5JB3SCldEIl29o,8385
|
|
5
|
-
marshmallow/error_store.py,sha256=A7AxgLMw9ffSmaxRH4x3wcBWibx-DuGH4LwSDpVn50I,2223
|
|
6
|
-
marshmallow/exceptions.py,sha256=DuARdOcirCdJxmlp16V97hQKAXOokvdW12jXtYOlGyk,2326
|
|
7
|
-
marshmallow/fields.py,sha256=MqrL2FplcXd6ZF5QhfAwawcDzy2NqcFFw2vGSd6pQOc,73253
|
|
8
|
-
marshmallow/orderedset.py,sha256=C2aAG6w1faIL1phinbAltbe3AUAnF5MN6n7fzESNDhI,2922
|
|
9
|
-
marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
marshmallow/schema.py,sha256=C4BsYkDBQbdgDA6w39oSqVlsDx4NfbkT_XtSIKcqxIo,48812
|
|
11
|
-
marshmallow/types.py,sha256=RDS4IfasIehvH2rGWh9e4RTBtsMp-JFFtjApajV22zc,283
|
|
12
|
-
marshmallow/utils.py,sha256=sWciesZ6tS08uX9Z9fzu2lbuut5eh8TKABU-TwgqSms,11886
|
|
13
|
-
marshmallow/validate.py,sha256=hS7fYC6byDHK9A7A4is0McDMZEzu6GkKke-7unLt2hE,23857
|
|
14
|
-
marshmallow/warnings.py,sha256=vHQu7AluuWqLhvlw5noXtWWbya13zDXY6JMaVSUzmDs,65
|
|
15
|
-
marshmallow-3.23.2.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
|
|
16
|
-
marshmallow-3.23.2.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
|
|
17
|
-
marshmallow-3.23.2.dist-info/METADATA,sha256=TlOpI469OQ6idWY74rjfgWR_xKzZPANdBN5wyB9J6bY,7147
|
|
18
|
-
marshmallow-3.23.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|