marshmallow 3.21.3__py3-none-any.whl → 3.23.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.
@@ -17,7 +17,7 @@ from marshmallow.exceptions import RegistryError
17
17
  if typing.TYPE_CHECKING:
18
18
  from marshmallow import Schema
19
19
 
20
- SchemaType = typing.Type[Schema]
20
+ SchemaType = type[Schema]
21
21
 
22
22
  # {
23
23
  # <class_name>: <list of class objects>
marshmallow/decorators.py CHANGED
@@ -68,6 +68,7 @@ Example: ::
68
68
  from __future__ import annotations
69
69
 
70
70
  import functools
71
+ from collections import defaultdict
71
72
  from typing import Any, Callable, cast
72
73
 
73
74
  PRE_DUMP = "pre_dump"
@@ -79,7 +80,7 @@ VALIDATES_SCHEMA = "validates_schema"
79
80
 
80
81
 
81
82
  class MarshmallowHook:
82
- __marshmallow_hook__: dict[tuple[str, bool] | str, Any] | None = None
83
+ __marshmallow_hook__: dict[str, list[tuple[bool, Any]]] | None = None
83
84
 
84
85
 
85
86
  def validates(field_name: str) -> Callable[..., Any]:
@@ -117,7 +118,8 @@ def validates_schema(
117
118
  """
118
119
  return set_hook(
119
120
  fn,
120
- (VALIDATES_SCHEMA, pass_many),
121
+ VALIDATES_SCHEMA,
122
+ many=pass_many,
121
123
  pass_original=pass_original,
122
124
  skip_on_field_errors=skip_on_field_errors,
123
125
  )
@@ -136,7 +138,7 @@ def pre_dump(
136
138
  .. versionchanged:: 3.0.0
137
139
  ``many`` is always passed as a keyword arguments to the decorated method.
138
140
  """
139
- return set_hook(fn, (PRE_DUMP, pass_many))
141
+ return set_hook(fn, PRE_DUMP, many=pass_many)
140
142
 
141
143
 
142
144
  def post_dump(
@@ -157,7 +159,7 @@ def post_dump(
157
159
  .. versionchanged:: 3.0.0
158
160
  ``many`` is always passed as a keyword arguments to the decorated method.
159
161
  """
160
- return set_hook(fn, (POST_DUMP, pass_many), pass_original=pass_original)
162
+ return set_hook(fn, POST_DUMP, many=pass_many, pass_original=pass_original)
161
163
 
162
164
 
163
165
  def pre_load(
@@ -174,7 +176,7 @@ def pre_load(
174
176
  ``partial`` and ``many`` are always passed as keyword arguments to
175
177
  the decorated method.
176
178
  """
177
- return set_hook(fn, (PRE_LOAD, pass_many))
179
+ return set_hook(fn, PRE_LOAD, many=pass_many)
178
180
 
179
181
 
180
182
  def post_load(
@@ -196,11 +198,11 @@ def post_load(
196
198
  ``partial`` and ``many`` are always passed as keyword arguments to
197
199
  the decorated method.
198
200
  """
199
- return set_hook(fn, (POST_LOAD, pass_many), pass_original=pass_original)
201
+ return set_hook(fn, POST_LOAD, many=pass_many, pass_original=pass_original)
200
202
 
201
203
 
202
204
  def set_hook(
203
- fn: Callable[..., Any] | None, key: tuple[str, bool] | str, **kwargs: Any
205
+ fn: Callable[..., Any] | None, tag: str, many: bool = False, **kwargs: Any
204
206
  ) -> Callable[..., Any]:
205
207
  """Mark decorated function as a hook to be picked up later.
206
208
  You should not need to use this method directly.
@@ -214,7 +216,7 @@ def set_hook(
214
216
  """
215
217
  # Allow using this as either a decorator or a decorator factory.
216
218
  if fn is None:
217
- return functools.partial(set_hook, key=key, **kwargs)
219
+ return functools.partial(set_hook, tag=tag, many=many, **kwargs)
218
220
 
219
221
  # Set a __marshmallow_hook__ attribute instead of wrapping in some class,
220
222
  # because I still want this to end up as a normal (unbound) method.
@@ -222,10 +224,10 @@ def set_hook(
222
224
  try:
223
225
  hook_config = function.__marshmallow_hook__
224
226
  except AttributeError:
225
- function.__marshmallow_hook__ = hook_config = {}
227
+ function.__marshmallow_hook__ = hook_config = defaultdict(list)
226
228
  # Also save the kwargs for the tagged function on
227
- # __marshmallow_hook__, keyed by (<tag>, <pass_many>)
229
+ # __marshmallow_hook__, keyed by <tag>
228
230
  if hook_config is not None:
229
- hook_config[key] = kwargs
231
+ hook_config[tag].append((many, kwargs))
230
232
 
231
233
  return fn
marshmallow/fields.py CHANGED
@@ -33,6 +33,10 @@ from marshmallow.utils import (
33
33
  from marshmallow.validate import And, Length
34
34
  from marshmallow.warnings import RemovedInMarshmallow4Warning
35
35
 
36
+ if typing.TYPE_CHECKING:
37
+ from marshmallow.schema import SchemaMeta
38
+
39
+
36
40
  __all__ = [
37
41
  "Field",
38
42
  "Raw",
@@ -535,10 +539,10 @@ class Nested(Field):
535
539
  def __init__(
536
540
  self,
537
541
  nested: SchemaABC
538
- | type
542
+ | SchemaMeta
539
543
  | str
540
- | dict[str, Field | type]
541
- | typing.Callable[[], SchemaABC | type | dict[str, Field | type]],
544
+ | dict[str, Field | type[Field]]
545
+ | typing.Callable[[], SchemaABC | SchemaMeta | dict[str, Field | type[Field]]],
542
546
  *,
543
547
  dump_default: typing.Any = missing_,
544
548
  default: typing.Any = missing_,
@@ -700,7 +704,7 @@ class Pluck(Nested):
700
704
 
701
705
  def __init__(
702
706
  self,
703
- nested: SchemaABC | type | str | typing.Callable[[], SchemaABC],
707
+ nested: SchemaABC | SchemaMeta | str | typing.Callable[[], SchemaABC],
704
708
  field_name: str,
705
709
  **kwargs,
706
710
  ):
@@ -751,7 +755,7 @@ class List(Field):
751
755
  #: Default error messages.
752
756
  default_error_messages = {"invalid": "Not a valid list."}
753
757
 
754
- def __init__(self, cls_or_instance: Field | type, **kwargs):
758
+ def __init__(self, cls_or_instance: Field | type[Field], **kwargs):
755
759
  super().__init__(**kwargs)
756
760
  try:
757
761
  self.inner = resolve_field_instance(cls_or_instance)
@@ -1236,7 +1240,7 @@ class DateTime(Field):
1236
1240
  "rfc822": utils.rfcformat,
1237
1241
  "timestamp": utils.timestamp,
1238
1242
  "timestamp_ms": utils.timestamp_ms,
1239
- } # type: typing.Dict[str, typing.Callable[[typing.Any], str | float]]
1243
+ } # type: dict[str, typing.Callable[[typing.Any], str | float]]
1240
1244
 
1241
1245
  DESERIALIZATION_FUNCS = {
1242
1246
  "iso": utils.from_iso_datetime,
@@ -1245,7 +1249,7 @@ class DateTime(Field):
1245
1249
  "rfc822": utils.from_rfc,
1246
1250
  "timestamp": utils.from_timestamp,
1247
1251
  "timestamp_ms": utils.from_timestamp_ms,
1248
- } # type: typing.Dict[str, typing.Callable[[str], typing.Any]]
1252
+ } # type: dict[str, typing.Callable[[str], typing.Any]]
1249
1253
 
1250
1254
  DEFAULT_FORMAT = "iso"
1251
1255
 
@@ -1555,8 +1559,8 @@ class Mapping(Field):
1555
1559
 
1556
1560
  def __init__(
1557
1561
  self,
1558
- keys: Field | type | None = None,
1559
- values: Field | type | None = None,
1562
+ keys: Field | type[Field] | None = None,
1563
+ values: Field | type[Field] | None = None,
1560
1564
  **kwargs,
1561
1565
  ):
1562
1566
  super().__init__(**kwargs)
@@ -1878,7 +1882,7 @@ class Enum(Field):
1878
1882
  self,
1879
1883
  enum: type[EnumType],
1880
1884
  *,
1881
- by_value: bool | Field | type = False,
1885
+ by_value: bool | Field | type[Field] = False,
1882
1886
  **kwargs,
1883
1887
  ):
1884
1888
  super().__init__(**kwargs)
marshmallow/schema.py CHANGED
@@ -40,8 +40,6 @@ from marshmallow.utils import (
40
40
  )
41
41
  from marshmallow.warnings import RemovedInMarshmallow4Warning
42
42
 
43
- _T = typing.TypeVar("_T")
44
-
45
43
 
46
44
  def _get_fields(attrs):
47
45
  """Get fields from a class
@@ -57,7 +55,7 @@ def _get_fields(attrs):
57
55
 
58
56
  # This function allows Schemas to inherit from non-Schema classes and ensures
59
57
  # inheritance according to the MRO
60
- def _get_fields_by_mro(klass):
58
+ def _get_fields_by_mro(klass: SchemaMeta):
61
59
  """Collect fields from a class, following its method resolution order. The
62
60
  class itself is excluded from the search; only its parents are checked. Get
63
61
  fields from ``_declared_fields`` if available, else use ``__dict__``.
@@ -125,10 +123,10 @@ class SchemaMeta(ABCMeta):
125
123
  @classmethod
126
124
  def get_declared_fields(
127
125
  mcs,
128
- klass: type,
126
+ klass: SchemaMeta,
129
127
  cls_fields: list,
130
128
  inherited_fields: list,
131
- dict_cls: type = dict,
129
+ dict_cls: type[dict] = dict,
132
130
  ):
133
131
  """Returns a dictionary of field_name => `Field` pairs declared on the class.
134
132
  This is exposed mainly so that plugins can add additional fields, e.g. fields
@@ -148,7 +146,7 @@ class SchemaMeta(ABCMeta):
148
146
  class_registry.register(name, cls)
149
147
  cls._hooks = cls.resolve_hooks()
150
148
 
151
- def resolve_hooks(cls) -> dict[types.Tag, list[str]]:
149
+ def resolve_hooks(cls) -> dict[str, list[tuple[str, bool, dict]]]:
152
150
  """Add in the decorated processors
153
151
 
154
152
  By doing this after constructing the class, we let standard inheritance
@@ -156,7 +154,7 @@ class SchemaMeta(ABCMeta):
156
154
  """
157
155
  mro = inspect.getmro(cls)
158
156
 
159
- hooks = defaultdict(list) # type: typing.Dict[types.Tag, typing.List[str]]
157
+ hooks = defaultdict(list) # type: dict[str, list[tuple[str, bool, dict]]]
160
158
 
161
159
  for attr_name in dir(cls):
162
160
  # Need to look up the actual descriptor, not whatever might be
@@ -176,14 +174,16 @@ class SchemaMeta(ABCMeta):
176
174
  continue
177
175
 
178
176
  try:
179
- hook_config = attr.__marshmallow_hook__
177
+ hook_config = attr.__marshmallow_hook__ # type: dict[str, list[tuple[bool, dict]]]
180
178
  except AttributeError:
181
179
  pass
182
180
  else:
183
- for key in hook_config.keys():
181
+ for tag, config in hook_config.items():
184
182
  # Use name here so we can get the bound method later, in
185
183
  # case the processor was a descriptor or something.
186
- hooks[key].append(attr_name)
184
+ hooks[tag].extend(
185
+ (attr_name, many, kwargs) for many, kwargs in config
186
+ )
187
187
 
188
188
  return hooks
189
189
 
@@ -226,6 +226,7 @@ class SchemaOpts:
226
226
  self.dump_only = getattr(meta, "dump_only", ())
227
227
  self.unknown = validate_unknown_parameter_value(getattr(meta, "unknown", RAISE))
228
228
  self.register = getattr(meta, "register", True)
229
+ self.many = getattr(meta, "many", False)
229
230
 
230
231
 
231
232
  class Schema(base.SchemaABC, metaclass=SchemaMeta):
@@ -303,14 +304,14 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
303
304
  dt.date: ma_fields.Date,
304
305
  dt.timedelta: ma_fields.TimeDelta,
305
306
  decimal.Decimal: ma_fields.Decimal,
306
- } # type: typing.Dict[type, typing.Type[ma_fields.Field]]
307
+ } # type: dict[type, typing.Type[ma_fields.Field]]
307
308
  #: Overrides for default schema-level error messages
308
- error_messages = {} # type: typing.Dict[str, str]
309
+ error_messages = {} # type: dict[str, str]
309
310
 
310
311
  _default_error_messages = {
311
312
  "type": "Invalid input type.",
312
313
  "unknown": "Unknown field.",
313
- } # type: typing.Dict[str, str]
314
+ } # type: dict[str, str]
314
315
 
315
316
  OPTIONS_CLASS = SchemaOpts # type: type
316
317
 
@@ -318,8 +319,8 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
318
319
 
319
320
  # These get set by SchemaMeta
320
321
  opts = None # type: SchemaOpts
321
- _declared_fields = {} # type: typing.Dict[str, ma_fields.Field]
322
- _hooks = {} # type: typing.Dict[types.Tag, typing.List[str]]
322
+ _declared_fields = {} # type: dict[str, ma_fields.Field]
323
+ _hooks = {} # type: dict[str, list[tuple[str, bool, dict]]]
323
324
 
324
325
  class Meta:
325
326
  """Options object for a Schema.
@@ -342,6 +343,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
342
343
  `OrderedDict`.
343
344
  - ``exclude``: Tuple or list of fields to exclude in the serialized result.
344
345
  Nested fields can be represented with dot delimiters.
346
+ - ``many``: Whether the data is a collection by default.
345
347
  - ``dateformat``: Default format for `Date <fields.Date>` fields.
346
348
  - ``datetimeformat``: Default format for `DateTime <fields.DateTime>` fields.
347
349
  - ``timeformat``: Default format for `Time <fields.Time>` fields.
@@ -365,7 +367,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
365
367
  *,
366
368
  only: types.StrSequenceOrSet | None = None,
367
369
  exclude: types.StrSequenceOrSet = (),
368
- many: bool = False,
370
+ many: bool | None = None,
369
371
  context: dict | None = None,
370
372
  load_only: types.StrSequenceOrSet = (),
371
373
  dump_only: types.StrSequenceOrSet = (),
@@ -379,7 +381,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
379
381
  raise StringNotCollectionError('"exclude" should be a list of strings')
380
382
  # copy declared fields from metaclass
381
383
  self.declared_fields = copy.deepcopy(self._declared_fields)
382
- self.many = many
384
+ self.many = self.opts.many if many is None else many
383
385
  self.only = only
384
386
  self.exclude: set[typing.Any] | typing.MutableSet[typing.Any] = set(
385
387
  self.opts.exclude
@@ -396,9 +398,9 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
396
398
  self.context = context or {}
397
399
  self._normalize_nested_options()
398
400
  #: Dictionary mapping field_names -> :class:`Field` objects
399
- self.fields = {} # type: typing.Dict[str, ma_fields.Field]
400
- self.load_fields = {} # type: typing.Dict[str, ma_fields.Field]
401
- self.dump_fields = {} # type: typing.Dict[str, ma_fields.Field]
401
+ self.fields = {} # type: dict[str, ma_fields.Field]
402
+ self.load_fields = {} # type: dict[str, ma_fields.Field]
403
+ self.dump_fields = {} # type: dict[str, ma_fields.Field]
402
404
  self._init_fields()
403
405
  messages = {}
404
406
  messages.update(self._default_error_messages)
@@ -411,16 +413,19 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
411
413
  return f"<{self.__class__.__name__}(many={self.many})>"
412
414
 
413
415
  @property
414
- def dict_class(self) -> type:
415
- return OrderedDict if self.ordered else dict
416
+ def dict_class(self) -> type[dict]:
417
+ if self.ordered:
418
+ return OrderedDict
419
+ else:
420
+ return dict
416
421
 
417
422
  @classmethod
418
423
  def from_dict(
419
424
  cls,
420
- fields: dict[str, ma_fields.Field | type],
425
+ fields: dict[str, ma_fields.Field | type[ma_fields.Field]],
421
426
  *,
422
427
  name: str = "GeneratedSchema",
423
- ) -> type:
428
+ ) -> type[Schema]:
424
429
  """Generate a `Schema` class given a dictionary of fields.
425
430
 
426
431
  .. code-block:: python
@@ -497,7 +502,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
497
502
  return error.valid_data or missing
498
503
  return value
499
504
 
500
- def _serialize(self, obj: _T | typing.Iterable[_T], *, many: bool = False):
505
+ def _serialize(self, obj: typing.Any, *, many: bool = False):
501
506
  """Serialize ``obj``.
502
507
 
503
508
  :param obj: The object(s) to serialize.
@@ -508,10 +513,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
508
513
  Renamed from ``marshal``.
509
514
  """
510
515
  if many and obj is not None:
511
- return [
512
- self._serialize(d, many=False)
513
- for d in typing.cast(typing.Iterable[_T], obj)
514
- ]
516
+ return [self._serialize(d, many=False) for d in obj]
515
517
  ret = self.dict_class()
516
518
  for attr_name, field_obj in self.dump_fields.items():
517
519
  value = field_obj.serialize(attr_name, obj, accessor=self.get_attribute)
@@ -539,7 +541,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
539
541
  Validation no longer occurs upon serialization.
540
542
  """
541
543
  many = self.many if many is None else bool(many)
542
- if self._has_processors(PRE_DUMP):
544
+ if self._hooks[PRE_DUMP]:
543
545
  processed_obj = self._invoke_dump_processors(
544
546
  PRE_DUMP, obj, many=many, original_data=obj
545
547
  )
@@ -548,7 +550,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
548
550
 
549
551
  result = self._serialize(processed_obj, many=many)
550
552
 
551
- if self._has_processors(POST_DUMP):
553
+ if self._hooks[POST_DUMP]:
552
554
  result = self._invoke_dump_processors(
553
555
  POST_DUMP, result, many=many, original_data=obj
554
556
  )
@@ -584,7 +586,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
584
586
  partial=None,
585
587
  unknown=RAISE,
586
588
  index=None,
587
- ) -> _T | list[_T]:
589
+ ) -> typing.Any | list[typing.Any]:
588
590
  """Deserialize ``data``.
589
591
 
590
592
  :param dict data: The data to deserialize.
@@ -598,26 +600,24 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
598
600
  fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
599
601
  :param int index: Index of the item being serialized (for storing errors) if
600
602
  serializing a collection, otherwise `None`.
601
- :return: A dictionary of the deserialized data.
603
+ :return: The deserialized data as `dict_class` instance or list of `dict_class`
604
+ instances if `many` is `True`.
602
605
  """
603
606
  index_errors = self.opts.index_errors
604
607
  index = index if index_errors else None
605
608
  if many:
606
609
  if not is_collection(data):
607
610
  error_store.store_error([self.error_messages["type"]], index=index)
608
- ret_l = [] # type: typing.List[_T]
611
+ ret_l = []
609
612
  else:
610
613
  ret_l = [
611
- typing.cast(
612
- _T,
613
- self._deserialize(
614
- typing.cast(typing.Mapping[str, typing.Any], d),
615
- error_store=error_store,
616
- many=False,
617
- partial=partial,
618
- unknown=unknown,
619
- index=idx,
620
- ),
614
+ self._deserialize(
615
+ typing.cast(dict, d),
616
+ error_store=error_store,
617
+ many=False,
618
+ partial=partial,
619
+ unknown=unknown,
620
+ index=idx,
621
621
  )
622
622
  for idx, d in enumerate(data)
623
623
  ]
@@ -802,7 +802,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
802
802
  try:
803
803
  self._do_load(data, many=many, partial=partial, postprocess=False)
804
804
  except ValidationError as exc:
805
- return typing.cast(typing.Dict[str, typing.List[str]], exc.messages)
805
+ return typing.cast(dict[str, list[str]], exc.messages)
806
806
  return {}
807
807
 
808
808
  ##### Private Helpers #####
@@ -846,7 +846,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
846
846
  if partial is None:
847
847
  partial = self.partial
848
848
  # Run preprocessors
849
- if self._has_processors(PRE_LOAD):
849
+ if self._hooks[PRE_LOAD]:
850
850
  try:
851
851
  processed_data = self._invoke_load_processors(
852
852
  PRE_LOAD, data, many=many, original_data=data, partial=partial
@@ -870,7 +870,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
870
870
  error_store=error_store, data=result, many=many
871
871
  )
872
872
  # Run schema-level validation
873
- if self._has_processors(VALIDATES_SCHEMA):
873
+ if self._hooks[VALIDATES_SCHEMA]:
874
874
  field_errors = bool(error_store.errors)
875
875
  self._invoke_schema_validators(
876
876
  error_store=error_store,
@@ -892,7 +892,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
892
892
  )
893
893
  errors = error_store.errors
894
894
  # Run post processors
895
- if not errors and postprocess and self._has_processors(POST_LOAD):
895
+ if not errors and postprocess and self._hooks[POST_LOAD]:
896
896
  try:
897
897
  result = self._invoke_load_processors(
898
898
  POST_LOAD,
@@ -1055,9 +1055,6 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1055
1055
  raise error
1056
1056
  self.on_bind_field(field_name, field_obj)
1057
1057
 
1058
- def _has_processors(self, tag) -> bool:
1059
- return bool(self._hooks[(tag, True)] or self._hooks[(tag, False)])
1060
-
1061
1058
  def _invoke_dump_processors(
1062
1059
  self, tag: str, data, *, many: bool, original_data=None
1063
1060
  ):
@@ -1102,9 +1099,8 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1102
1099
  return data
1103
1100
 
1104
1101
  def _invoke_field_validators(self, *, error_store: ErrorStore, data, many: bool):
1105
- for attr_name in self._hooks[VALIDATES]:
1102
+ for attr_name, _, validator_kwargs in self._hooks[VALIDATES]:
1106
1103
  validator = getattr(self, attr_name)
1107
- validator_kwargs = validator.__marshmallow_hook__[VALIDATES]
1108
1104
  field_name = validator_kwargs["field_name"]
1109
1105
 
1110
1106
  try:
@@ -1159,11 +1155,10 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1159
1155
  partial: bool | types.StrSequenceOrSet | None,
1160
1156
  field_errors: bool = False,
1161
1157
  ):
1162
- for attr_name in self._hooks[(VALIDATES_SCHEMA, pass_many)]:
1158
+ for attr_name, hook_many, validator_kwargs in self._hooks[VALIDATES_SCHEMA]:
1159
+ if hook_many != pass_many:
1160
+ continue
1163
1161
  validator = getattr(self, attr_name)
1164
- validator_kwargs = validator.__marshmallow_hook__[
1165
- (VALIDATES_SCHEMA, pass_many)
1166
- ]
1167
1162
  if field_errors and validator_kwargs["skip_on_field_errors"]:
1168
1163
  continue
1169
1164
  pass_original = validator_kwargs.get("pass_original", False)
@@ -1201,12 +1196,11 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1201
1196
  original_data=None,
1202
1197
  **kwargs,
1203
1198
  ):
1204
- key = (tag, pass_many)
1205
- for attr_name in self._hooks[key]:
1199
+ for attr_name, hook_many, processor_kwargs in self._hooks[tag]:
1200
+ if hook_many != pass_many:
1201
+ continue
1206
1202
  # This will be a bound method.
1207
1203
  processor = getattr(self, attr_name)
1208
-
1209
- processor_kwargs = processor.__marshmallow_hook__[key]
1210
1204
  pass_original = processor_kwargs.get("pass_original", False)
1211
1205
 
1212
1206
  if many and not pass_many:
marshmallow/types.py CHANGED
@@ -8,5 +8,4 @@
8
8
  import typing
9
9
 
10
10
  StrSequenceOrSet = typing.Union[typing.Sequence[str], typing.AbstractSet[str]]
11
- Tag = typing.Union[str, typing.Tuple[str, bool]]
12
11
  Validator = typing.Callable[[typing.Any], typing.Any]
@@ -1,31 +1,30 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: marshmallow
3
- Version: 3.21.3
3
+ Version: 3.23.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>
7
- Requires-Python: >=3.8
7
+ Requires-Python: >=3.9
8
8
  Description-Content-Type: text/x-rst
9
9
  Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.8
14
13
  Classifier: Programming Language :: Python :: 3.9
15
14
  Classifier: Programming Language :: Python :: 3.10
16
15
  Classifier: Programming Language :: Python :: 3.11
17
16
  Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
18
  Requires-Dist: packaging>=17.0
19
19
  Requires-Dist: marshmallow[tests] ; extra == "dev"
20
20
  Requires-Dist: tox ; extra == "dev"
21
- Requires-Dist: pre-commit~=3.5 ; extra == "dev"
22
- Requires-Dist: sphinx==7.3.7 ; extra == "docs"
23
- Requires-Dist: sphinx-issues==4.1.0 ; extra == "docs"
24
- Requires-Dist: alabaster==0.7.16 ; extra == "docs"
21
+ Requires-Dist: pre-commit>=3.5,<5.0 ; extra == "dev"
22
+ Requires-Dist: sphinx==8.1.3 ; extra == "docs"
23
+ Requires-Dist: sphinx-issues==5.0.0 ; extra == "docs"
24
+ Requires-Dist: alabaster==1.0.0 ; extra == "docs"
25
25
  Requires-Dist: sphinx-version-warning==1.1.2 ; extra == "docs"
26
- Requires-Dist: autodocsumm==0.2.12 ; extra == "docs"
26
+ Requires-Dist: autodocsumm==0.2.13 ; extra == "docs"
27
27
  Requires-Dist: pytest ; extra == "tests"
28
- Requires-Dist: pytz ; extra == "tests"
29
28
  Requires-Dist: simplejson ; extra == "tests"
30
29
  Project-URL: Changelog, https://marshmallow.readthedocs.io/en/latest/changelog.html
31
30
  Project-URL: Funding, https://opencollective.com/marshmallow
@@ -40,24 +39,39 @@ Provides-Extra: tests
40
39
  marshmallow: simplified object serialization
41
40
  ********************************************
42
41
 
43
- .. image:: https://badgen.net/pypi/v/marshmallow
42
+ |pypi| |build-status| |pre-commit| |docs|
43
+
44
+ .. |pypi| image:: https://badgen.net/pypi/v/marshmallow
44
45
  :target: https://pypi.org/project/marshmallow/
45
46
  :alt: Latest version
46
47
 
47
- .. image:: https://github.com/marshmallow-code/marshmallow/actions/workflows/build-release.yml/badge.svg
48
+ .. |build-status| image:: https://github.com/marshmallow-code/marshmallow/actions/workflows/build-release.yml/badge.svg
48
49
  :target: https://github.com/marshmallow-code/marshmallow/actions/workflows/build-release.yml
49
50
  :alt: Build status
50
51
 
51
- .. image:: https://results.pre-commit.ci/badge/github/marshmallow-code/marshmallow/dev.svg
52
+ .. |pre-commit| image:: https://results.pre-commit.ci/badge/github/marshmallow-code/marshmallow/dev.svg
52
53
  :target: https://results.pre-commit.ci/latest/github/marshmallow-code/marshmallow/dev
53
54
  :alt: pre-commit.ci status
54
55
 
55
- .. image:: https://readthedocs.org/projects/marshmallow/badge/
56
+ .. |docs| image:: https://readthedocs.org/projects/marshmallow/badge/
56
57
  :target: https://marshmallow.readthedocs.io/
57
58
  :alt: Documentation
58
59
 
59
60
  **marshmallow** is an ORM/ODM/framework-agnostic library for converting complex datatypes, such as objects, to and from native Python datatypes.
60
61
 
62
+ Sponsor Message
63
+ ===============
64
+
65
+ Input an OpenAPI spec to generate API docs that look as good as Stripe's. `Request a preview <https://form.typeform.com/to/bShdJw7z>`_ of your docs on Fern.
66
+
67
+ .. image:: https://github.com/user-attachments/assets/69916225-0d61-4bd7-b3b9-e378557673cb
68
+ :target: https://form.typeform.com/to/bShdJw7z
69
+ :align: center
70
+ :alt: Fern logo
71
+
72
+ Example
73
+ =======
74
+
61
75
  .. code-block:: python
62
76
 
63
77
  from datetime import date
@@ -109,7 +123,7 @@ Full documentation is available at https://marshmallow.readthedocs.io/ .
109
123
  Requirements
110
124
  ============
111
125
 
112
- - Python >= 3.8
126
+ - Python >= 3.9
113
127
 
114
128
  Ecosystem
115
129
  =========
@@ -152,15 +166,16 @@ Thank you to all our backers! [`Become a backer`_]
152
166
  Sponsors
153
167
  --------
154
168
 
155
- Support this project by becoming a sponsor (or ask your company to support this project by becoming a sponsor).
156
- Your logo will show up here with a link to your website. [`Become a sponsor`_]
169
+ marshmallow is sponsored by `Route4Me <https://route4me.com>`_.
157
170
 
158
- .. _`Become a sponsor`: https://opencollective.com/marshmallow#sponsor
171
+ .. image:: https://github.com/user-attachments/assets/018c2e23-032e-4a11-98da-8b6dc25b9054
172
+ :target: https://route4me.com
173
+ :alt: Routing Planner
159
174
 
160
- .. image:: https://opencollective.com/static/images/become_sponsor.svg
161
- :target: https://opencollective.com/marshmallow#sponsor
162
- :alt: Become a sponsor
175
+ Support this project by becoming a sponsor (or ask your company to support this project by becoming a sponsor).
176
+ Your logo will be displayed here with a link to your website. [`Become a sponsor`_]
163
177
 
178
+ .. _`Become a sponsor`: https://opencollective.com/marshmallow#sponsor
164
179
 
165
180
  Professional Support
166
181
  ====================
@@ -1,18 +1,18 @@
1
1
  marshmallow/__init__.py,sha256=C-zbaQJ9dlJLJxotIqTa5OOaD6ojGNRqW8moGrMsGr8,2387
2
2
  marshmallow/base.py,sha256=jZ68DZxxSCvRg2GTcxQcf2JjTxqEn-xFNrBEMK3CinU,1346
3
- marshmallow/class_registry.py,sha256=Uvg-Obos0MejwTrpOHNEH4VF_SfGXKgR-4F2LnCbt1A,2811
4
- marshmallow/decorators.py,sha256=aa0tmqYW7-EJSae0ztZU9fHiQ3YIBdvIgaCrl1ChLNA,8300
3
+ marshmallow/class_registry.py,sha256=kT_kv9KT0EUclIluLD5734ms9P0e65t5aky8y3lipFI,2804
4
+ marshmallow/decorators.py,sha256=vmQFgBgdV0s1Fw8ySyZyQKvjKBTNf5JB3SCldEIl29o,8385
5
5
  marshmallow/error_store.py,sha256=A7AxgLMw9ffSmaxRH4x3wcBWibx-DuGH4LwSDpVn50I,2223
6
6
  marshmallow/exceptions.py,sha256=DuARdOcirCdJxmlp16V97hQKAXOokvdW12jXtYOlGyk,2326
7
- marshmallow/fields.py,sha256=3mWgT1TiLzKgdhgWTJYsGe6lVgUz02g8sb63FEEn5hc,72995
7
+ marshmallow/fields.py,sha256=6Cit4Z6AE_HDQBvspibHR8UgtwBkp_oNRaCIqjPR64s,73114
8
8
  marshmallow/orderedset.py,sha256=C2aAG6w1faIL1phinbAltbe3AUAnF5MN6n7fzESNDhI,2922
9
9
  marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- marshmallow/schema.py,sha256=6LgdLVs63eOCO253-dbmyFhVijpQO9nlMmO4NePb0yM,48938
11
- marshmallow/types.py,sha256=eHMwQR8-ICX2RHf_i6bgjnhzdanbpBqXuzXuP6jHcNI,332
10
+ marshmallow/schema.py,sha256=C4BsYkDBQbdgDA6w39oSqVlsDx4NfbkT_XtSIKcqxIo,48812
11
+ marshmallow/types.py,sha256=RDS4IfasIehvH2rGWh9e4RTBtsMp-JFFtjApajV22zc,283
12
12
  marshmallow/utils.py,sha256=sWciesZ6tS08uX9Z9fzu2lbuut5eh8TKABU-TwgqSms,11886
13
13
  marshmallow/validate.py,sha256=hS7fYC6byDHK9A7A4is0McDMZEzu6GkKke-7unLt2hE,23857
14
14
  marshmallow/warnings.py,sha256=vHQu7AluuWqLhvlw5noXtWWbya13zDXY6JMaVSUzmDs,65
15
- marshmallow-3.21.3.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
16
- marshmallow-3.21.3.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
17
- marshmallow-3.21.3.dist-info/METADATA,sha256=fj4yso9TRYDOr1uK6J1CWKCdguaKRy-KEC5gLBKaFsU,7079
18
- marshmallow-3.21.3.dist-info/RECORD,,
15
+ marshmallow-3.23.0.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
16
+ marshmallow-3.23.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
17
+ marshmallow-3.23.0.dist-info/METADATA,sha256=kKdIlUdvaVt3ZOQbuGFgfX65m2Yv8FrmPt3766XiBmU,7582
18
+ marshmallow-3.23.0.dist-info/RECORD,,