marshmallow 3.23.3__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 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
@@ -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
@@ -14,7 +14,7 @@ from collections.abc import Mapping as _Mapping
14
14
  from enum import Enum as EnumType
15
15
 
16
16
  from marshmallow import class_registry, types, utils, validate
17
- from marshmallow.base import FieldABC, SchemaABC
17
+ from marshmallow.base import FieldABC
18
18
  from marshmallow.exceptions import (
19
19
  FieldInstanceResolutionError,
20
20
  StringNotCollectionError,
@@ -29,10 +29,13 @@ from marshmallow.utils import (
29
29
  missing as missing_,
30
30
  )
31
31
  from marshmallow.validate import And, Length
32
- from marshmallow.warnings import RemovedInMarshmallow4Warning
32
+ from marshmallow.warnings import (
33
+ ChangedInMarshmallow4Warning,
34
+ RemovedInMarshmallow4Warning,
35
+ )
33
36
 
34
37
  if typing.TYPE_CHECKING:
35
- from marshmallow.schema import SchemaMeta
38
+ from marshmallow.schema import Schema, SchemaMeta
36
39
 
37
40
 
38
41
  __all__ = [
@@ -75,8 +78,6 @@ __all__ = [
75
78
  "Pluck",
76
79
  ]
77
80
 
78
- _T = typing.TypeVar("_T")
79
-
80
81
 
81
82
  class Field(FieldABC):
82
83
  """Basic field from which other fields should extend. It applies no
@@ -132,12 +133,22 @@ class Field(FieldABC):
132
133
  #: Default error messages for various kinds of errors. The keys in this dictionary
133
134
  #: are passed to `Field.make_error`. The values are error messages passed to
134
135
  #: :exc:`marshmallow.exceptions.ValidationError`.
135
- default_error_messages = {
136
+ default_error_messages: dict[str, str] = {
136
137
  "required": "Missing data for required field.",
137
138
  "null": "Field may not be null.",
138
139
  "validator_failed": "Invalid value.",
139
140
  }
140
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
+
141
152
  def __init__(
142
153
  self,
143
154
  *,
@@ -218,12 +229,16 @@ class Field(FieldABC):
218
229
  )
219
230
 
220
231
  # Collect default error message from self and parent classes
221
- messages = {} # type: dict[str, str]
232
+ messages: dict[str, str] = {}
222
233
  for cls in reversed(self.__class__.__mro__):
223
234
  messages.update(getattr(cls, "default_error_messages", {}))
224
235
  messages.update(error_messages or {})
225
236
  self.error_messages = messages
226
237
 
238
+ self.parent: Field | Schema | None = None
239
+ self.name: str | None = None
240
+ self.root: Schema | None = None
241
+
227
242
  def __repr__(self) -> str:
228
243
  return (
229
244
  f"<fields.{self.__class__.__name__}(dump_default={self.dump_default!r}, "
@@ -237,7 +252,15 @@ class Field(FieldABC):
237
252
  def __deepcopy__(self, memo):
238
253
  return copy.copy(self)
239
254
 
240
- def get_value(self, obj, attr, accessor=None, default=missing_):
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
+ ):
241
264
  """Return the value for a given key from an object.
242
265
 
243
266
  :param object obj: The object to get the value from.
@@ -249,14 +272,14 @@ class Field(FieldABC):
249
272
  check_key = attr if self.attribute is None else self.attribute
250
273
  return accessor_func(obj, check_key, default)
251
274
 
252
- def _validate(self, value):
275
+ def _validate(self, value: typing.Any):
253
276
  """Perform validation on ``value``. Raise a :exc:`ValidationError` if validation
254
277
  does not succeed.
255
278
  """
256
279
  self._validate_all(value)
257
280
 
258
281
  @property
259
- def _validate_all(self):
282
+ def _validate_all(self) -> typing.Callable[[typing.Any], None]:
260
283
  return And(*self.validators, error=self.error_messages["validator_failed"])
261
284
 
262
285
  def make_error(self, key: str, **kwargs) -> ValidationError:
@@ -290,7 +313,7 @@ class Field(FieldABC):
290
313
  )
291
314
  raise self.make_error(key=key, **kwargs)
292
315
 
293
- def _validate_missing(self, value):
316
+ def _validate_missing(self, value: typing.Any) -> None:
294
317
  """Validate missing values. Raise a :exc:`ValidationError` if
295
318
  `value` should be considered missing.
296
319
  """
@@ -357,7 +380,7 @@ class Field(FieldABC):
357
380
 
358
381
  # Methods for concrete classes to override.
359
382
 
360
- def _bind_to_schema(self, field_name, schema):
383
+ def _bind_to_schema(self, field_name: str, schema: Schema | Field) -> None:
361
384
  """Update field with values from its parent schema. Called by
362
385
  :meth:`Schema._bind_field <marshmallow.Schema._bind_field>`.
363
386
 
@@ -372,7 +395,7 @@ class Field(FieldABC):
372
395
 
373
396
  def _serialize(
374
397
  self, value: typing.Any, attr: str | None, obj: typing.Any, **kwargs
375
- ):
398
+ ) -> typing.Any:
376
399
  """Serializes ``value`` to a basic Python datatype. Noop by default.
377
400
  Concrete :class:`Field` classes should implement this method.
378
401
 
@@ -398,7 +421,7 @@ class Field(FieldABC):
398
421
  attr: str | None,
399
422
  data: typing.Mapping[str, typing.Any] | None,
400
423
  **kwargs,
401
- ):
424
+ ) -> typing.Any:
402
425
  """Deserialize value. Concrete :class:`Field` classes should implement this method.
403
426
 
404
427
  :param value: The value to be deserialized.
@@ -416,9 +439,11 @@ class Field(FieldABC):
416
439
  # Properties
417
440
 
418
441
  @property
419
- def context(self):
442
+ def context(self) -> dict | None:
420
443
  """The context dictionary for the parent :class:`Schema`."""
421
- return self.parent.context
444
+ if self.parent:
445
+ return self.parent.context
446
+ return None
422
447
 
423
448
  # the default and missing properties are provided for compatibility and
424
449
  # emit warnings when they are accessed and set
@@ -519,13 +544,11 @@ class Nested(Field):
519
544
  def __init__(
520
545
  self,
521
546
  nested: (
522
- SchemaABC
547
+ Schema
523
548
  | SchemaMeta
524
549
  | str
525
- | dict[str, Field | type[Field]]
526
- | typing.Callable[
527
- [], SchemaABC | SchemaMeta | dict[str, Field | type[Field]]
528
- ]
550
+ | dict[str, Field]
551
+ | typing.Callable[[], Schema | SchemaMeta | dict[str, Field]]
529
552
  ),
530
553
  *,
531
554
  dump_default: typing.Any = missing_,
@@ -555,11 +578,11 @@ class Nested(Field):
555
578
  self.exclude = exclude
556
579
  self.many = many
557
580
  self.unknown = unknown
558
- self._schema = None # Cached Schema instance
581
+ self._schema: Schema | None = None # Cached Schema instance
559
582
  super().__init__(default=default, dump_default=dump_default, **kwargs)
560
583
 
561
584
  @property
562
- def schema(self):
585
+ def schema(self) -> Schema:
563
586
  """The nested Schema object.
564
587
 
565
588
  .. versionchanged:: 1.0.0
@@ -571,18 +594,18 @@ class Nested(Field):
571
594
  if callable(self.nested) and not isinstance(self.nested, type):
572
595
  nested = self.nested()
573
596
  else:
574
- nested = self.nested
575
- if isinstance(nested, dict):
576
- # defer the import of `marshmallow.schema` to avoid circular imports
577
- 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
578
600
 
601
+ if isinstance(nested, dict):
579
602
  nested = Schema.from_dict(nested)
580
603
 
581
- if isinstance(nested, SchemaABC):
604
+ if isinstance(nested, Schema):
582
605
  self._schema = copy.copy(nested)
583
606
  self._schema.context.update(context)
584
607
  # Respect only and exclude passed from parent and re-initialize fields
585
- set_class = self._schema.set_class
608
+ set_class = typing.cast(type[set], self._schema.set_class)
586
609
  if self.only is not None:
587
610
  if self._schema.only is not None:
588
611
  original = self._schema.only
@@ -594,17 +617,17 @@ class Nested(Field):
594
617
  self._schema.exclude = set_class(self.exclude) | set_class(original)
595
618
  self._schema._init_fields()
596
619
  else:
597
- if isinstance(nested, type) and issubclass(nested, SchemaABC):
598
- schema_class = nested
620
+ if isinstance(nested, type) and issubclass(nested, Schema):
621
+ schema_class: type[Schema] = nested
599
622
  elif not isinstance(nested, (str, bytes)):
600
623
  raise ValueError(
601
624
  "`Nested` fields must be passed a "
602
625
  f"`Schema`, not {nested.__class__}."
603
626
  )
604
627
  elif nested == "self":
605
- schema_class = self.root.__class__
628
+ schema_class = typing.cast(Schema, self.root).__class__
606
629
  else:
607
- schema_class = class_registry.get_class(nested)
630
+ schema_class = class_registry.get_class(nested, all=False)
608
631
  self._schema = schema_class(
609
632
  many=self.many,
610
633
  only=self.only,
@@ -632,12 +655,14 @@ class Nested(Field):
632
655
  many = schema.many or self.many
633
656
  return schema.dump(nested_obj, many=many)
634
657
 
635
- def _test_collection(self, value):
658
+ def _test_collection(self, value: typing.Any) -> None:
636
659
  many = self.schema.many or self.many
637
660
  if many and not utils.is_collection(value):
638
661
  raise self.make_error("type", input=value, type=value.__class__.__name__)
639
662
 
640
- def _load(self, value, data, partial=None):
663
+ def _load(
664
+ self, value: typing.Any, partial: bool | types.StrSequenceOrSet | None = None
665
+ ):
641
666
  try:
642
667
  valid_data = self.schema.load(value, unknown=self.unknown, partial=partial)
643
668
  except ValidationError as error:
@@ -646,7 +671,14 @@ class Nested(Field):
646
671
  ) from error
647
672
  return valid_data
648
673
 
649
- def _deserialize(self, value, attr, data, partial=None, **kwargs):
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:
650
682
  """Same as :meth:`Field._deserialize` with additional ``partial`` argument.
651
683
 
652
684
  :param bool|tuple partial: For nested schemas, the ``partial``
@@ -656,7 +688,7 @@ class Nested(Field):
656
688
  Add ``partial`` parameter.
657
689
  """
658
690
  self._test_collection(value)
659
- return self._load(value, data, partial=partial)
691
+ return self._load(value, partial=partial)
660
692
 
661
693
 
662
694
  class Pluck(Nested):
@@ -688,7 +720,7 @@ class Pluck(Nested):
688
720
 
689
721
  def __init__(
690
722
  self,
691
- nested: SchemaABC | SchemaMeta | str | typing.Callable[[], SchemaABC],
723
+ nested: Schema | SchemaMeta | str | typing.Callable[[], Schema],
692
724
  field_name: str,
693
725
  **kwargs,
694
726
  ):
@@ -696,7 +728,7 @@ class Pluck(Nested):
696
728
  self.field_name = field_name
697
729
 
698
730
  @property
699
- def _field_data_key(self):
731
+ def _field_data_key(self) -> str:
700
732
  only_field = self.schema.fields[self.field_name]
701
733
  return only_field.data_key or self.field_name
702
734
 
@@ -714,7 +746,7 @@ class Pluck(Nested):
714
746
  value = [{self._field_data_key: v} for v in value]
715
747
  else:
716
748
  value = {self._field_data_key: value}
717
- return self._load(value, data, partial=partial)
749
+ return self._load(value, partial=partial)
718
750
 
719
751
 
720
752
  class List(Field):
@@ -748,7 +780,7 @@ class List(Field):
748
780
  self.only = self.inner.only
749
781
  self.exclude = self.inner.exclude
750
782
 
751
- def _bind_to_schema(self, field_name, schema):
783
+ def _bind_to_schema(self, field_name: str, schema: Schema | Field) -> None:
752
784
  super()._bind_to_schema(field_name, schema)
753
785
  self.inner = copy.deepcopy(self.inner)
754
786
  self.inner._bind_to_schema(field_name, self)
@@ -792,7 +824,7 @@ class Tuple(Field):
792
824
  `typing.NamedTuple`, using a Schema within a Nested field for them is
793
825
  more appropriate than using a `Tuple` field.
794
826
 
795
- :param Iterable[Field] tuple_fields: An iterable of field classes or
827
+ :param tuple_fields: An iterable of field classes or
796
828
  instances.
797
829
  :param kwargs: The same keyword arguments that :class:`Field` receives.
798
830
 
@@ -802,7 +834,7 @@ class Tuple(Field):
802
834
  #: Default error messages.
803
835
  default_error_messages = {"invalid": "Not a valid tuple."}
804
836
 
805
- def __init__(self, tuple_fields, *args, **kwargs):
837
+ def __init__(self, tuple_fields: typing.Iterable[Field], *args, **kwargs):
806
838
  super().__init__(*args, **kwargs)
807
839
  if not utils.is_collection(tuple_fields):
808
840
  raise ValueError(
@@ -822,7 +854,7 @@ class Tuple(Field):
822
854
 
823
855
  self.validate_length = Length(equal=len(self.tuple_fields))
824
856
 
825
- def _bind_to_schema(self, field_name, schema):
857
+ def _bind_to_schema(self, field_name: str, schema: Schema | Field) -> None:
826
858
  super()._bind_to_schema(field_name, schema)
827
859
  new_tuple_fields = []
828
860
  for field in self.tuple_fields:
@@ -912,14 +944,17 @@ class UUID(String):
912
944
  return self._validated(value)
913
945
 
914
946
 
915
- class Number(Field):
947
+ _NumType = typing.TypeVar("_NumType")
948
+
949
+
950
+ class Number(Field, typing.Generic[_NumType]):
916
951
  """Base class for number fields.
917
952
 
918
953
  :param bool as_string: If `True`, format the serialized value as a string.
919
954
  :param kwargs: The same keyword arguments that :class:`Field` receives.
920
955
  """
921
956
 
922
- num_type = float # type: typing.Type
957
+ num_type: type = float
923
958
 
924
959
  #: Default error messages.
925
960
  default_error_messages = {
@@ -927,18 +962,25 @@ class Number(Field):
927
962
  "too_large": "Number too large.",
928
963
  }
929
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
+
930
974
  def __init__(self, *, as_string: bool = False, **kwargs):
931
975
  self.as_string = as_string
932
976
  super().__init__(**kwargs)
933
977
 
934
- def _format_num(self, value) -> typing.Any:
978
+ def _format_num(self, value) -> _NumType:
935
979
  """Return the number value for value, given this field's `num_type`."""
936
980
  return self.num_type(value)
937
981
 
938
- def _validated(self, value) -> _T | None:
982
+ def _validated(self, value: typing.Any) -> _NumType:
939
983
  """Format the value or raise a :exc:`ValidationError` if an error occurs."""
940
- if value is None:
941
- return None
942
984
  # (value is True or value is False) is ~5x faster than isinstance(value, bool)
943
985
  if value is True or value is False:
944
986
  raise self.make_error("invalid", input=value)
@@ -949,21 +991,21 @@ class Number(Field):
949
991
  except OverflowError as error:
950
992
  raise self.make_error("too_large", input=value) from error
951
993
 
952
- def _to_string(self, value) -> str:
994
+ def _to_string(self, value: _NumType) -> str:
953
995
  return str(value)
954
996
 
955
- def _serialize(self, value, attr, obj, **kwargs) -> str | _T | None:
997
+ def _serialize(self, value, attr, obj, **kwargs) -> str | _NumType | None:
956
998
  """Return a string if `self.as_string=True`, otherwise return this field's `num_type`."""
957
999
  if value is None:
958
1000
  return None
959
- ret = self._format_num(value) # type: _T
1001
+ ret: _NumType = self._format_num(value)
960
1002
  return self._to_string(ret) if self.as_string else ret
961
1003
 
962
- def _deserialize(self, value, attr, data, **kwargs) -> _T | None:
1004
+ def _deserialize(self, value, attr, data, **kwargs) -> _NumType | None:
963
1005
  return self._validated(value)
964
1006
 
965
1007
 
966
- class Integer(Number):
1008
+ class Integer(Number[int]):
967
1009
  """An integer field.
968
1010
 
969
1011
  :param strict: If `True`, only integer types are valid.
@@ -981,13 +1023,13 @@ class Integer(Number):
981
1023
  super().__init__(**kwargs)
982
1024
 
983
1025
  # override Number
984
- def _validated(self, value):
1026
+ def _validated(self, value: typing.Any) -> int:
985
1027
  if self.strict and not isinstance(value, numbers.Integral):
986
1028
  raise self.make_error("invalid", input=value)
987
1029
  return super()._validated(value)
988
1030
 
989
1031
 
990
- class Float(Number):
1032
+ class Float(Number[float]):
991
1033
  """A double as an IEEE-754 double precision string.
992
1034
 
993
1035
  :param bool allow_nan: If `True`, `NaN`, `Infinity` and `-Infinity` are allowed,
@@ -1007,7 +1049,7 @@ class Float(Number):
1007
1049
  self.allow_nan = allow_nan
1008
1050
  super().__init__(as_string=as_string, **kwargs)
1009
1051
 
1010
- def _validated(self, value):
1052
+ def _validated(self, value: typing.Any) -> float:
1011
1053
  num = super()._validated(value)
1012
1054
  if self.allow_nan is False:
1013
1055
  if math.isnan(num) or num == float("inf") or num == float("-inf"):
@@ -1015,7 +1057,7 @@ class Float(Number):
1015
1057
  return num
1016
1058
 
1017
1059
 
1018
- class Decimal(Number):
1060
+ class Decimal(Number[decimal.Decimal]):
1019
1061
  """A field that (de)serializes to the Python ``decimal.Decimal`` type.
1020
1062
  It's safe to use when dealing with money values, percentages, ratios
1021
1063
  or other numbers where precision is critical.
@@ -1086,7 +1128,7 @@ class Decimal(Number):
1086
1128
  return num
1087
1129
 
1088
1130
  # override Number
1089
- def _validated(self, value):
1131
+ def _validated(self, value: typing.Any) -> decimal.Decimal:
1090
1132
  try:
1091
1133
  num = super()._validated(value)
1092
1134
  except decimal.InvalidOperation as error:
@@ -1096,7 +1138,7 @@ class Decimal(Number):
1096
1138
  return num
1097
1139
 
1098
1140
  # override Number
1099
- def _to_string(self, value):
1141
+ def _to_string(self, value: decimal.Decimal) -> str:
1100
1142
  return format(value, "f")
1101
1143
 
1102
1144
 
@@ -1170,7 +1212,9 @@ class Boolean(Field):
1170
1212
  if falsy is not None:
1171
1213
  self.falsy = set(falsy)
1172
1214
 
1173
- def _serialize(self, value, attr, obj, **kwargs):
1215
+ def _serialize(
1216
+ self, value: typing.Any, attr: str | None, obj: typing.Any, **kwargs
1217
+ ):
1174
1218
  if value is None:
1175
1219
  return None
1176
1220
 
@@ -1213,23 +1257,23 @@ class DateTime(Field):
1213
1257
  Add timestamp as a format.
1214
1258
  """
1215
1259
 
1216
- SERIALIZATION_FUNCS = {
1260
+ SERIALIZATION_FUNCS: dict[str, typing.Callable[[typing.Any], str | float]] = {
1217
1261
  "iso": utils.isoformat,
1218
1262
  "iso8601": utils.isoformat,
1219
1263
  "rfc": utils.rfcformat,
1220
1264
  "rfc822": utils.rfcformat,
1221
1265
  "timestamp": utils.timestamp,
1222
1266
  "timestamp_ms": utils.timestamp_ms,
1223
- } # type: dict[str, typing.Callable[[typing.Any], str | float]]
1267
+ }
1224
1268
 
1225
- DESERIALIZATION_FUNCS = {
1269
+ DESERIALIZATION_FUNCS: dict[str, typing.Callable[[str], typing.Any]] = {
1226
1270
  "iso": utils.from_iso_datetime,
1227
1271
  "iso8601": utils.from_iso_datetime,
1228
1272
  "rfc": utils.from_rfc,
1229
1273
  "rfc822": utils.from_rfc,
1230
1274
  "timestamp": utils.from_timestamp,
1231
1275
  "timestamp_ms": utils.from_timestamp_ms,
1232
- } # type: dict[str, typing.Callable[[str], typing.Any]]
1276
+ }
1233
1277
 
1234
1278
  DEFAULT_FORMAT = "iso"
1235
1279
 
@@ -1534,6 +1578,15 @@ class Mapping(Field):
1534
1578
  #: Default error messages.
1535
1579
  default_error_messages = {"invalid": "Not a valid mapping type."}
1536
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
+
1537
1590
  def __init__(
1538
1591
  self,
1539
1592
  keys: Field | type[Field] | None = None,
@@ -1732,7 +1785,7 @@ class IP(Field):
1732
1785
 
1733
1786
  default_error_messages = {"invalid_ip": "Not a valid IP address."}
1734
1787
 
1735
- DESERIALIZATION_CLASS = None # type: typing.Optional[typing.Type]
1788
+ DESERIALIZATION_CLASS: type | None = None
1736
1789
 
1737
1790
  def __init__(self, *args, exploded=False, **kwargs):
1738
1791
  super().__init__(*args, **kwargs)
@@ -1796,7 +1849,7 @@ class IPInterface(Field):
1796
1849
 
1797
1850
  default_error_messages = {"invalid_ip_interface": "Not a valid IP interface."}
1798
1851
 
1799
- DESERIALIZATION_CLASS = None # type: typing.Optional[typing.Type]
1852
+ DESERIALIZATION_CLASS: type | None = None
1800
1853
 
1801
1854
  def __init__(self, *args, exploded: bool = False, **kwargs):
1802
1855
  super().__init__(*args, **kwargs)
@@ -1846,7 +1899,7 @@ class Enum(Field):
1846
1899
  or Field class or instance to use to (de)serialize by value. Defaults to False.
1847
1900
 
1848
1901
  If `by_value` is `False` (default), enum members are (de)serialized by symbol (name).
1849
- If it is `True`, they are (de)serialized by value using :class:`Field`.
1902
+ If it is `True`, they are (de)serialized by value using :class:`Raw`.
1850
1903
  If it is a field instance or class, they are (de)serialized by value using this field.
1851
1904
 
1852
1905
  .. versionadded:: 3.18.0
@@ -1876,7 +1929,7 @@ class Enum(Field):
1876
1929
  # Serialization by value
1877
1930
  else:
1878
1931
  if by_value is True:
1879
- self.field = Field()
1932
+ self.field = Raw()
1880
1933
  else:
1881
1934
  try:
1882
1935
  self.field = resolve_field_instance(by_value)
marshmallow/schema.py CHANGED
@@ -154,7 +154,7 @@ class SchemaMeta(ABCMeta):
154
154
  """
155
155
  mro = inspect.getmro(cls)
156
156
 
157
- hooks = defaultdict(list) # type: dict[str, list[tuple[str, bool, dict]]]
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 = attr.__marshmallow_hook__ # type: dict[str, list[tuple[bool, dict]]]
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(base.SchemaABC, metaclass=SchemaMeta):
234
+ class Schema(metaclass=SchemaMeta):
233
235
  """Base schema class with which to define custom schemas.
234
236
 
235
237
  Example usage:
@@ -282,7 +284,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
282
284
  `prefix` parameter removed.
283
285
  """
284
286
 
285
- TYPE_MAPPING = {
287
+ TYPE_MAPPING: dict[type, type[ma_fields.Field]] = {
286
288
  str: ma_fields.String,
287
289
  bytes: ma_fields.String,
288
290
  dt.datetime: ma_fields.DateTime,
@@ -297,23 +299,23 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
297
299
  dt.date: ma_fields.Date,
298
300
  dt.timedelta: ma_fields.TimeDelta,
299
301
  decimal.Decimal: ma_fields.Decimal,
300
- } # type: dict[type, typing.Type[ma_fields.Field]]
302
+ }
301
303
  #: Overrides for default schema-level error messages
302
- error_messages = {} # type: dict[str, str]
304
+ error_messages: dict[str, str] = {}
303
305
 
304
- _default_error_messages = {
306
+ _default_error_messages: dict[str, str] = {
305
307
  "type": "Invalid input type.",
306
308
  "unknown": "Unknown field.",
307
- } # type: dict[str, str]
309
+ }
308
310
 
309
- OPTIONS_CLASS = SchemaOpts # type: type
311
+ OPTIONS_CLASS: type = SchemaOpts
310
312
 
311
313
  set_class = OrderedSet
312
314
 
313
315
  # These get set by SchemaMeta
314
- opts = None # type: SchemaOpts
315
- _declared_fields = {} # type: dict[str, ma_fields.Field]
316
- _hooks = {} # type: dict[str, list[tuple[str, bool, dict]]]
316
+ opts: SchemaOpts
317
+ _declared_fields: dict[str, ma_fields.Field] = {}
318
+ _hooks: dict[str, list[tuple[str, bool, dict]]] = {}
317
319
 
318
320
  class Meta:
319
321
  """Options object for a Schema.
@@ -388,12 +390,19 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
388
390
  if unknown is None
389
391
  else validate_unknown_parameter_value(unknown)
390
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
+ )
391
400
  self.context = context or {}
392
401
  self._normalize_nested_options()
393
402
  #: Dictionary mapping field_names -> :class:`Field` objects
394
- self.fields = {} # type: dict[str, ma_fields.Field]
395
- self.load_fields = {} # type: dict[str, ma_fields.Field]
396
- self.dump_fields = {} # type: dict[str, ma_fields.Field]
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] = {}
397
406
  self._init_fields()
398
407
  messages = {}
399
408
  messages.update(self._default_error_messages)
@@ -821,7 +830,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
821
830
  :return: Deserialized data
822
831
  """
823
832
  error_store = ErrorStore()
824
- errors = {} # type: dict[str, list[str]]
833
+ errors: dict[str, list[str]] = {}
825
834
  many = self.many if many is None else bool(many)
826
835
  unknown = (
827
836
  self.unknown
@@ -838,7 +847,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
838
847
  )
839
848
  except ValidationError as err:
840
849
  errors = err.normalized_messages()
841
- result = None # type: list | dict | None
850
+ result: list | dict | None = None
842
851
  else:
843
852
  processed_data = data
844
853
  if not errors:
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 = None # type: str | None
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 # type: str
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 # type: str
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 # type: str
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 # type: str
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 # type: str
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 # type: str
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 # type: str
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 # type: str
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,2 +1,10 @@
1
- class RemovedInMarshmallow4Warning(DeprecationWarning):
1
+ class Marshmallow4Warning(DeprecationWarning):
2
+ pass
3
+
4
+
5
+ class ChangedInMarshmallow4Warning(Marshmallow4Warning):
6
+ pass
7
+
8
+
9
+ class RemovedInMarshmallow4Warning(Marshmallow4Warning):
2
10
  pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: marshmallow
3
- Version: 3.23.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>
@@ -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=bea24GyneKy47tNM6slFy08-R7Sycu_Yii2_bpU82ms,72098
8
- marshmallow/orderedset.py,sha256=C2aAG6w1faIL1phinbAltbe3AUAnF5MN6n7fzESNDhI,2922
9
- marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- marshmallow/schema.py,sha256=UcKJdnKbpqHlgK3E2LNvnrDTFQoWWQ70Qt6rhevfu7E,48240
11
- marshmallow/types.py,sha256=RDS4IfasIehvH2rGWh9e4RTBtsMp-JFFtjApajV22zc,283
12
- marshmallow/utils.py,sha256=-6jOnkuqFvb0DLeTVVifAPOklD_IdHC4LanhClCO0Hc,11897
13
- marshmallow/validate.py,sha256=hS7fYC6byDHK9A7A4is0McDMZEzu6GkKke-7unLt2hE,23857
14
- marshmallow/warnings.py,sha256=vHQu7AluuWqLhvlw5noXtWWbya13zDXY6JMaVSUzmDs,65
15
- marshmallow-3.23.3.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
16
- marshmallow-3.23.3.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
17
- marshmallow-3.23.3.dist-info/METADATA,sha256=TqrYnapcPl01I17SmOHM8iDpcryV0Dba3IMkby9e4Vg,7084
18
- marshmallow-3.23.3.dist-info/RECORD,,