marshmallow 3.25.0__py3-none-any.whl → 3.26.0__py3-none-any.whl

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