davidtran999 commited on
Commit
0958857
·
verified ·
1 Parent(s): dcbe3bf

Upload backend/venv/lib/python3.10/site-packages/marshmallow/schema.py with huggingface_hub

Browse files
backend/venv/lib/python3.10/site-packages/marshmallow/schema.py ADDED
@@ -0,0 +1,1309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """The `Schema <marshmallow.Schema>` class, including its metaclass and options (`class Meta <marshmallow.Schema.Meta>`)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import copy
6
+ import datetime as dt
7
+ import decimal
8
+ import functools
9
+ import inspect
10
+ import json
11
+ import operator
12
+ import typing
13
+ import uuid
14
+ import warnings
15
+ from abc import ABCMeta
16
+ from collections import OrderedDict, defaultdict
17
+ from collections.abc import Mapping
18
+ from itertools import zip_longest
19
+
20
+ from marshmallow import base, class_registry, types
21
+ from marshmallow import fields as ma_fields
22
+ from marshmallow.decorators import (
23
+ POST_DUMP,
24
+ POST_LOAD,
25
+ PRE_DUMP,
26
+ PRE_LOAD,
27
+ VALIDATES,
28
+ VALIDATES_SCHEMA,
29
+ )
30
+ from marshmallow.error_store import ErrorStore
31
+ from marshmallow.exceptions import SCHEMA, StringNotCollectionError, ValidationError
32
+ from marshmallow.orderedset import OrderedSet
33
+ from marshmallow.utils import (
34
+ EXCLUDE,
35
+ INCLUDE,
36
+ RAISE,
37
+ get_value,
38
+ is_collection,
39
+ is_instance_or_subclass,
40
+ missing,
41
+ set_value,
42
+ validate_unknown_parameter_value,
43
+ )
44
+ from marshmallow.warnings import RemovedInMarshmallow4Warning
45
+
46
+ if typing.TYPE_CHECKING:
47
+ from marshmallow.fields import Field
48
+
49
+
50
+ def _get_fields(attrs) -> list[tuple[str, Field]]:
51
+ """Get fields from a class
52
+
53
+ :param attrs: Mapping of class attributes
54
+ """
55
+ return [
56
+ (field_name, field_value)
57
+ for field_name, field_value in attrs.items()
58
+ if is_instance_or_subclass(field_value, base.FieldABC)
59
+ ]
60
+
61
+
62
+ # This function allows Schemas to inherit from non-Schema classes and ensures
63
+ # inheritance according to the MRO
64
+ def _get_fields_by_mro(klass: SchemaMeta):
65
+ """Collect fields from a class, following its method resolution order. The
66
+ class itself is excluded from the search; only its parents are checked. Get
67
+ fields from ``_declared_fields`` if available, else use ``__dict__``.
68
+
69
+ :param klass: Class whose fields to retrieve
70
+ """
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, [])
74
+ # Loop over mro in reverse to maintain correct order of fields
75
+ return functools.reduce(
76
+ operator.iadd,
77
+ (
78
+ _get_fields(
79
+ getattr(base, "_declared_fields", base.__dict__),
80
+ )
81
+ for base in mro[:0:-1]
82
+ ),
83
+ [],
84
+ )
85
+
86
+
87
+ class SchemaMeta(ABCMeta):
88
+ """Metaclass for the Schema class. Binds the declared fields to
89
+ a ``_declared_fields`` attribute, which is a dictionary mapping attribute
90
+ names to field objects. Also sets the ``opts`` class attribute, which is
91
+ the Schema class's `class Meta <marshmallow.Schema.Meta>` options.
92
+ """
93
+
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:
105
+ meta = attrs.get("Meta")
106
+ ordered = getattr(meta, "ordered", False)
107
+ if not ordered:
108
+ # Inherit 'ordered' option
109
+ # Warning: We loop through bases instead of MRO because we don't
110
+ # yet have access to the class object
111
+ # (i.e. can't call super before we have fields)
112
+ for base_ in bases:
113
+ if hasattr(base_, "Meta") and hasattr(base_.Meta, "ordered"):
114
+ ordered = base_.Meta.ordered
115
+ break
116
+ else:
117
+ ordered = False
118
+ cls_fields = _get_fields(attrs)
119
+ # Remove fields from list of class attributes to avoid shadowing
120
+ # Schema attributes/methods in case of name conflict
121
+ for field_name, _ in cls_fields:
122
+ del attrs[field_name]
123
+ klass = super().__new__(mcs, name, bases, attrs)
124
+ inherited_fields = _get_fields_by_mro(klass)
125
+
126
+ meta = klass.Meta
127
+ # Set klass.opts in __new__ rather than __init__ so that it is accessible in
128
+ # get_declared_fields
129
+ klass.opts = klass.OPTIONS_CLASS(meta, ordered=ordered)
130
+ # Add fields specified in the `include` class Meta option
131
+ cls_fields += list(klass.opts.include.items())
132
+
133
+ # Assign _declared_fields on class
134
+ klass._declared_fields = mcs.get_declared_fields( # noqa: SLF001
135
+ klass=klass,
136
+ cls_fields=cls_fields,
137
+ inherited_fields=inherited_fields,
138
+ dict_cls=dict,
139
+ )
140
+ return klass
141
+
142
+ @classmethod
143
+ def get_declared_fields(
144
+ mcs, # noqa: N804
145
+ klass: SchemaMeta,
146
+ cls_fields: list[tuple[str, Field]],
147
+ inherited_fields: list[tuple[str, Field]],
148
+ dict_cls: type[dict] = dict,
149
+ ) -> dict[str, Field]:
150
+ """Returns a dictionary of field_name => `Field` pairs declared on the class.
151
+ This is exposed mainly so that plugins can add additional fields, e.g. fields
152
+ computed from `class Meta <marshmallow.Schema.Meta>` options.
153
+
154
+ :param klass: The class object.
155
+ :param cls_fields: The fields declared on the class, including those added
156
+ by the ``include`` `class Meta <marshmallow.Schema.Meta>` option.
157
+ :param inherited_fields: Inherited fields.
158
+ :param dict_cls: dict-like class to use for dict output Default to ``dict``.
159
+ """
160
+ return dict_cls(inherited_fields + cls_fields)
161
+
162
+ def __init__(cls, name, bases, attrs):
163
+ super().__init__(name, bases, attrs)
164
+ if name and cls.opts.register:
165
+ class_registry.register(name, cls)
166
+ cls._hooks = cls.resolve_hooks()
167
+
168
+ def resolve_hooks(cls) -> dict[str, list[tuple[str, bool, dict]]]:
169
+ """Add in the decorated processors
170
+
171
+ By doing this after constructing the class, we let standard inheritance
172
+ do all the hard work.
173
+ """
174
+ mro = inspect.getmro(cls)
175
+
176
+ hooks: dict[str, list[tuple[str, bool, dict]]] = defaultdict(list)
177
+
178
+ for attr_name in dir(cls):
179
+ # Need to look up the actual descriptor, not whatever might be
180
+ # bound to the class. This needs to come from the __dict__ of the
181
+ # declaring class.
182
+ for parent in mro:
183
+ try:
184
+ attr = parent.__dict__[attr_name]
185
+ except KeyError:
186
+ continue
187
+ else:
188
+ break
189
+ else:
190
+ # In case we didn't find the attribute and didn't break above.
191
+ # We should never hit this - it's just here for completeness
192
+ # to exclude the possibility of attr being undefined.
193
+ continue
194
+
195
+ try:
196
+ hook_config: dict[str, list[tuple[bool, dict]]] = (
197
+ attr.__marshmallow_hook__
198
+ )
199
+ except AttributeError:
200
+ pass
201
+ else:
202
+ for tag, config in hook_config.items():
203
+ # Use name here so we can get the bound method later, in
204
+ # case the processor was a descriptor or something.
205
+ hooks[tag].extend(
206
+ (attr_name, many, kwargs) for many, kwargs in config
207
+ )
208
+
209
+ return hooks
210
+
211
+
212
+ class SchemaOpts:
213
+ """Defines defaults for `marshmallow.Schema.Meta`."""
214
+
215
+ def __init__(self, meta: type, ordered: bool = False): # noqa: FBT001, FBT002
216
+ self.fields = getattr(meta, "fields", ())
217
+ if not isinstance(self.fields, (list, tuple)):
218
+ raise ValueError("`fields` option must be a list or tuple.")
219
+ self.additional = getattr(meta, "additional", ())
220
+ if not isinstance(self.additional, (list, tuple)):
221
+ raise ValueError("`additional` option must be a list or tuple.")
222
+ if self.fields and self.additional:
223
+ raise ValueError(
224
+ "Cannot set both `fields` and `additional` options for the same Schema."
225
+ )
226
+ self.exclude = getattr(meta, "exclude", ())
227
+ if not isinstance(self.exclude, (list, tuple)):
228
+ raise ValueError("`exclude` must be a list or tuple.")
229
+ self.dateformat = getattr(meta, "dateformat", None)
230
+ self.datetimeformat = getattr(meta, "datetimeformat", None)
231
+ self.timeformat = getattr(meta, "timeformat", None)
232
+ if hasattr(meta, "json_module"):
233
+ warnings.warn(
234
+ "The json_module class Meta option is deprecated. Use render_module instead.",
235
+ RemovedInMarshmallow4Warning,
236
+ stacklevel=2,
237
+ )
238
+ render_module = getattr(meta, "json_module", json)
239
+ else:
240
+ render_module = json
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
+ )
250
+ self.ordered = getattr(meta, "ordered", ordered)
251
+ self.index_errors = getattr(meta, "index_errors", True)
252
+ self.include = getattr(meta, "include", {})
253
+ self.load_only = getattr(meta, "load_only", ())
254
+ self.dump_only = getattr(meta, "dump_only", ())
255
+ self.unknown = validate_unknown_parameter_value(getattr(meta, "unknown", RAISE))
256
+ self.register = getattr(meta, "register", True)
257
+ self.many = getattr(meta, "many", False)
258
+
259
+
260
+ class Schema(base.SchemaABC, metaclass=SchemaMeta):
261
+ """Base schema class with which to define schemas.
262
+
263
+ Example usage:
264
+
265
+ .. code-block:: python
266
+
267
+ import datetime as dt
268
+ from dataclasses import dataclass
269
+
270
+ from marshmallow import Schema, fields
271
+
272
+
273
+ @dataclass
274
+ class Album:
275
+ title: str
276
+ release_date: dt.date
277
+
278
+
279
+ class AlbumSchema(Schema):
280
+ title = fields.Str()
281
+ release_date = fields.Date()
282
+
283
+
284
+ album = Album("Beggars Banquet", dt.date(1968, 12, 6))
285
+ schema = AlbumSchema()
286
+ data = schema.dump(album)
287
+ data # {'release_date': '1968-12-06', 'title': 'Beggars Banquet'}
288
+
289
+ :param only: Whitelist of the declared fields to select when
290
+ instantiating the Schema. If None, all fields are used. Nested fields
291
+ can be represented with dot delimiters.
292
+ :param exclude: Blacklist of the declared fields to exclude
293
+ when instantiating the Schema. If a field appears in both `only` and
294
+ `exclude`, it is not used. Nested fields can be represented with dot
295
+ delimiters.
296
+ :param many: Should be set to `True` if ``obj`` is a collection
297
+ so that the object will be serialized to a list.
298
+ :param context: Optional context passed to :class:`fields.Method` and
299
+ :class:`fields.Function` fields.
300
+ :param load_only: Fields to skip during serialization (write-only fields)
301
+ :param dump_only: Fields to skip during deserialization (read-only fields)
302
+ :param partial: Whether to ignore missing fields and not require
303
+ any fields declared. Propagates down to ``Nested`` fields as well. If
304
+ its value is an iterable, only missing fields listed in that iterable
305
+ will be ignored. Use dot delimiters to specify nested fields.
306
+ :param unknown: Whether to exclude, include, or raise an error for unknown
307
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
308
+
309
+ .. versionchanged:: 3.0.0
310
+ `prefix` parameter removed.
311
+ """
312
+
313
+ TYPE_MAPPING: dict[type, type[Field]] = {
314
+ str: ma_fields.String,
315
+ bytes: ma_fields.String,
316
+ dt.datetime: ma_fields.DateTime,
317
+ float: ma_fields.Float,
318
+ bool: ma_fields.Boolean,
319
+ tuple: ma_fields.Raw,
320
+ list: ma_fields.Raw,
321
+ set: ma_fields.Raw,
322
+ int: ma_fields.Integer,
323
+ uuid.UUID: ma_fields.UUID,
324
+ dt.time: ma_fields.Time,
325
+ dt.date: ma_fields.Date,
326
+ dt.timedelta: ma_fields.TimeDelta,
327
+ decimal.Decimal: ma_fields.Decimal,
328
+ }
329
+ #: Overrides for default schema-level error messages
330
+ error_messages: dict[str, str] = {}
331
+
332
+ _default_error_messages: dict[str, str] = {
333
+ "type": "Invalid input type.",
334
+ "unknown": "Unknown field.",
335
+ }
336
+
337
+ OPTIONS_CLASS: type = SchemaOpts
338
+
339
+ set_class = OrderedSet
340
+
341
+ # These get set by SchemaMeta
342
+ opts: typing.Any
343
+ _declared_fields: dict[str, Field] = {}
344
+ _hooks: dict[str, list[tuple[str, bool, dict]]] = {}
345
+
346
+ class Meta:
347
+ """Options object for a Schema.
348
+
349
+ Example usage: ::
350
+
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[str, ...] | list[str]]
388
+ """Fields to include in the (de)serialized result"""
389
+ additional: typing.ClassVar[tuple[str, ...] | list[str]]
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[str, ...] | list[str]]
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
+
412
+ # FIXME: Use a more constrained type here.
413
+ # ClassVar[RenderModule] doesn't work.
414
+ render_module: typing.Any
415
+ """ Module to use for `loads <marshmallow.Schema.loads>` and `dumps <marshmallow.Schema.dumps>`.
416
+ Defaults to `json` from the standard library.
417
+ """
418
+ ordered: typing.ClassVar[bool]
419
+ """If `True`, `Schema.dump <marshmallow.Schema.dump>` is a `collections.OrderedDict`."""
420
+ index_errors: typing.ClassVar[bool]
421
+ """If `True`, errors dictionaries will include the index of invalid items in a collection."""
422
+ load_only: typing.ClassVar[tuple[str, ...] | list[str]]
423
+ """Fields to exclude from serialized results"""
424
+ dump_only: typing.ClassVar[tuple[str, ...] | list[str]]
425
+ """Fields to exclude from serialized results"""
426
+ unknown: typing.ClassVar[str]
427
+ """Whether to exclude, include, or raise an error for unknown fields in the data.
428
+ Use `EXCLUDE`, `INCLUDE` or `RAISE`.
429
+ """
430
+ register: typing.ClassVar[bool]
431
+ """Whether to register the `Schema <marshmallow.Schema>` with marshmallow's internal
432
+ class registry. Must be `True` if you intend to refer to this `Schema <marshmallow.Schema>`
433
+ by class name in `Nested` fields. Only set this to `False` when memory
434
+ usage is critical. Defaults to `True`.
435
+ """
436
+
437
+ def __init__(
438
+ self,
439
+ *,
440
+ only: types.StrSequenceOrSet | None = None,
441
+ exclude: types.StrSequenceOrSet = (),
442
+ many: bool | None = None,
443
+ context: dict | None = None,
444
+ load_only: types.StrSequenceOrSet = (),
445
+ dump_only: types.StrSequenceOrSet = (),
446
+ partial: bool | types.StrSequenceOrSet | None = None,
447
+ unknown: str | None = None,
448
+ ):
449
+ # Raise error if only or exclude is passed as string, not list of strings
450
+ if only is not None and not is_collection(only):
451
+ raise StringNotCollectionError('"only" should be a list of strings')
452
+ if not is_collection(exclude):
453
+ raise StringNotCollectionError('"exclude" should be a list of strings')
454
+ # copy declared fields from metaclass
455
+ self.declared_fields = copy.deepcopy(self._declared_fields)
456
+ self.many = self.opts.many if many is None else many
457
+ self.only = only
458
+ self.exclude: set[typing.Any] | typing.MutableSet[typing.Any] = set(
459
+ self.opts.exclude
460
+ ) | set(exclude)
461
+ self.ordered = self.opts.ordered
462
+ self.load_only = set(load_only) or set(self.opts.load_only)
463
+ self.dump_only = set(dump_only) or set(self.opts.dump_only)
464
+ self.partial = partial
465
+ self.unknown = (
466
+ self.opts.unknown
467
+ if unknown is None
468
+ else validate_unknown_parameter_value(unknown)
469
+ )
470
+ if context:
471
+ warnings.warn(
472
+ "The `context` parameter is deprecated and will be removed in marshmallow 4.0. "
473
+ "Use `contextvars.ContextVar` to pass context instead.",
474
+ RemovedInMarshmallow4Warning,
475
+ stacklevel=2,
476
+ )
477
+ self.context = context or {}
478
+ self._normalize_nested_options()
479
+ #: Dictionary mapping field_names -> :class:`Field` objects
480
+ self.fields: dict[str, Field] = {}
481
+ self.load_fields: dict[str, Field] = {}
482
+ self.dump_fields: dict[str, Field] = {}
483
+ self._init_fields()
484
+ messages = {}
485
+ messages.update(self._default_error_messages)
486
+ for cls in reversed(self.__class__.__mro__):
487
+ messages.update(getattr(cls, "error_messages", {}))
488
+ messages.update(self.error_messages or {})
489
+ self.error_messages = messages
490
+
491
+ def __repr__(self) -> str:
492
+ return f"<{self.__class__.__name__}(many={self.many})>"
493
+
494
+ @property
495
+ def dict_class(self) -> type[dict]:
496
+ """`dict` type to return when serializing."""
497
+ if self.ordered:
498
+ return OrderedDict
499
+ return dict
500
+
501
+ @classmethod
502
+ def from_dict(
503
+ cls,
504
+ fields: dict[str, Field],
505
+ *,
506
+ name: str = "GeneratedSchema",
507
+ ) -> type[Schema]:
508
+ """Generate a `Schema <marshmallow.Schema>` class given a dictionary of fields.
509
+
510
+ .. code-block:: python
511
+
512
+ from marshmallow import Schema, fields
513
+
514
+ PersonSchema = Schema.from_dict({"name": fields.Str()})
515
+ print(PersonSchema().load({"name": "David"})) # => {'name': 'David'}
516
+
517
+ Generated schemas are not added to the class registry and therefore cannot
518
+ be referred to by name in `Nested` fields.
519
+
520
+
521
+ :param fields: Dictionary mapping field names to field instances.
522
+ :param name: Optional name for the class, which will appear in
523
+ the ``repr`` for the class.
524
+
525
+ .. versionadded:: 3.0.0
526
+ """
527
+ Meta = type(
528
+ "GeneratedMeta", (getattr(cls, "Meta", object),), {"register": False}
529
+ )
530
+ return type(name, (cls,), {**fields.copy(), "Meta": Meta})
531
+
532
+ ##### Override-able methods #####
533
+
534
+ def handle_error(
535
+ self, error: ValidationError, data: typing.Any, *, many: bool, **kwargs
536
+ ):
537
+ """Custom error handler function for the schema.
538
+
539
+ :param error: The `ValidationError` raised during (de)serialization.
540
+ :param data: The original input data.
541
+ :param many: Value of ``many`` on dump or load.
542
+ :param partial: Value of ``partial`` on load.
543
+
544
+ .. versionchanged:: 3.0.0rc9
545
+ Receives `many` and `partial` (on deserialization) as keyword arguments.
546
+ """
547
+
548
+ def get_attribute(self, obj: typing.Any, attr: str, default: typing.Any):
549
+ """Defines how to pull values from an object to serialize.
550
+
551
+ .. versionchanged:: 3.0.0a1
552
+ Changed position of ``obj`` and ``attr``.
553
+ """
554
+ return get_value(obj, attr, default)
555
+
556
+ ##### Serialization/Deserialization API #####
557
+
558
+ @staticmethod
559
+ def _call_and_store(getter_func, data, *, field_name, error_store, index=None):
560
+ """Call ``getter_func`` with ``data`` as its argument, and store any `ValidationErrors`.
561
+
562
+ :param getter_func: Function for getting the serialized/deserialized
563
+ value from ``data``.
564
+ :param data: The data passed to ``getter_func``.
565
+ :param field_name: Field name.
566
+ :param index: Index of the item being validated, if validating a collection,
567
+ otherwise `None`.
568
+ """
569
+ try:
570
+ value = getter_func(data)
571
+ except ValidationError as error:
572
+ error_store.store_error(error.messages, field_name, index=index)
573
+ # When a Nested field fails validation, the marshalled data is stored
574
+ # on the ValidationError's valid_data attribute
575
+ return error.valid_data or missing
576
+ return value
577
+
578
+ def _serialize(self, obj: typing.Any, *, many: bool = False):
579
+ """Serialize ``obj``.
580
+
581
+ :param obj: The object(s) to serialize.
582
+ :param many: `True` if ``data`` should be serialized as a collection.
583
+ :return: A dictionary of the serialized data
584
+ """
585
+ if many and obj is not None:
586
+ return [self._serialize(d, many=False) for d in obj]
587
+ ret = self.dict_class()
588
+ for attr_name, field_obj in self.dump_fields.items():
589
+ value = field_obj.serialize(attr_name, obj, accessor=self.get_attribute)
590
+ if value is missing:
591
+ continue
592
+ key = field_obj.data_key if field_obj.data_key is not None else attr_name
593
+ ret[key] = value
594
+ return ret
595
+
596
+ def dump(self, obj: typing.Any, *, many: bool | None = None):
597
+ """Serialize an object to native Python data types according to this
598
+ Schema's fields.
599
+
600
+ :param obj: The object to serialize.
601
+ :param many: Whether to serialize `obj` as a collection. If `None`, the value
602
+ for `self.many` is used.
603
+ :return: Serialized data
604
+
605
+ .. versionadded:: 1.0.0
606
+ .. versionchanged:: 3.0.0b7
607
+ This method returns the serialized data rather than a ``(data, errors)`` duple.
608
+ A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
609
+ if ``obj`` is invalid.
610
+ .. versionchanged:: 3.0.0rc9
611
+ Validation no longer occurs upon serialization.
612
+ """
613
+ many = self.many if many is None else bool(many)
614
+ if self._hooks[PRE_DUMP]:
615
+ processed_obj = self._invoke_dump_processors(
616
+ PRE_DUMP, obj, many=many, original_data=obj
617
+ )
618
+ else:
619
+ processed_obj = obj
620
+
621
+ result = self._serialize(processed_obj, many=many)
622
+
623
+ if self._hooks[POST_DUMP]:
624
+ result = self._invoke_dump_processors(
625
+ POST_DUMP, result, many=many, original_data=obj
626
+ )
627
+
628
+ return result
629
+
630
+ def dumps(self, obj: typing.Any, *args, many: bool | None = None, **kwargs):
631
+ """Same as :meth:`dump`, except return a JSON-encoded string.
632
+
633
+ :param obj: The object to serialize.
634
+ :param many: Whether to serialize `obj` as a collection. If `None`, the value
635
+ for `self.many` is used.
636
+ :return: A ``json`` string
637
+
638
+ .. versionadded:: 1.0.0
639
+ .. versionchanged:: 3.0.0b7
640
+ This method returns the serialized data rather than a ``(data, errors)`` duple.
641
+ A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
642
+ if ``obj`` is invalid.
643
+ """
644
+ serialized = self.dump(obj, many=many)
645
+ return self.opts.render_module.dumps(serialized, *args, **kwargs)
646
+
647
+ def _deserialize(
648
+ self,
649
+ data: (
650
+ typing.Mapping[str, typing.Any]
651
+ | typing.Iterable[typing.Mapping[str, typing.Any]]
652
+ ),
653
+ *,
654
+ error_store: ErrorStore,
655
+ many: bool = False,
656
+ partial=None,
657
+ unknown=RAISE,
658
+ index=None,
659
+ ) -> typing.Any | list[typing.Any]:
660
+ """Deserialize ``data``.
661
+
662
+ :param data: The data to deserialize.
663
+ :param error_store: Structure to store errors.
664
+ :param many: `True` if ``data`` should be deserialized as a collection.
665
+ :param partial: Whether to ignore missing fields and not require
666
+ any fields declared. Propagates down to ``Nested`` fields as well. If
667
+ its value is an iterable, only missing fields listed in that iterable
668
+ will be ignored. Use dot delimiters to specify nested fields.
669
+ :param unknown: Whether to exclude, include, or raise an error for unknown
670
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
671
+ :param index: Index of the item being serialized (for storing errors) if
672
+ serializing a collection, otherwise `None`.
673
+ :return: The deserialized data as `dict_class` instance or list of `dict_class`
674
+ instances if `many` is `True`.
675
+ """
676
+ index_errors = self.opts.index_errors
677
+ index = index if index_errors else None
678
+ if many:
679
+ if not is_collection(data):
680
+ error_store.store_error([self.error_messages["type"]], index=index)
681
+ ret_l = []
682
+ else:
683
+ ret_l = [
684
+ self._deserialize(
685
+ typing.cast(dict, d),
686
+ error_store=error_store,
687
+ many=False,
688
+ partial=partial,
689
+ unknown=unknown,
690
+ index=idx,
691
+ )
692
+ for idx, d in enumerate(data)
693
+ ]
694
+ return ret_l
695
+ ret_d = self.dict_class()
696
+ # Check data is a dict
697
+ if not isinstance(data, Mapping):
698
+ error_store.store_error([self.error_messages["type"]], index=index)
699
+ else:
700
+ partial_is_collection = is_collection(partial)
701
+ for attr_name, field_obj in self.load_fields.items():
702
+ field_name = (
703
+ field_obj.data_key if field_obj.data_key is not None else attr_name
704
+ )
705
+ raw_value = data.get(field_name, missing)
706
+ if raw_value is missing:
707
+ # Ignore missing field if we're allowed to.
708
+ if partial is True or (
709
+ partial_is_collection and attr_name in partial
710
+ ):
711
+ continue
712
+ d_kwargs = {}
713
+ # Allow partial loading of nested schemas.
714
+ if partial_is_collection:
715
+ prefix = field_name + "."
716
+ len_prefix = len(prefix)
717
+ sub_partial = [
718
+ f[len_prefix:] for f in partial if f.startswith(prefix)
719
+ ]
720
+ d_kwargs["partial"] = sub_partial
721
+ elif partial is not None:
722
+ d_kwargs["partial"] = partial
723
+
724
+ def getter(
725
+ val, field_obj=field_obj, field_name=field_name, d_kwargs=d_kwargs
726
+ ):
727
+ return field_obj.deserialize(
728
+ val,
729
+ field_name,
730
+ data,
731
+ **d_kwargs,
732
+ )
733
+
734
+ value = self._call_and_store(
735
+ getter_func=getter,
736
+ data=raw_value,
737
+ field_name=field_name,
738
+ error_store=error_store,
739
+ index=index,
740
+ )
741
+ if value is not missing:
742
+ key = field_obj.attribute or attr_name
743
+ set_value(ret_d, key, value)
744
+ if unknown != EXCLUDE:
745
+ fields = {
746
+ field_obj.data_key if field_obj.data_key is not None else field_name
747
+ for field_name, field_obj in self.load_fields.items()
748
+ }
749
+ for key in set(data) - fields:
750
+ value = data[key]
751
+ if unknown == INCLUDE:
752
+ ret_d[key] = value
753
+ elif unknown == RAISE:
754
+ error_store.store_error(
755
+ [self.error_messages["unknown"]],
756
+ key,
757
+ (index if index_errors else None),
758
+ )
759
+ return ret_d
760
+
761
+ def load(
762
+ self,
763
+ data: (
764
+ typing.Mapping[str, typing.Any]
765
+ | typing.Iterable[typing.Mapping[str, typing.Any]]
766
+ ),
767
+ *,
768
+ many: bool | None = None,
769
+ partial: bool | types.StrSequenceOrSet | None = None,
770
+ unknown: str | None = None,
771
+ ):
772
+ """Deserialize a data structure to an object defined by this Schema's fields.
773
+
774
+ :param data: The data to deserialize.
775
+ :param many: Whether to deserialize `data` as a collection. If `None`, the
776
+ value for `self.many` is used.
777
+ :param partial: Whether to ignore missing fields and not require
778
+ any fields declared. Propagates down to ``Nested`` fields as well. If
779
+ its value is an iterable, only missing fields listed in that iterable
780
+ will be ignored. Use dot delimiters to specify nested fields.
781
+ :param unknown: Whether to exclude, include, or raise an error for unknown
782
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
783
+ If `None`, the value for `self.unknown` is used.
784
+ :return: Deserialized data
785
+
786
+ .. versionadded:: 1.0.0
787
+ .. versionchanged:: 3.0.0b7
788
+ This method returns the deserialized data rather than a ``(data, errors)`` duple.
789
+ A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
790
+ if invalid data are passed.
791
+ """
792
+ return self._do_load(
793
+ data, many=many, partial=partial, unknown=unknown, postprocess=True
794
+ )
795
+
796
+ def loads(
797
+ self,
798
+ json_data: str | bytes | bytearray,
799
+ *,
800
+ many: bool | None = None,
801
+ partial: bool | types.StrSequenceOrSet | None = None,
802
+ unknown: str | None = None,
803
+ **kwargs,
804
+ ):
805
+ """Same as :meth:`load`, except it uses `marshmallow.Schema.Meta.render_module` to deserialize
806
+ the passed string before passing data to :meth:`load`.
807
+
808
+ :param json_data: A string of the data to deserialize.
809
+ :param many: Whether to deserialize `obj` as a collection. If `None`, the
810
+ value for `self.many` is used.
811
+ :param partial: Whether to ignore missing fields and not require
812
+ any fields declared. Propagates down to ``Nested`` fields as well. If
813
+ its value is an iterable, only missing fields listed in that iterable
814
+ will be ignored. Use dot delimiters to specify nested fields.
815
+ :param unknown: Whether to exclude, include, or raise an error for unknown
816
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
817
+ If `None`, the value for `self.unknown` is used.
818
+ :return: Deserialized data
819
+
820
+ .. versionadded:: 1.0.0
821
+ .. versionchanged:: 3.0.0b7
822
+ This method returns the deserialized data rather than a ``(data, errors)`` duple.
823
+ A :exc:`ValidationError <marshmallow.exceptions.ValidationError>` is raised
824
+ if invalid data are passed.
825
+ """
826
+ data = self.opts.render_module.loads(json_data, **kwargs)
827
+ return self.load(data, many=many, partial=partial, unknown=unknown)
828
+
829
+ def _run_validator(
830
+ self,
831
+ validator_func: types.SchemaValidator,
832
+ output,
833
+ *,
834
+ original_data,
835
+ error_store: ErrorStore,
836
+ many: bool,
837
+ partial: bool | types.StrSequenceOrSet | None,
838
+ pass_original: bool,
839
+ index: int | None = None,
840
+ ):
841
+ try:
842
+ if pass_original: # Pass original, raw data (before unmarshalling)
843
+ validator_func(output, original_data, partial=partial, many=many)
844
+ else:
845
+ validator_func(output, partial=partial, many=many)
846
+ except ValidationError as err:
847
+ field_name = err.field_name
848
+ data_key: str
849
+ if field_name == SCHEMA:
850
+ data_key = SCHEMA
851
+ else:
852
+ field_obj: Field | None = None
853
+ try:
854
+ field_obj = self.fields[field_name]
855
+ except KeyError:
856
+ if field_name in self.declared_fields:
857
+ field_obj = self.declared_fields[field_name]
858
+ if field_obj:
859
+ data_key = (
860
+ field_obj.data_key
861
+ if field_obj.data_key is not None
862
+ else field_name
863
+ )
864
+ else:
865
+ data_key = field_name
866
+ error_store.store_error(err.messages, data_key, index=index)
867
+
868
+ def validate(
869
+ self,
870
+ data: (
871
+ typing.Mapping[str, typing.Any]
872
+ | typing.Iterable[typing.Mapping[str, typing.Any]]
873
+ ),
874
+ *,
875
+ many: bool | None = None,
876
+ partial: bool | types.StrSequenceOrSet | None = None,
877
+ ) -> dict[str, list[str]]:
878
+ """Validate `data` against the schema, returning a dictionary of
879
+ validation errors.
880
+
881
+ :param data: The data to validate.
882
+ :param many: Whether to validate `data` as a collection. If `None`, the
883
+ value for `self.many` is used.
884
+ :param partial: Whether to ignore missing fields and not require
885
+ any fields declared. Propagates down to ``Nested`` fields as well. If
886
+ its value is an iterable, only missing fields listed in that iterable
887
+ will be ignored. Use dot delimiters to specify nested fields.
888
+ :return: A dictionary of validation errors.
889
+
890
+ .. versionadded:: 1.1.0
891
+ """
892
+ try:
893
+ self._do_load(data, many=many, partial=partial, postprocess=False)
894
+ except ValidationError as exc:
895
+ return typing.cast(dict[str, list[str]], exc.messages)
896
+ return {}
897
+
898
+ ##### Private Helpers #####
899
+
900
+ def _do_load(
901
+ self,
902
+ data: (
903
+ typing.Mapping[str, typing.Any]
904
+ | typing.Iterable[typing.Mapping[str, typing.Any]]
905
+ ),
906
+ *,
907
+ many: bool | None = None,
908
+ partial: bool | types.StrSequenceOrSet | None = None,
909
+ unknown: str | None = None,
910
+ postprocess: bool = True,
911
+ ):
912
+ """Deserialize `data`, returning the deserialized result.
913
+ This method is private API.
914
+
915
+ :param data: The data to deserialize.
916
+ :param many: Whether to deserialize `data` as a collection. If `None`, the
917
+ value for `self.many` is used.
918
+ :param partial: Whether to validate required fields. If its
919
+ value is an iterable, only fields listed in that iterable will be
920
+ ignored will be allowed missing. If `True`, all fields will be allowed missing.
921
+ If `None`, the value for `self.partial` is used.
922
+ :param unknown: Whether to exclude, include, or raise an error for unknown
923
+ fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.
924
+ If `None`, the value for `self.unknown` is used.
925
+ :param postprocess: Whether to run post_load methods..
926
+ :return: Deserialized data
927
+ """
928
+ error_store = ErrorStore()
929
+ errors: dict[str, list[str]] = {}
930
+ many = self.many if many is None else bool(many)
931
+ unknown = (
932
+ self.unknown
933
+ if unknown is None
934
+ else validate_unknown_parameter_value(unknown)
935
+ )
936
+ if partial is None:
937
+ partial = self.partial
938
+ # Run preprocessors
939
+ if self._hooks[PRE_LOAD]:
940
+ try:
941
+ processed_data = self._invoke_load_processors(
942
+ PRE_LOAD, data, many=many, original_data=data, partial=partial
943
+ )
944
+ except ValidationError as err:
945
+ errors = err.normalized_messages()
946
+ result: list | dict | None = None
947
+ else:
948
+ processed_data = data
949
+ if not errors:
950
+ # Deserialize data
951
+ result = self._deserialize(
952
+ processed_data,
953
+ error_store=error_store,
954
+ many=many,
955
+ partial=partial,
956
+ unknown=unknown,
957
+ )
958
+ # Run field-level validation
959
+ self._invoke_field_validators(
960
+ error_store=error_store, data=result, many=many
961
+ )
962
+ # Run schema-level validation
963
+ if self._hooks[VALIDATES_SCHEMA]:
964
+ field_errors = bool(error_store.errors)
965
+ self._invoke_schema_validators(
966
+ error_store=error_store,
967
+ pass_many=True,
968
+ data=result,
969
+ original_data=data,
970
+ many=many,
971
+ partial=partial,
972
+ field_errors=field_errors,
973
+ )
974
+ self._invoke_schema_validators(
975
+ error_store=error_store,
976
+ pass_many=False,
977
+ data=result,
978
+ original_data=data,
979
+ many=many,
980
+ partial=partial,
981
+ field_errors=field_errors,
982
+ )
983
+ errors = error_store.errors
984
+ # Run post processors
985
+ if not errors and postprocess and self._hooks[POST_LOAD]:
986
+ try:
987
+ result = self._invoke_load_processors(
988
+ POST_LOAD,
989
+ result,
990
+ many=many,
991
+ original_data=data,
992
+ partial=partial,
993
+ )
994
+ except ValidationError as err:
995
+ errors = err.normalized_messages()
996
+ if errors:
997
+ exc = ValidationError(errors, data=data, valid_data=result)
998
+ self.handle_error(exc, data, many=many, partial=partial)
999
+ raise exc
1000
+
1001
+ return result
1002
+
1003
+ def _normalize_nested_options(self) -> None:
1004
+ """Apply then flatten nested schema options.
1005
+ This method is private API.
1006
+ """
1007
+ if self.only is not None:
1008
+ # Apply the only option to nested fields.
1009
+ self.__apply_nested_option("only", self.only, "intersection")
1010
+ # Remove the child field names from the only option.
1011
+ self.only = self.set_class([field.split(".", 1)[0] for field in self.only])
1012
+ if self.exclude:
1013
+ # Apply the exclude option to nested fields.
1014
+ self.__apply_nested_option("exclude", self.exclude, "union")
1015
+ # Remove the parent field names from the exclude option.
1016
+ self.exclude = self.set_class(
1017
+ [field for field in self.exclude if "." not in field]
1018
+ )
1019
+
1020
+ def __apply_nested_option(self, option_name, field_names, set_operation) -> None:
1021
+ """Apply nested options to nested fields"""
1022
+ # Split nested field names on the first dot.
1023
+ nested_fields = [name.split(".", 1) for name in field_names if "." in name]
1024
+ # Partition the nested field names by parent field.
1025
+ nested_options = defaultdict(list) # type: defaultdict
1026
+ for parent, nested_names in nested_fields:
1027
+ nested_options[parent].append(nested_names)
1028
+ # Apply the nested field options.
1029
+ for key, options in iter(nested_options.items()):
1030
+ new_options = self.set_class(options)
1031
+ original_options = getattr(self.declared_fields[key], option_name, ())
1032
+ if original_options:
1033
+ if set_operation == "union":
1034
+ new_options |= self.set_class(original_options)
1035
+ if set_operation == "intersection":
1036
+ new_options &= self.set_class(original_options)
1037
+ setattr(self.declared_fields[key], option_name, new_options)
1038
+
1039
+ def _init_fields(self) -> None:
1040
+ """Update self.fields, self.load_fields, and self.dump_fields based on schema options.
1041
+ This method is private API.
1042
+ """
1043
+ if self.opts.fields:
1044
+ available_field_names = self.set_class(self.opts.fields)
1045
+ else:
1046
+ available_field_names = self.set_class(self.declared_fields.keys())
1047
+ if self.opts.additional:
1048
+ available_field_names |= self.set_class(self.opts.additional)
1049
+
1050
+ invalid_fields = self.set_class()
1051
+
1052
+ if self.only is not None:
1053
+ # Return only fields specified in only option
1054
+ field_names: typing.AbstractSet[typing.Any] = self.set_class(self.only)
1055
+
1056
+ invalid_fields |= field_names - available_field_names
1057
+ else:
1058
+ field_names = available_field_names
1059
+
1060
+ # If "exclude" option or param is specified, remove those fields.
1061
+ if self.exclude:
1062
+ # Note that this isn't available_field_names, since we want to
1063
+ # apply "only" for the actual calculation.
1064
+ field_names = field_names - self.exclude
1065
+ invalid_fields |= self.exclude - available_field_names
1066
+
1067
+ if invalid_fields:
1068
+ message = f"Invalid fields for {self}: {invalid_fields}."
1069
+ raise ValueError(message)
1070
+
1071
+ fields_dict = self.dict_class()
1072
+ for field_name in field_names:
1073
+ field_obj = self.declared_fields.get(field_name, ma_fields.Inferred())
1074
+ self._bind_field(field_name, field_obj)
1075
+ fields_dict[field_name] = field_obj
1076
+
1077
+ load_fields, dump_fields = self.dict_class(), self.dict_class()
1078
+ for field_name, field_obj in fields_dict.items():
1079
+ if not field_obj.dump_only:
1080
+ load_fields[field_name] = field_obj
1081
+ if not field_obj.load_only:
1082
+ dump_fields[field_name] = field_obj
1083
+
1084
+ dump_data_keys = [
1085
+ field_obj.data_key if field_obj.data_key is not None else name
1086
+ for name, field_obj in dump_fields.items()
1087
+ ]
1088
+ if len(dump_data_keys) != len(set(dump_data_keys)):
1089
+ data_keys_duplicates = {
1090
+ x for x in dump_data_keys if dump_data_keys.count(x) > 1
1091
+ }
1092
+ raise ValueError(
1093
+ "The data_key argument for one or more fields collides "
1094
+ "with another field's name or data_key argument. "
1095
+ "Check the following field names and "
1096
+ f"data_key arguments: {list(data_keys_duplicates)}"
1097
+ )
1098
+ load_attributes = [obj.attribute or name for name, obj in load_fields.items()]
1099
+ if len(load_attributes) != len(set(load_attributes)):
1100
+ attributes_duplicates = {
1101
+ x for x in load_attributes if load_attributes.count(x) > 1
1102
+ }
1103
+ raise ValueError(
1104
+ "The attribute argument for one or more fields collides "
1105
+ "with another field's name or attribute argument. "
1106
+ "Check the following field names and "
1107
+ f"attribute arguments: {list(attributes_duplicates)}"
1108
+ )
1109
+
1110
+ self.fields = fields_dict
1111
+ self.dump_fields = dump_fields
1112
+ self.load_fields = load_fields
1113
+
1114
+ def on_bind_field(self, field_name: str, field_obj: Field) -> None:
1115
+ """Hook to modify a field when it is bound to the `Schema <marshmallow.Schema>`.
1116
+
1117
+ No-op by default.
1118
+ """
1119
+ return
1120
+
1121
+ def _bind_field(self, field_name: str, field_obj: Field) -> None:
1122
+ """Bind field to the schema, setting any necessary attributes on the
1123
+ field (e.g. parent and name).
1124
+
1125
+ Also set field load_only and dump_only values if field_name was
1126
+ specified in `class Meta <marshmallow.Schema.Meta>`.
1127
+ """
1128
+ if field_name in self.load_only:
1129
+ field_obj.load_only = True
1130
+ if field_name in self.dump_only:
1131
+ field_obj.dump_only = True
1132
+ try:
1133
+ field_obj._bind_to_schema(field_name, self) # noqa: SLF001
1134
+ except TypeError as error:
1135
+ # Field declared as a class, not an instance. Ignore type checking because
1136
+ # we handle unsupported arg types, i.e. this is dead code from
1137
+ # the type checker's perspective.
1138
+ if isinstance(field_obj, type) and issubclass(field_obj, base.FieldABC):
1139
+ msg = (
1140
+ f'Field for "{field_name}" must be declared as a '
1141
+ "Field instance, not a class. "
1142
+ f'Did you mean "fields.{field_obj.__name__}()"?' # type: ignore[attr-defined]
1143
+ )
1144
+ raise TypeError(msg) from error
1145
+ raise
1146
+ self.on_bind_field(field_name, field_obj)
1147
+
1148
+ def _invoke_dump_processors(
1149
+ self, tag: str, data, *, many: bool, original_data=None
1150
+ ):
1151
+ # The pass_many post-dump processors may do things like add an envelope, so
1152
+ # invoke those after invoking the non-pass_many processors which will expect
1153
+ # to get a list of items.
1154
+ data = self._invoke_processors(
1155
+ tag, pass_many=False, data=data, many=many, original_data=original_data
1156
+ )
1157
+ return self._invoke_processors(
1158
+ tag, pass_many=True, data=data, many=many, original_data=original_data
1159
+ )
1160
+
1161
+ def _invoke_load_processors(
1162
+ self,
1163
+ tag: str,
1164
+ data,
1165
+ *,
1166
+ many: bool,
1167
+ original_data,
1168
+ partial: bool | types.StrSequenceOrSet | None,
1169
+ ):
1170
+ # This has to invert the order of the dump processors, so run the pass_many
1171
+ # processors first.
1172
+ data = self._invoke_processors(
1173
+ tag,
1174
+ pass_many=True,
1175
+ data=data,
1176
+ many=many,
1177
+ original_data=original_data,
1178
+ partial=partial,
1179
+ )
1180
+ return self._invoke_processors(
1181
+ tag,
1182
+ pass_many=False,
1183
+ data=data,
1184
+ many=many,
1185
+ original_data=original_data,
1186
+ partial=partial,
1187
+ )
1188
+
1189
+ def _invoke_field_validators(self, *, error_store: ErrorStore, data, many: bool):
1190
+ for attr_name, _, validator_kwargs in self._hooks[VALIDATES]:
1191
+ validator = getattr(self, attr_name)
1192
+ field_name = validator_kwargs["field_name"]
1193
+
1194
+ try:
1195
+ field_obj = self.fields[field_name]
1196
+ except KeyError as error:
1197
+ if field_name in self.declared_fields:
1198
+ continue
1199
+ raise ValueError(f'"{field_name}" field does not exist.') from error
1200
+
1201
+ data_key = (
1202
+ field_obj.data_key if field_obj.data_key is not None else field_name
1203
+ )
1204
+ if many:
1205
+ for idx, item in enumerate(data):
1206
+ try:
1207
+ value = item[field_obj.attribute or field_name]
1208
+ except KeyError:
1209
+ pass
1210
+ else:
1211
+ validated_value = self._call_and_store(
1212
+ getter_func=validator,
1213
+ data=value,
1214
+ field_name=data_key,
1215
+ error_store=error_store,
1216
+ index=(idx if self.opts.index_errors else None),
1217
+ )
1218
+ if validated_value is missing:
1219
+ item.pop(field_name, None)
1220
+ else:
1221
+ try:
1222
+ value = data[field_obj.attribute or field_name]
1223
+ except KeyError:
1224
+ pass
1225
+ else:
1226
+ validated_value = self._call_and_store(
1227
+ getter_func=validator,
1228
+ data=value,
1229
+ field_name=data_key,
1230
+ error_store=error_store,
1231
+ )
1232
+ if validated_value is missing:
1233
+ data.pop(field_name, None)
1234
+
1235
+ def _invoke_schema_validators(
1236
+ self,
1237
+ *,
1238
+ error_store: ErrorStore,
1239
+ pass_many: bool,
1240
+ data,
1241
+ original_data,
1242
+ many: bool,
1243
+ partial: bool | types.StrSequenceOrSet | None,
1244
+ field_errors: bool = False,
1245
+ ):
1246
+ for attr_name, hook_many, validator_kwargs in self._hooks[VALIDATES_SCHEMA]:
1247
+ if hook_many != pass_many:
1248
+ continue
1249
+ validator = getattr(self, attr_name)
1250
+ if field_errors and validator_kwargs["skip_on_field_errors"]:
1251
+ continue
1252
+ pass_original = validator_kwargs.get("pass_original", False)
1253
+
1254
+ if many and not pass_many:
1255
+ for idx, (item, orig) in enumerate(zip(data, original_data)):
1256
+ self._run_validator(
1257
+ validator,
1258
+ item,
1259
+ original_data=orig,
1260
+ error_store=error_store,
1261
+ many=many,
1262
+ partial=partial,
1263
+ index=idx,
1264
+ pass_original=pass_original,
1265
+ )
1266
+ else:
1267
+ self._run_validator(
1268
+ validator,
1269
+ data,
1270
+ original_data=original_data,
1271
+ error_store=error_store,
1272
+ many=many,
1273
+ pass_original=pass_original,
1274
+ partial=partial,
1275
+ )
1276
+
1277
+ def _invoke_processors(
1278
+ self,
1279
+ tag: str,
1280
+ *,
1281
+ pass_many: bool,
1282
+ data,
1283
+ many: bool,
1284
+ original_data=None,
1285
+ **kwargs,
1286
+ ):
1287
+ for attr_name, hook_many, processor_kwargs in self._hooks[tag]:
1288
+ if hook_many != pass_many:
1289
+ continue
1290
+ # This will be a bound method.
1291
+ processor = getattr(self, attr_name)
1292
+ pass_original = processor_kwargs.get("pass_original", False)
1293
+
1294
+ if many and not pass_many:
1295
+ if pass_original:
1296
+ data = [
1297
+ processor(item, original, many=many, **kwargs)
1298
+ for item, original in zip_longest(data, original_data)
1299
+ ]
1300
+ else:
1301
+ data = [processor(item, many=many, **kwargs) for item in data]
1302
+ elif pass_original:
1303
+ data = processor(data, original_data, many=many, **kwargs)
1304
+ else:
1305
+ data = processor(data, many=many, **kwargs)
1306
+ return data
1307
+
1308
+
1309
+ BaseSchema = Schema # for backwards compatibility