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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
marshmallow/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
@@ -18,6 +19,10 @@ from marshmallow.base import FieldABC
18
19
  from marshmallow.exceptions import FieldInstanceResolutionError
19
20
  from marshmallow.warnings import RemovedInMarshmallow4Warning
20
21
 
22
+ if typing.TYPE_CHECKING:
23
+ from marshmallow.fields import Field
24
+
25
+
21
26
  EXCLUDE = "exclude"
22
27
  INCLUDE = "include"
23
28
  RAISE = "raise"
@@ -111,7 +116,7 @@ def from_rfc(datestring: str) -> dt.datetime:
111
116
  def rfcformat(datetime: dt.datetime) -> str:
112
117
  """Return the RFC822-formatted representation of a datetime object.
113
118
 
114
- :param datetime datetime: The datetime.
119
+ :param datetime: The datetime.
115
120
  """
116
121
  return format_datetime(datetime)
117
122
 
@@ -133,7 +138,7 @@ _iso8601_time_re = re.compile(
133
138
  )
134
139
 
135
140
 
136
- def get_fixed_timezone(offset: int | float | dt.timedelta) -> dt.timezone:
141
+ def get_fixed_timezone(offset: float | dt.timedelta) -> dt.timezone:
137
142
  """Return a tzinfo instance with a fixed offset from UTC."""
138
143
  if isinstance(offset, dt.timedelta):
139
144
  offset = offset.total_seconds() // 60
@@ -165,7 +170,7 @@ def from_iso_datetime(value):
165
170
  tzinfo = get_fixed_timezone(offset)
166
171
  kw = {k: int(v) for k, v in kw.items() if v is not None}
167
172
  kw["tzinfo"] = tzinfo
168
- return dt.datetime(**kw)
173
+ return dt.datetime(**kw) # noqa: DTZ001
169
174
 
170
175
 
171
176
  def from_iso_time(value):
@@ -229,7 +234,7 @@ def timestamp_ms(value: dt.datetime) -> float:
229
234
  def isoformat(datetime: dt.datetime) -> str:
230
235
  """Return the ISO8601-formatted representation of a datetime object.
231
236
 
232
- :param datetime datetime: The datetime.
237
+ :param datetime: The datetime.
233
238
  """
234
239
  return datetime.isoformat()
235
240
 
@@ -275,17 +280,15 @@ def get_value(obj, key: int | str, default=missing):
275
280
  """
276
281
  if not isinstance(key, int) and "." in key:
277
282
  return _get_value_for_keys(obj, key.split("."), default)
278
- else:
279
- return _get_value_for_key(obj, key, default)
283
+ return _get_value_for_key(obj, key, default)
280
284
 
281
285
 
282
286
  def _get_value_for_keys(obj, keys, default):
283
287
  if len(keys) == 1:
284
288
  return _get_value_for_key(obj, keys[0], default)
285
- else:
286
- return _get_value_for_keys(
287
- _get_value_for_key(obj, keys[0], default), keys[1:], default
288
- )
289
+ return _get_value_for_keys(
290
+ _get_value_for_key(obj, keys[0], default), keys[1:], default
291
+ )
289
292
 
290
293
 
291
294
  def _get_value_for_key(obj, key, default):
@@ -314,7 +317,7 @@ def set_value(dct: dict[str, typing.Any], key: str, value: typing.Any):
314
317
  target = dct.setdefault(head, {})
315
318
  if not isinstance(target, dict):
316
319
  raise ValueError(
317
- f"Cannot set {key} in {head} " f"due to existing value: {target}"
320
+ f"Cannot set {key} in {head} due to existing value: {target}"
318
321
  )
319
322
  set_value(target, rest, value)
320
323
  else:
@@ -347,19 +350,18 @@ def get_func_args(func: typing.Callable) -> list[str]:
347
350
  return _signature(func)
348
351
 
349
352
 
350
- def resolve_field_instance(cls_or_instance):
351
- """Return a Schema instance from a Schema class or instance.
353
+ def resolve_field_instance(cls_or_instance: type[Field] | Field) -> Field:
354
+ """Return a field instance from a field class or instance.
352
355
 
353
- :param type|Schema cls_or_instance: Marshmallow Schema class or instance.
356
+ :param cls_or_instance: Field class or instance.
354
357
  """
355
358
  if isinstance(cls_or_instance, type):
356
359
  if not issubclass(cls_or_instance, FieldABC):
357
360
  raise FieldInstanceResolutionError
358
361
  return cls_or_instance()
359
- else:
360
- if not isinstance(cls_or_instance, FieldABC):
361
- raise FieldInstanceResolutionError
362
- return cls_or_instance
362
+ if not isinstance(cls_or_instance, FieldABC):
363
+ raise FieldInstanceResolutionError
364
+ return cls_or_instance
363
365
 
364
366
 
365
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):
@@ -637,9 +651,9 @@ class ContainsOnly(OneOf):
637
651
  in the sequence is also in the sequence passed as ``choices``. Empty input
638
652
  is considered valid.
639
653
 
640
- :param iterable choices: Same as :class:`OneOf`.
641
- :param iterable labels: Same as :class:`OneOf`.
642
- :param str error: Same as :class:`OneOf`.
654
+ :param choices: Same as :class:`OneOf`.
655
+ :param labels: Same as :class:`OneOf`.
656
+ :param error: Same as :class:`OneOf`.
643
657
 
644
658
  .. versionchanged:: 3.0.0b2
645
659
  Duplicate values are considered valid.
@@ -667,8 +681,8 @@ class ContainsNoneOf(NoneOf):
667
681
  in the sequence is a member of the sequence passed as ``iterable``. Empty input
668
682
  is considered valid.
669
683
 
670
- :param iterable iterable: Same as :class:`NoneOf`.
671
- :param str error: Same as :class:`NoneOf`.
684
+ :param iterable: Same as :class:`NoneOf`.
685
+ :param error: Same as :class:`NoneOf`.
672
686
 
673
687
  .. versionadded:: 3.6.0
674
688
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: marshmallow
3
- Version: 3.25.0
3
+ Version: 3.26.0
4
4
  Summary: A lightweight library for converting complex datatypes to and from native Python datatypes.
5
5
  Author-email: Steven Loria <sloria1@gmail.com>
6
6
  Maintainer-email: Steven Loria <sloria1@gmail.com>, Jérôme Lafréchoux <jerome@jolimont.fr>, Jared Deckard <jared@shademaps.com>
@@ -19,10 +19,12 @@ Requires-Dist: packaging>=17.0
19
19
  Requires-Dist: marshmallow[tests] ; extra == "dev"
20
20
  Requires-Dist: tox ; extra == "dev"
21
21
  Requires-Dist: pre-commit>=3.5,<5.0 ; extra == "dev"
22
- Requires-Dist: sphinx==8.1.3 ; extra == "docs"
23
- Requires-Dist: sphinx-issues==5.0.0 ; extra == "docs"
24
- Requires-Dist: alabaster==1.0.0 ; extra == "docs"
25
22
  Requires-Dist: autodocsumm==0.2.14 ; extra == "docs"
23
+ Requires-Dist: furo==2024.8.6 ; extra == "docs"
24
+ Requires-Dist: sphinx-copybutton==0.5.2 ; extra == "docs"
25
+ Requires-Dist: sphinx-issues==5.0.0 ; extra == "docs"
26
+ Requires-Dist: sphinx==8.1.3 ; extra == "docs"
27
+ Requires-Dist: sphinxext-opengraph==0.9.1 ; extra == "docs"
26
28
  Requires-Dist: pytest ; extra == "tests"
27
29
  Requires-Dist: simplejson ; extra == "tests"
28
30
  Project-URL: Changelog, https://marshmallow.readthedocs.io/en/latest/changelog.html
@@ -56,6 +58,8 @@ marshmallow: simplified object serialization
56
58
  :target: https://marshmallow.readthedocs.io/
57
59
  :alt: Documentation
58
60
 
61
+ .. start elevator-pitch
62
+
59
63
  **marshmallow** is an ORM/ODM/framework-agnostic library for converting complex datatypes, such as objects, to and from native Python datatypes.
60
64
 
61
65
  .. code-block:: python
@@ -86,20 +90,21 @@ marshmallow: simplified object serialization
86
90
  # 'release_date': '1971-12-17',
87
91
  # 'title': 'Hunky Dory'}
88
92
 
89
-
90
93
  In short, marshmallow schemas can be used to:
91
94
 
92
95
  - **Validate** input data.
93
96
  - **Deserialize** input data to app-level objects.
94
97
  - **Serialize** app-level objects to primitive Python types. The serialized objects can then be rendered to standard formats such as JSON for use in an HTTP API.
95
98
 
96
- Get It Now
99
+ Get it now
97
100
  ==========
98
101
 
99
- ::
102
+ .. code-block:: shell-session
100
103
 
101
104
  $ pip install -U marshmallow
102
105
 
106
+ .. end elevator-pitch
107
+
103
108
  Documentation
104
109
  =============
105
110
 
@@ -146,6 +151,8 @@ Thank you to all our backers! [`Become a backer`_]
146
151
  Sponsors
147
152
  --------
148
153
 
154
+ .. start sponsors
155
+
149
156
  marshmallow is sponsored by `Route4Me <https://route4me.com>`_.
150
157
 
151
158
  .. image:: https://github.com/user-attachments/assets/018c2e23-032e-4a11-98da-8b6dc25b9054
@@ -157,6 +164,8 @@ Your logo will be displayed here with a link to your website. [`Become a sponsor
157
164
 
158
165
  .. _`Become a sponsor`: https://opencollective.com/marshmallow#sponsor
159
166
 
167
+ .. end sponsors
168
+
160
169
  Professional Support
161
170
  ====================
162
171
 
@@ -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=DjjL5m5YZbwMVHE97MQDNfoFf_e75qMR3eIs17UuVMc,74763
8
+ marshmallow/orderedset.py,sha256=-Lq83AWIIFs2bxptDwkHtfQ63ebX3WD3R6N3B5rRnVI,2936
9
+ marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ marshmallow/schema.py,sha256=bSBynndwixq1zcOOPdoZkX7DmpVSpHBaNEh1zqiD888,52128
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.0.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
16
+ marshmallow-3.26.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
17
+ marshmallow-3.26.0.dist-info/METADATA,sha256=Scbh6z8NMiWGVQ3EYrwo6H9-PNczOrepN_tFFZu_A9k,7310
18
+ marshmallow-3.26.0.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=ZULbtwFxnj4bbzQqfwTLyNPUpr6xAZTLFMar4YJfKJQ,3032
4
- marshmallow/decorators.py,sha256=B8Z-PsxWrftY4jTq3y_wt7kwlJWQI2vVQQyApMY5IeQ,8490
5
- marshmallow/error_store.py,sha256=A7AxgLMw9ffSmaxRH4x3wcBWibx-DuGH4LwSDpVn50I,2223
6
- marshmallow/exceptions.py,sha256=DuARdOcirCdJxmlp16V97hQKAXOokvdW12jXtYOlGyk,2326
7
- marshmallow/fields.py,sha256=Z8wS9If4tqcv0KFnbm7HS5csMiVOD6--Donv6FlMfOc,74082
8
- marshmallow/orderedset.py,sha256=C2aAG6w1faIL1phinbAltbe3AUAnF5MN6n7fzESNDhI,2922
9
- marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- marshmallow/schema.py,sha256=qUY1MvcYxtEuztzjoom2fYaC7x2t16cAx4FBdgz3SDY,48696
11
- marshmallow/types.py,sha256=RDS4IfasIehvH2rGWh9e4RTBtsMp-JFFtjApajV22zc,283
12
- marshmallow/utils.py,sha256=pLZXqQWu7PHaQrQCrgwnR8eI_-aq_BVct5CCwyygUvk,11917
13
- marshmallow/validate.py,sha256=t5-4Qg_XlSQgcCujf_pimKIdZE0QT63jHyQP-miJNK0,24151
14
- marshmallow/warnings.py,sha256=YHC0kQQBbTKCiA1FuwnbnXqrph7oKuU9BjTV4cxwnzE,192
15
- marshmallow-3.25.0.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
16
- marshmallow-3.25.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
17
- marshmallow-3.25.0.dist-info/METADATA,sha256=yQLETlmBAzADnSDY4fAT_4zsyjlAxPlRFT6NVIovaYo,7084
18
- marshmallow-3.25.0.dist-info/RECORD,,