marshmallow 3.25.1__py3-none-any.whl → 3.26.1__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/__init__.py CHANGED
@@ -68,14 +68,14 @@ __all__ = [
68
68
  "RAISE",
69
69
  "Schema",
70
70
  "SchemaOpts",
71
+ "ValidationError",
71
72
  "fields",
72
- "validates",
73
- "validates_schema",
74
- "pre_dump",
73
+ "missing",
75
74
  "post_dump",
76
- "pre_load",
77
75
  "post_load",
78
76
  "pprint",
79
- "ValidationError",
80
- "missing",
77
+ "pre_dump",
78
+ "pre_load",
79
+ "validates",
80
+ "validates_schema",
81
81
  ]
@@ -7,6 +7,7 @@ class:`fields.Nested <marshmallow.fields.Nested>`.
7
7
  This module is treated as private API.
8
8
  Users should not need to use this module directly.
9
9
  """
10
+ # ruff: noqa: ERA001
10
11
 
11
12
  from __future__ import annotations
12
13
 
@@ -49,7 +50,7 @@ def register(classname: str, cls: SchemaType) -> None:
49
50
  module = cls.__module__
50
51
  # Full module path to the class
51
52
  # e.g. user.schemas.UserSchema
52
- fullpath = ".".join([module, classname])
53
+ fullpath = f"{module}.{classname}"
53
54
  # If the class is already registered; need to check if the entries are
54
55
  # in the same module as cls to avoid having multiple instances of the same
55
56
  # class in the registry
@@ -66,18 +67,19 @@ def register(classname: str, cls: SchemaType) -> None:
66
67
  else:
67
68
  # If fullpath does exist, replace existing entry
68
69
  _registry[fullpath] = [cls]
69
- return None
70
70
 
71
71
 
72
72
  @typing.overload
73
- def get_class(classname: str, all: typing.Literal[False] = ...) -> SchemaType: ...
73
+ def get_class(classname: str, *, all: typing.Literal[False] = ...) -> SchemaType: ...
74
74
 
75
75
 
76
76
  @typing.overload
77
- def get_class(classname: str, all: typing.Literal[True] = ...) -> list[SchemaType]: ...
77
+ def get_class(
78
+ classname: str, *, all: typing.Literal[True] = ...
79
+ ) -> list[SchemaType]: ...
78
80
 
79
81
 
80
- def get_class(classname: str, all: bool = False) -> list[SchemaType] | SchemaType:
82
+ def get_class(classname: str, *, all: bool = False) -> list[SchemaType] | SchemaType: # noqa: A002
81
83
  """Retrieve a class from the registry.
82
84
 
83
85
  :raises: `marshmallow.exceptions.RegistryError` if the class cannot be found
@@ -98,5 +100,4 @@ def get_class(classname: str, all: bool = False) -> list[SchemaType] | SchemaTyp
98
100
  "were found. Please use the full, "
99
101
  "module-qualified path."
100
102
  )
101
- else:
102
- return _registry[classname][0]
103
+ return _registry[classname][0]
marshmallow/decorators.py CHANGED
@@ -93,9 +93,9 @@ def validates(field_name: str) -> Callable[..., Any]:
93
93
 
94
94
  def validates_schema(
95
95
  fn: Callable[..., Any] | None = None,
96
- pass_many: bool = False,
97
- pass_original: bool = False,
98
- skip_on_field_errors: bool = True,
96
+ pass_many: bool = False, # noqa: FBT001, FBT002
97
+ pass_original: bool = False, # noqa: FBT001, FBT002
98
+ skip_on_field_errors: bool = True, # noqa: FBT001, FBT002
99
99
  ) -> Callable[..., Any]:
100
100
  """Register a schema-level validator.
101
101
 
@@ -126,7 +126,8 @@ def validates_schema(
126
126
 
127
127
 
128
128
  def pre_dump(
129
- fn: Callable[..., Any] | None = None, pass_many: bool = False
129
+ fn: Callable[..., Any] | None = None,
130
+ pass_many: bool = False, # noqa: FBT001, FBT002
130
131
  ) -> Callable[..., Any]:
131
132
  """Register a method to invoke before serializing an object. The method
132
133
  receives the object to be serialized and returns the processed object.
@@ -143,8 +144,8 @@ def pre_dump(
143
144
 
144
145
  def post_dump(
145
146
  fn: Callable[..., Any] | None = None,
146
- pass_many: bool = False,
147
- pass_original: bool = False,
147
+ pass_many: bool = False, # noqa: FBT001, FBT002
148
+ pass_original: bool = False, # noqa: FBT001, FBT002
148
149
  ) -> Callable[..., Any]:
149
150
  """Register a method to invoke after serializing an object. The method
150
151
  receives the serialized object and returns the processed object.
@@ -163,7 +164,8 @@ def post_dump(
163
164
 
164
165
 
165
166
  def pre_load(
166
- fn: Callable[..., Any] | None = None, pass_many: bool = False
167
+ fn: Callable[..., Any] | None = None,
168
+ pass_many: bool = False, # noqa: FBT001, FBT002
167
169
  ) -> Callable[..., Any]:
168
170
  """Register a method to invoke before deserializing an object. The method
169
171
  receives the data to be deserialized and returns the processed data.
@@ -181,8 +183,8 @@ def pre_load(
181
183
 
182
184
  def post_load(
183
185
  fn: Callable[..., Any] | None = None,
184
- pass_many: bool = False,
185
- pass_original: bool = False,
186
+ pass_many: bool = False, # noqa: FBT001, FBT002
187
+ pass_original: bool = False, # noqa: FBT001, FBT002
186
188
  ) -> Callable[..., Any]:
187
189
  """Register a method to invoke after deserializing an object. The method
188
190
  receives the deserialized data and returns the processed data.
@@ -202,7 +204,10 @@ def post_load(
202
204
 
203
205
 
204
206
  def set_hook(
205
- fn: Callable[..., Any] | None, tag: str, many: bool = False, **kwargs: Any
207
+ fn: Callable[..., Any] | None,
208
+ tag: str,
209
+ many: bool = False, # noqa: FBT001, FBT002
210
+ **kwargs: Any,
206
211
  ) -> Callable[..., Any]:
207
212
  """Mark decorated function as a hook to be picked up later.
208
213
  You should not need to use this method directly.
@@ -25,7 +25,7 @@ class ErrorStore:
25
25
  self.errors = merge_errors(self.errors, messages)
26
26
 
27
27
 
28
- def merge_errors(errors1, errors2):
28
+ def merge_errors(errors1, errors2): # noqa: PLR0911
29
29
  """Deeply merge two error messages.
30
30
 
31
31
  The format of ``errors1`` and ``errors2`` matches the ``message``
@@ -40,7 +40,7 @@ def merge_errors(errors1, errors2):
40
40
  return errors1 + errors2
41
41
  if isinstance(errors2, dict):
42
42
  return dict(errors2, **{SCHEMA: merge_errors(errors1, errors2.get(SCHEMA))})
43
- return errors1 + [errors2]
43
+ return [*errors1, errors2]
44
44
  if isinstance(errors1, dict):
45
45
  if isinstance(errors2, list):
46
46
  return dict(errors1, **{SCHEMA: merge_errors(errors1.get(SCHEMA), errors2)})
@@ -54,7 +54,7 @@ def merge_errors(errors1, errors2):
54
54
  return errors
55
55
  return dict(errors1, **{SCHEMA: merge_errors(errors1.get(SCHEMA), errors2)})
56
56
  if isinstance(errors2, list):
57
- return [errors1] + errors2
57
+ return [errors1, *errors2]
58
58
  if isinstance(errors2, dict):
59
59
  return dict(errors2, **{SCHEMA: merge_errors(errors1, errors2.get(SCHEMA))})
60
60
  return [errors1, errors2]
marshmallow/fields.py CHANGED
@@ -1,3 +1,4 @@
1
+ # ruff: noqa: F841, SLF001
1
2
  from __future__ import annotations
2
3
 
3
4
  import collections
@@ -11,7 +12,6 @@ import typing
11
12
  import uuid
12
13
  import warnings
13
14
  from collections.abc import Mapping as _Mapping
14
- from enum import Enum as EnumType
15
15
 
16
16
  from marshmallow import class_registry, types, utils, validate
17
17
  from marshmallow.base import FieldABC
@@ -35,47 +35,49 @@ from marshmallow.warnings import (
35
35
  )
36
36
 
37
37
  if typing.TYPE_CHECKING:
38
+ from enum import Enum as EnumType
39
+
38
40
  from marshmallow.schema import Schema, SchemaMeta
39
41
 
40
42
 
41
43
  __all__ = [
42
- "Field",
43
- "Raw",
44
- "Nested",
45
- "Mapping",
46
- "Dict",
47
- "List",
48
- "Tuple",
49
- "String",
44
+ "IP",
45
+ "URL",
50
46
  "UUID",
51
- "Number",
52
- "Integer",
53
- "Decimal",
54
- "Boolean",
55
- "Float",
56
- "DateTime",
57
- "NaiveDateTime",
58
47
  "AwareDateTime",
59
- "Time",
48
+ "Bool",
49
+ "Boolean",
50
+ "Constant",
60
51
  "Date",
61
- "TimeDelta",
62
- "Url",
63
- "URL",
52
+ "DateTime",
53
+ "Decimal",
54
+ "Dict",
64
55
  "Email",
65
- "IP",
66
- "IPv4",
67
- "IPv6",
56
+ "Enum",
57
+ "Field",
58
+ "Float",
59
+ "Function",
68
60
  "IPInterface",
61
+ "IPv4",
69
62
  "IPv4Interface",
63
+ "IPv6",
70
64
  "IPv6Interface",
71
- "Enum",
72
- "Method",
73
- "Function",
74
- "Str",
75
- "Bool",
76
65
  "Int",
77
- "Constant",
66
+ "Integer",
67
+ "List",
68
+ "Mapping",
69
+ "Method",
70
+ "NaiveDateTime",
71
+ "Nested",
72
+ "Number",
78
73
  "Pluck",
74
+ "Raw",
75
+ "Str",
76
+ "String",
77
+ "Time",
78
+ "TimeDelta",
79
+ "Tuple",
80
+ "Url",
79
81
  ]
80
82
 
81
83
 
@@ -498,7 +500,9 @@ class Nested(Field):
498
500
  name = fields.Str()
499
501
  # Use lambda functions when you need two-way nesting or self-nesting
500
502
  parent = fields.Nested(lambda: ParentSchema(only=("id",)), dump_only=True)
501
- siblings = fields.List(fields.Nested(lambda: ChildSchema(only=("id", "name"))))
503
+ siblings = fields.List(
504
+ fields.Nested(lambda: ChildSchema(only=("id", "name")))
505
+ )
502
506
 
503
507
 
504
508
  class ParentSchema(Schema):
@@ -671,7 +675,7 @@ class Nested(Field):
671
675
  self,
672
676
  value: typing.Any,
673
677
  attr: str | None,
674
- data: typing.Mapping[str, typing.Any] | None = None,
678
+ data: typing.Mapping[str, typing.Any] | None,
675
679
  partial: bool | types.StrSequenceOrSet | None = None,
676
680
  **kwargs,
677
681
  ) -> typing.Any:
@@ -843,7 +847,7 @@ class Tuple(Field):
843
847
  super().__init__(**kwargs)
844
848
  if not utils.is_collection(tuple_fields):
845
849
  raise ValueError(
846
- "tuple_fields must be an iterable of Field classes or " "instances."
850
+ "tuple_fields must be an iterable of Field classes or instances."
847
851
  )
848
852
 
849
853
  try:
@@ -863,9 +867,9 @@ class Tuple(Field):
863
867
  super()._bind_to_schema(field_name, schema)
864
868
  new_tuple_fields = []
865
869
  for field in self.tuple_fields:
866
- field = copy.deepcopy(field)
867
- field._bind_to_schema(field_name, self)
868
- new_tuple_fields.append(field)
870
+ new_field = copy.deepcopy(field)
871
+ new_field._bind_to_schema(field_name, self)
872
+ new_tuple_fields.append(new_field)
869
873
 
870
874
  self.tuple_fields = new_tuple_fields
871
875
 
@@ -1294,7 +1298,7 @@ class DateTime(Field):
1294
1298
  "format": '"{input}" cannot be formatted as a {obj_type}.',
1295
1299
  }
1296
1300
 
1297
- def __init__(self, format: str | None = None, **kwargs) -> None:
1301
+ def __init__(self, format: str | None = None, **kwargs) -> None: # noqa: A002
1298
1302
  super().__init__(**kwargs)
1299
1303
  # Allow this to be None. It may be set later in the ``_serialize``
1300
1304
  # or ``_deserialize`` methods. This allows a Schema to dynamically set the
@@ -1352,7 +1356,7 @@ class NaiveDateTime(DateTime):
1352
1356
 
1353
1357
  def __init__(
1354
1358
  self,
1355
- format: str | None = None,
1359
+ format: str | None = None, # noqa: A002
1356
1360
  *,
1357
1361
  timezone: dt.timezone | None = None,
1358
1362
  **kwargs,
@@ -1389,7 +1393,7 @@ class AwareDateTime(DateTime):
1389
1393
 
1390
1394
  def __init__(
1391
1395
  self,
1392
- format: str | None = None,
1396
+ format: str | None = None, # noqa: A002
1393
1397
  *,
1394
1398
  default_timezone: dt.tzinfo | None = None,
1395
1399
  **kwargs,
@@ -1548,7 +1552,7 @@ class TimeDelta(Field):
1548
1552
  delta = utils.timedelta_to_microseconds(value)
1549
1553
  unit = utils.timedelta_to_microseconds(base_unit)
1550
1554
  return delta // unit
1551
- assert self.serialization_type is float
1555
+ assert self.serialization_type is float # noqa: S101
1552
1556
  return value.total_seconds() / base_unit.total_seconds()
1553
1557
 
1554
1558
  def _deserialize(self, value, attr, data, **kwargs):
@@ -1643,16 +1647,15 @@ class Mapping(Field):
1643
1647
  if not self.value_field and not self.key_field:
1644
1648
  return self.mapping_type(value)
1645
1649
 
1646
- #  Serialize keys
1650
+ # Serialize keys
1647
1651
  if self.key_field is None:
1648
- keys = {k: k for k in value.keys()}
1652
+ keys = {k: k for k in value}
1649
1653
  else:
1650
1654
  keys = {
1651
- k: self.key_field._serialize(k, None, None, **kwargs)
1652
- for k in value.keys()
1655
+ k: self.key_field._serialize(k, None, None, **kwargs) for k in value
1653
1656
  }
1654
1657
 
1655
- #  Serialize values
1658
+ # Serialize values
1656
1659
  result = self.mapping_type()
1657
1660
  if self.value_field is None:
1658
1661
  for k, v in value.items():
@@ -1672,18 +1675,18 @@ class Mapping(Field):
1672
1675
 
1673
1676
  errors = collections.defaultdict(dict)
1674
1677
 
1675
- #  Deserialize keys
1678
+ # Deserialize keys
1676
1679
  if self.key_field is None:
1677
- keys = {k: k for k in value.keys()}
1680
+ keys = {k: k for k in value}
1678
1681
  else:
1679
1682
  keys = {}
1680
- for key in value.keys():
1683
+ for key in value:
1681
1684
  try:
1682
1685
  keys[key] = self.key_field.deserialize(key, **kwargs)
1683
1686
  except ValidationError as error:
1684
1687
  errors[key]["key"] = error.messages
1685
1688
 
1686
- #  Deserialize values
1689
+ # Deserialize values
1687
1690
  result = self.mapping_type()
1688
1691
  if self.value_field is None:
1689
1692
  for k, v in value.items():
marshmallow/orderedset.py CHANGED
@@ -45,7 +45,7 @@ class OrderedSet(MutableSet):
45
45
 
46
46
  def discard(self, key):
47
47
  if key in self.map:
48
- key, prev, next = self.map.pop(key)
48
+ key, prev, next = self.map.pop(key) # noqa: A001
49
49
  prev[2] = next
50
50
  next[1] = prev
51
51
 
marshmallow/schema.py CHANGED
@@ -1,18 +1,21 @@
1
- """The `Schema <marshmallow.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
@@ -63,8 +69,11 @@ def _get_fields_by_mro(klass: SchemaMeta):
63
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 `Schema <marshmallow.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,90 @@ 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[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`.
358
435
  """
359
436
 
360
437
  def __init__(
@@ -400,9 +477,9 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
400
477
  self.context = context or {}
401
478
  self._normalize_nested_options()
402
479
  #: 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] = {}
480
+ self.fields: dict[str, Field] = {}
481
+ self.load_fields: dict[str, Field] = {}
482
+ self.dump_fields: dict[str, Field] = {}
406
483
  self._init_fields()
407
484
  messages = {}
408
485
  messages.update(self._default_error_messages)
@@ -416,15 +493,15 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
416
493
 
417
494
  @property
418
495
  def dict_class(self) -> type[dict]:
496
+ """`dict` type to return when serializing."""
419
497
  if self.ordered:
420
498
  return OrderedDict
421
- else:
422
- return dict
499
+ return dict
423
500
 
424
501
  @classmethod
425
502
  def from_dict(
426
503
  cls,
427
- fields: dict[str, ma_fields.Field],
504
+ fields: dict[str, Field],
428
505
  *,
429
506
  name: str = "GeneratedSchema",
430
507
  ) -> type[Schema]:
@@ -450,8 +527,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
450
527
  Meta = type(
451
528
  "GeneratedMeta", (getattr(cls, "Meta", object),), {"register": False}
452
529
  )
453
- schema_cls = type(name, (cls,), {**fields.copy(), "Meta": Meta})
454
- return schema_cls
530
+ return type(name, (cls,), {**fields.copy(), "Meta": Meta})
455
531
 
456
532
  ##### Override-able methods #####
457
533
 
@@ -468,7 +544,6 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
468
544
  .. versionchanged:: 3.0.0rc9
469
545
  Receives `many` and `partial` (on deserialization) as keyword arguments.
470
546
  """
471
- pass
472
547
 
473
548
  def get_attribute(self, obj: typing.Any, attr: str, default: typing.Any):
474
549
  """Defines how to pull values from an object to serialize.
@@ -720,16 +795,17 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
720
795
 
721
796
  def loads(
722
797
  self,
723
- json_data: str,
798
+ json_data: str | bytes | bytearray,
724
799
  *,
725
800
  many: bool | None = None,
726
801
  partial: bool | types.StrSequenceOrSet | None = None,
727
802
  unknown: str | None = None,
728
803
  **kwargs,
729
804
  ):
730
- """Same as :meth:`load`, except it takes a JSON string as input.
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`.
731
807
 
732
- :param json_data: A JSON string of the data to deserialize.
808
+ :param json_data: A string of the data to deserialize.
733
809
  :param many: Whether to deserialize `obj` as a collection. If `None`, the
734
810
  value for `self.many` is used.
735
811
  :param partial: Whether to ignore missing fields and not require
@@ -752,15 +828,15 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
752
828
 
753
829
  def _run_validator(
754
830
  self,
755
- validator_func,
831
+ validator_func: types.SchemaValidator,
756
832
  output,
757
833
  *,
758
834
  original_data,
759
- error_store,
760
- many,
761
- partial,
762
- pass_original,
763
- index=None,
835
+ error_store: ErrorStore,
836
+ many: bool,
837
+ partial: bool | types.StrSequenceOrSet | None,
838
+ pass_original: bool,
839
+ index: int | None = None,
764
840
  ):
765
841
  try:
766
842
  if pass_original: # Pass original, raw data (before unmarshalling)
@@ -768,7 +844,26 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
768
844
  else:
769
845
  validator_func(output, partial=partial, many=many)
770
846
  except ValidationError as err:
771
- error_store.store_error(err.messages, err.field_name, index=index)
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)
772
867
 
773
868
  def validate(
774
869
  self,
@@ -1016,26 +1111,26 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1016
1111
  self.dump_fields = dump_fields
1017
1112
  self.load_fields = load_fields
1018
1113
 
1019
- def on_bind_field(self, field_name: str, field_obj: ma_fields.Field) -> None:
1114
+ def on_bind_field(self, field_name: str, field_obj: Field) -> None:
1020
1115
  """Hook to modify a field when it is bound to the `Schema <marshmallow.Schema>`.
1021
1116
 
1022
1117
  No-op by default.
1023
1118
  """
1024
- return None
1119
+ return
1025
1120
 
1026
- def _bind_field(self, field_name: str, field_obj: ma_fields.Field) -> None:
1121
+ def _bind_field(self, field_name: str, field_obj: Field) -> None:
1027
1122
  """Bind field to the schema, setting any necessary attributes on the
1028
1123
  field (e.g. parent and name).
1029
1124
 
1030
1125
  Also set field load_only and dump_only values if field_name was
1031
- specified in ``class Meta``.
1126
+ specified in `class Meta <marshmallow.Schema.Meta>`.
1032
1127
  """
1033
1128
  if field_name in self.load_only:
1034
1129
  field_obj.load_only = True
1035
1130
  if field_name in self.dump_only:
1036
1131
  field_obj.dump_only = True
1037
1132
  try:
1038
- field_obj._bind_to_schema(field_name, self)
1133
+ field_obj._bind_to_schema(field_name, self) # noqa: SLF001
1039
1134
  except TypeError as error:
1040
1135
  # Field declared as a class, not an instance. Ignore type checking because
1041
1136
  # we handle unsupported arg types, i.e. this is dead code from
@@ -1044,10 +1139,10 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1044
1139
  msg = (
1045
1140
  f'Field for "{field_name}" must be declared as a '
1046
1141
  "Field instance, not a class. "
1047
- f'Did you mean "fields.{field_obj.__name__}()"?' # type: ignore
1142
+ f'Did you mean "fields.{field_obj.__name__}()"?' # type: ignore[attr-defined]
1048
1143
  )
1049
1144
  raise TypeError(msg) from error
1050
- raise error
1145
+ raise
1051
1146
  self.on_bind_field(field_name, field_obj)
1052
1147
 
1053
1148
  def _invoke_dump_processors(
@@ -1059,10 +1154,9 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1059
1154
  data = self._invoke_processors(
1060
1155
  tag, pass_many=False, data=data, many=many, original_data=original_data
1061
1156
  )
1062
- data = self._invoke_processors(
1157
+ return self._invoke_processors(
1063
1158
  tag, pass_many=True, data=data, many=many, original_data=original_data
1064
1159
  )
1065
- return data
1066
1160
 
1067
1161
  def _invoke_load_processors(
1068
1162
  self,
@@ -1083,7 +1177,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1083
1177
  original_data=original_data,
1084
1178
  partial=partial,
1085
1179
  )
1086
- data = self._invoke_processors(
1180
+ return self._invoke_processors(
1087
1181
  tag,
1088
1182
  pass_many=False,
1089
1183
  data=data,
@@ -1091,7 +1185,6 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1091
1185
  original_data=original_data,
1092
1186
  partial=partial,
1093
1187
  )
1094
- return data
1095
1188
 
1096
1189
  def _invoke_field_validators(self, *, error_store: ErrorStore, data, many: bool):
1097
1190
  for attr_name, _, validator_kwargs in self._hooks[VALIDATES]:
@@ -1123,7 +1216,7 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1123
1216
  index=(idx if self.opts.index_errors else None),
1124
1217
  )
1125
1218
  if validated_value is missing:
1126
- data[idx].pop(field_name, None)
1219
+ item.pop(field_name, None)
1127
1220
  else:
1128
1221
  try:
1129
1222
  value = data[field_obj.attribute or field_name]
@@ -1202,15 +1295,14 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
1202
1295
  if pass_original:
1203
1296
  data = [
1204
1297
  processor(item, original, many=many, **kwargs)
1205
- for item, original in zip(data, original_data)
1298
+ for item, original in zip_longest(data, original_data)
1206
1299
  ]
1207
1300
  else:
1208
1301
  data = [processor(item, many=many, **kwargs) for item in data]
1302
+ elif pass_original:
1303
+ data = processor(data, original_data, many=many, **kwargs)
1209
1304
  else:
1210
- if pass_original:
1211
- data = processor(data, original_data, many=many, **kwargs)
1212
- else:
1213
- data = processor(data, many=many, **kwargs)
1305
+ data = processor(data, many=many, **kwargs)
1214
1306
  return data
1215
1307
 
1216
1308
 
marshmallow/types.py CHANGED
@@ -14,3 +14,27 @@ StrSequenceOrSet = typing.Union[typing.Sequence[str], typing.AbstractSet[str]]
14
14
 
15
15
  #: Type for validator functions
16
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: ...
marshmallow/utils.py CHANGED
@@ -1,5 +1,6 @@
1
1
  """Utility methods for marshmallow."""
2
2
 
3
+ # ruff: noqa: T201, T203
3
4
  from __future__ import annotations
4
5
 
5
6
  import collections
@@ -137,7 +138,7 @@ _iso8601_time_re = re.compile(
137
138
  )
138
139
 
139
140
 
140
- def get_fixed_timezone(offset: int | float | dt.timedelta) -> dt.timezone:
141
+ def get_fixed_timezone(offset: float | dt.timedelta) -> dt.timezone:
141
142
  """Return a tzinfo instance with a fixed offset from UTC."""
142
143
  if isinstance(offset, dt.timedelta):
143
144
  offset = offset.total_seconds() // 60
@@ -169,7 +170,7 @@ def from_iso_datetime(value):
169
170
  tzinfo = get_fixed_timezone(offset)
170
171
  kw = {k: int(v) for k, v in kw.items() if v is not None}
171
172
  kw["tzinfo"] = tzinfo
172
- return dt.datetime(**kw)
173
+ return dt.datetime(**kw) # noqa: DTZ001
173
174
 
174
175
 
175
176
  def from_iso_time(value):
@@ -279,17 +280,15 @@ def get_value(obj, key: int | str, default=missing):
279
280
  """
280
281
  if not isinstance(key, int) and "." in key:
281
282
  return _get_value_for_keys(obj, key.split("."), default)
282
- else:
283
- return _get_value_for_key(obj, key, default)
283
+ return _get_value_for_key(obj, key, default)
284
284
 
285
285
 
286
286
  def _get_value_for_keys(obj, keys, default):
287
287
  if len(keys) == 1:
288
288
  return _get_value_for_key(obj, keys[0], default)
289
- else:
290
- return _get_value_for_keys(
291
- _get_value_for_key(obj, keys[0], default), keys[1:], default
292
- )
289
+ return _get_value_for_keys(
290
+ _get_value_for_key(obj, keys[0], default), keys[1:], default
291
+ )
293
292
 
294
293
 
295
294
  def _get_value_for_key(obj, key, default):
@@ -318,7 +317,7 @@ def set_value(dct: dict[str, typing.Any], key: str, value: typing.Any):
318
317
  target = dct.setdefault(head, {})
319
318
  if not isinstance(target, dict):
320
319
  raise ValueError(
321
- f"Cannot set {key} in {head} " f"due to existing value: {target}"
320
+ f"Cannot set {key} in {head} due to existing value: {target}"
322
321
  )
323
322
  set_value(target, rest, value)
324
323
  else:
@@ -360,10 +359,9 @@ def resolve_field_instance(cls_or_instance: type[Field] | Field) -> Field:
360
359
  if not issubclass(cls_or_instance, FieldABC):
361
360
  raise FieldInstanceResolutionError
362
361
  return cls_or_instance()
363
- else:
364
- if not isinstance(cls_or_instance, FieldABC):
365
- raise FieldInstanceResolutionError
366
- return cls_or_instance
362
+ if not isinstance(cls_or_instance, FieldABC):
363
+ raise FieldInstanceResolutionError
364
+ return cls_or_instance
367
365
 
368
366
 
369
367
  def timedelta_to_microseconds(value: dt.timedelta) -> int:
marshmallow/validate.py CHANGED
@@ -9,10 +9,12 @@ from abc import ABC, abstractmethod
9
9
  from itertools import zip_longest
10
10
  from operator import attrgetter
11
11
 
12
- from marshmallow import types
13
12
  from marshmallow.exceptions import ValidationError
14
13
  from marshmallow.warnings import ChangedInMarshmallow4Warning
15
14
 
15
+ if typing.TYPE_CHECKING:
16
+ from marshmallow import types
17
+
16
18
  _T = typing.TypeVar("_T")
17
19
 
18
20
 
@@ -73,8 +75,8 @@ class And(Validator):
73
75
  return f"validators={self.validators!r}"
74
76
 
75
77
  def __call__(self, value: typing.Any) -> typing.Any:
76
- errors = []
77
- kwargs = {}
78
+ errors: list[str | dict] = []
79
+ kwargs: dict[str, typing.Any] = {}
78
80
  for validator in self.validators:
79
81
  try:
80
82
  r = validator(value)
@@ -85,14 +87,13 @@ class And(Validator):
85
87
  ChangedInMarshmallow4Warning,
86
88
  stacklevel=2,
87
89
  )
88
- raise ValidationError(self.error)
90
+ raise ValidationError(self.error) # noqa: TRY301
89
91
  except ValidationError as err:
90
92
  kwargs.update(err.kwargs)
91
93
  if isinstance(err.messages, dict):
92
94
  errors.append(err.messages)
93
95
  else:
94
- # FIXME : Get rid of cast
95
- errors.extend(typing.cast(list, err.messages))
96
+ errors.extend(err.messages)
96
97
  if errors:
97
98
  raise ValidationError(errors, **kwargs)
98
99
  return value
@@ -115,7 +116,7 @@ class URL(Validator):
115
116
  self._memoized = {}
116
117
 
117
118
  def _regex_generator(
118
- self, relative: bool, absolute: bool, require_tld: bool
119
+ self, *, relative: bool, absolute: bool, require_tld: bool
119
120
  ) -> typing.Pattern:
120
121
  hostname_variants = [
121
122
  # a normal domain name, expressed in [A-Z0-9] chars with hyphens allowed only in the middle
@@ -169,12 +170,12 @@ class URL(Validator):
169
170
  return re.compile("".join(parts), re.IGNORECASE)
170
171
 
171
172
  def __call__(
172
- self, relative: bool, absolute: bool, require_tld: bool
173
+ self, *, relative: bool, absolute: bool, require_tld: bool
173
174
  ) -> typing.Pattern:
174
175
  key = (relative, absolute, require_tld)
175
176
  if key not in self._memoized:
176
177
  self._memoized[key] = self._regex_generator(
177
- relative, absolute, require_tld
178
+ relative=relative, absolute=absolute, require_tld=require_tld
178
179
  )
179
180
 
180
181
  return self._memoized[key]
@@ -215,14 +216,24 @@ class URL(Validator):
215
216
  raise ValidationError(message)
216
217
 
217
218
  # Check first if the scheme is valid
219
+ scheme = None
218
220
  if "://" in value:
219
221
  scheme = value.split("://")[0].lower()
220
222
  if scheme not in self.schemes:
221
223
  raise ValidationError(message)
222
224
 
223
- regex = self._regex(self.relative, self.absolute, self.require_tld)
225
+ regex = self._regex(
226
+ relative=self.relative, absolute=self.absolute, require_tld=self.require_tld
227
+ )
228
+
229
+ # Hostname is optional for file URLS. If absent it means `localhost`.
230
+ # Fill it in for the validation if needed
231
+ if scheme == "file" and value.startswith("file:///"):
232
+ matched = regex.search(value.replace("file:///", "file://localhost/", 1))
233
+ else:
234
+ matched = regex.search(value)
224
235
 
225
- if not regex.search(value):
236
+ if not matched:
226
237
  raise ValidationError(message)
227
238
 
228
239
  return value
@@ -318,8 +329,8 @@ class Range(Validator):
318
329
 
319
330
  def __init__(
320
331
  self,
321
- min=None,
322
- max=None,
332
+ min=None, # noqa: A002
333
+ max=None, # noqa: A002
323
334
  *,
324
335
  min_inclusive: bool = True,
325
336
  max_inclusive: bool = True,
@@ -365,6 +376,9 @@ class Range(Validator):
365
376
  return value
366
377
 
367
378
 
379
+ _SizedT = typing.TypeVar("_SizedT", bound=typing.Sized)
380
+
381
+
368
382
  class Length(Validator):
369
383
  """Validator which succeeds if the value passed to it has a
370
384
  length between a minimum and maximum. Uses len(), so it
@@ -387,8 +401,8 @@ class Length(Validator):
387
401
 
388
402
  def __init__(
389
403
  self,
390
- min: int | None = None,
391
- max: int | None = None,
404
+ min: int | None = None, # noqa: A002
405
+ max: int | None = None, # noqa: A002
392
406
  *,
393
407
  equal: int | None = None,
394
408
  error: str | None = None,
@@ -407,12 +421,12 @@ class Length(Validator):
407
421
  def _repr_args(self) -> str:
408
422
  return f"min={self.min!r}, max={self.max!r}, equal={self.equal!r}"
409
423
 
410
- def _format_error(self, value: typing.Sized, message: str) -> str:
424
+ def _format_error(self, value: _SizedT, message: str) -> str:
411
425
  return (self.error or message).format(
412
426
  input=value, min=self.min, max=self.max, equal=self.equal
413
427
  )
414
428
 
415
- def __call__(self, value: typing.Sized) -> typing.Sized:
429
+ def __call__(self, value: _SizedT) -> _SizedT:
416
430
  length = len(value)
417
431
 
418
432
  if self.equal is not None:
@@ -531,7 +545,7 @@ class Predicate(Validator):
531
545
  def _format_error(self, value: typing.Any) -> str:
532
546
  return self.error.format(input=value, method=self.method)
533
547
 
534
- def __call__(self, value: typing.Any) -> typing.Any:
548
+ def __call__(self, value: _T) -> _T:
535
549
  method = getattr(value, self.method)
536
550
 
537
551
  if not method(**self.kwargs):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: marshmallow
3
- Version: 3.25.1
3
+ Version: 3.26.1
4
4
  Summary: A lightweight library for converting complex datatypes to and from native Python datatypes.
5
5
  Author-email: Steven Loria <sloria1@gmail.com>
6
6
  Maintainer-email: Steven Loria <sloria1@gmail.com>, Jérôme Lafréchoux <jerome@jolimont.fr>, Jared Deckard <jared@shademaps.com>
@@ -0,0 +1,18 @@
1
+ marshmallow/__init__.py,sha256=TU1arjtOLs87YDfW4Z35YVbaY2CUXK-VgylcuL8LaQg,2387
2
+ marshmallow/base.py,sha256=39W78-rnuzzx5T95YWBEECzjtqxdUA8XzYJNHd39VLg,1362
3
+ marshmallow/class_registry.py,sha256=HTC9srCEaRsiy5L_vUKQso7IQfeZeRXxZfz4_2NitoM,3029
4
+ marshmallow/decorators.py,sha256=pMjGPaXBZCRfAdQS3Bz5ieTZGA3BOv61FdTPsLwCtMQ,8749
5
+ marshmallow/error_store.py,sha256=iCPSdw8nJGiS4fjWuIAY1aSI_Hhckcdo3l_g-7pjaMw,2240
6
+ marshmallow/exceptions.py,sha256=DuARdOcirCdJxmlp16V97hQKAXOokvdW12jXtYOlGyk,2326
7
+ marshmallow/fields.py,sha256=TKVxFY9hLpq7ch6_HEb1be5uPw0fgs-uC4n5o_fTkg8,74756
8
+ marshmallow/orderedset.py,sha256=-Lq83AWIIFs2bxptDwkHtfQ63ebX3WD3R6N3B5rRnVI,2936
9
+ marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ marshmallow/schema.py,sha256=Dc6ent2eI-0g9phGc1FB4EURpSNDRGFOjpyE2BWwYTc,52207
11
+ marshmallow/types.py,sha256=VY0_D-Xou7nKjcvWB1iccm8cZtxI3rkis1nhNelNn5Q,979
12
+ marshmallow/utils.py,sha256=tLzu9FDL3Ph51qKsoqWIyPSwg8dZ8rzjeXXGLUndHFE,11943
13
+ marshmallow/validate.py,sha256=Fx3F8F20dBGg-Wrv84Chx5SYedX9E0l592hR4MxS0kQ,24652
14
+ marshmallow/warnings.py,sha256=YHC0kQQBbTKCiA1FuwnbnXqrph7oKuU9BjTV4cxwnzE,192
15
+ marshmallow-3.26.1.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
16
+ marshmallow-3.26.1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
17
+ marshmallow-3.26.1.dist-info/METADATA,sha256=9TJTS8CSQ5yUx_cNqkUz_0dQU9p0gCQcsJ_lUeq_7tE,7310
18
+ marshmallow-3.26.1.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- marshmallow/__init__.py,sha256=C-zbaQJ9dlJLJxotIqTa5OOaD6ojGNRqW8moGrMsGr8,2387
2
- marshmallow/base.py,sha256=39W78-rnuzzx5T95YWBEECzjtqxdUA8XzYJNHd39VLg,1362
3
- marshmallow/class_registry.py,sha256=JaA2tJo53ZNzTVoJM_MuN_WKaadEskIcxjOrLKy76iQ,3015
4
- marshmallow/decorators.py,sha256=3U7gLAmiotqoVC8O2j_7kwUS2ceoJUdkAcuk8SuH9oQ,8486
5
- marshmallow/error_store.py,sha256=A7AxgLMw9ffSmaxRH4x3wcBWibx-DuGH4LwSDpVn50I,2223
6
- marshmallow/exceptions.py,sha256=DuARdOcirCdJxmlp16V97hQKAXOokvdW12jXtYOlGyk,2326
7
- marshmallow/fields.py,sha256=WgtoWGZR3WLkqEf056NTUlHurLVlfCho3TQQ5zSlMqc,74688
8
- marshmallow/orderedset.py,sha256=C2aAG6w1faIL1phinbAltbe3AUAnF5MN6n7fzESNDhI,2922
9
- marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- marshmallow/schema.py,sha256=w81gPdm9L4_NaloLb8Z04U5shzUbuDOtDPeJL8uMHH0,48653
11
- marshmallow/types.py,sha256=csTzHJh-tbNs9t9eDRG6HjJMNawSVNw27mmor6w4ztM,423
12
- marshmallow/utils.py,sha256=Xvpd7h3IdB8tRKfa-u95DbOXjLgDzWRNJIwjsTNI9n0,11970
13
- marshmallow/validate.py,sha256=D9CbPe2vywalBcTa3iuwCqIK6mNhDn5pQaJ_kn_6_y4,24116
14
- marshmallow/warnings.py,sha256=YHC0kQQBbTKCiA1FuwnbnXqrph7oKuU9BjTV4cxwnzE,192
15
- marshmallow-3.25.1.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
16
- marshmallow-3.25.1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
17
- marshmallow-3.25.1.dist-info/METADATA,sha256=aBxXuzqfK0y4iUwJb9zVGHq9vcndAyUzCRZRVVTLmf8,7310
18
- marshmallow-3.25.1.dist-info/RECORD,,