codekingpro/portable-devtools
114k
1# ruff: noqa: F841, SLF0012from __future__ import annotations3 4import collections5import copy6import datetime as dt7import decimal8import ipaddress9import math10import numbers11import typing12import uuid13import warnings14from collections.abc import Mapping as _Mapping15 16from marshmallow import class_registry, types, utils, validate17from marshmallow.base import FieldABC18from marshmallow.exceptions import (19 FieldInstanceResolutionError,20 StringNotCollectionError,21 ValidationError,22)23from marshmallow.utils import (24 is_aware,25 is_collection,26 resolve_field_instance,27)28from marshmallow.utils import (29 missing as missing_,30)31from marshmallow.validate import And, Length32from marshmallow.warnings import (33 ChangedInMarshmallow4Warning,34 RemovedInMarshmallow4Warning,35)36 37if typing.TYPE_CHECKING:38 from enum import Enum as EnumType39 40 from marshmallow.schema import Schema, SchemaMeta41 42 43__all__ = [44 "IP",45 "URL",46 "UUID",47 "AwareDateTime",48 "Bool",49 "Boolean",50 "Constant",51 "Date",52 "DateTime",53 "Decimal",54 "Dict",55 "Email",56 "Enum",57 "Field",58 "Float",59 "Function",60 "IPInterface",61 "IPv4",62 "IPv4Interface",63 "IPv6",64 "IPv6Interface",65 "Int",66 "Integer",67 "List",68 "Mapping",69 "Method",70 "NaiveDateTime",71 "Nested",72 "Number",73 "Pluck",74 "Raw",75 "Str",76 "String",77 "Time",78 "TimeDelta",79 "Tuple",80 "Url",81]82 83 84class Field(FieldABC):85 """Base field from which other fields inherit.86 87 :param dump_default: If set, this value will be used during serialization if the88 input value is missing. If not set, the field will be excluded from the89 serialized output if the input value is missing. May be a value or a callable.90 :param load_default: Default deserialization value for the field if the field is not91 found in the input data. May be a value or a callable.92 :param data_key: The name of the dict key in the external representation, i.e.93 the input of `load` and the output of `dump`.94 If `None`, the key will match the name of the field.95 :param attribute: The name of the key/attribute in the internal representation, i.e.96 the output of `load` and the input of `dump`.97 If `None`, the key/attribute will match the name of the field.98 Note: This should only be used for very specific use cases such as99 outputting multiple fields for a single attribute, or using keys/attributes100 that are invalid variable names, unsuitable for field names. In most cases,101 you should use ``data_key`` instead.102 :param validate: Validator or collection of validators that are called103 during deserialization. Validator takes a field's input value as104 its only parameter and returns a boolean.105 If it returns `False`, an :exc:`ValidationError` is raised.106 :param required: Raise a :exc:`ValidationError` if the field value107 is not supplied during deserialization.108 :param allow_none: Set this to `True` if `None` should be considered a valid value during109 validation/deserialization. If set to `False` (the default), `None` is considered invalid input.110 If ``load_default`` is explicitly set to `None` and ``allow_none`` is unset,111 `allow_none` is implicitly set to ``True``.112 :param load_only: If `True` skip this field during serialization, otherwise113 its value will be present in the serialized data.114 :param dump_only: If `True` skip this field during deserialization, otherwise115 its value will be present in the deserialized object. In the context of an116 HTTP API, this effectively marks the field as "read-only".117 :param error_messages: Overrides for `Field.default_error_messages`.118 :param metadata: Extra information to be stored as field metadata.119 120 .. versionchanged:: 3.0.0b8121 Add ``data_key`` parameter for the specifying the key in the input and122 output data. This parameter replaced both ``load_from`` and ``dump_to``.123 124 .. versionchanged:: 3.13.0125 Replace ``missing`` and ``default`` parameters with ``load_default`` and ``dump_default``.126 127 .. versionchanged:: 3.24.0128 `Field <marshmallow.fields.Field>` should no longer be used as a field within a `Schema <marshmallow.Schema>`.129 Use `Raw <marshmallow.fields.Raw>` or another `Field <marshmallow.fields.Field>` subclass instead.130 """131 132 # Some fields, such as Method fields and Function fields, are not expected133 # to exist as attributes on the objects to serialize. Set this to False134 # for those fields135 _CHECK_ATTRIBUTE = True136 137 #: Default error messages for various kinds of errors. The keys in this dictionary138 #: are passed to `Field.make_error`. The values are error messages passed to139 #: :exc:`marshmallow.exceptions.ValidationError`.140 default_error_messages: dict[str, str] = {141 "required": "Missing data for required field.",142 "null": "Field may not be null.",143 "validator_failed": "Invalid value.",144 }145 146 def __init__(147 self,148 *,149 load_default: typing.Any = missing_,150 missing: typing.Any = missing_,151 dump_default: typing.Any = missing_,152 default: typing.Any = missing_,153 data_key: str | None = None,154 attribute: str | None = None,155 validate: types.Validator | typing.Iterable[types.Validator] | None = None,156 required: bool = False,157 allow_none: bool | None = None,158 load_only: bool = False,159 dump_only: bool = False,160 error_messages: dict[str, str] | None = None,161 metadata: typing.Mapping[str, typing.Any] | None = None,162 **additional_metadata,163 ) -> None:164 if self.__class__ is Field:165 warnings.warn(166 "`Field` should not be instantiated. Use `fields.Raw` or "167 "another field subclass instead.",168 ChangedInMarshmallow4Warning,169 stacklevel=2,170 )171 # handle deprecated `default` and `missing` parameters172 if default is not missing_:173 warnings.warn(174 "The 'default' argument to fields is deprecated. "175 "Use 'dump_default' instead.",176 RemovedInMarshmallow4Warning,177 stacklevel=2,178 )179 if dump_default is missing_:180 dump_default = default181 if missing is not missing_:182 warnings.warn(183 "The 'missing' argument to fields is deprecated. "184 "Use 'load_default' instead.",185 RemovedInMarshmallow4Warning,186 stacklevel=2,187 )188 if load_default is missing_:189 load_default = missing190 self.dump_default = dump_default191 self.load_default = load_default192 193 self.attribute = attribute194 self.data_key = data_key195 self.validate = validate196 if validate is None:197 self.validators = []198 elif callable(validate):199 self.validators = [validate]200 elif utils.is_iterable_but_not_string(validate):201 self.validators = list(validate)202 else:203 raise ValueError(204 "The 'validate' parameter must be a callable "205 "or a collection of callables."206 )207 208 # If allow_none is None and load_default is None209 # None should be considered valid by default210 self.allow_none = load_default is None if allow_none is None else allow_none211 self.load_only = load_only212 self.dump_only = dump_only213 if required is True and load_default is not missing_:214 raise ValueError("'load_default' must not be set for required fields.")215 self.required = required216 217 metadata = metadata or {}218 self.metadata = {**metadata, **additional_metadata}219 if additional_metadata:220 warnings.warn(221 "Passing field metadata as keyword arguments is deprecated. Use the "222 "explicit `metadata=...` argument instead. "223 f"Additional metadata: {additional_metadata}",224 RemovedInMarshmallow4Warning,225 stacklevel=2,226 )227 228 # Collect default error message from self and parent classes229 messages: dict[str, str] = {}230 for cls in reversed(self.__class__.__mro__):231 messages.update(getattr(cls, "default_error_messages", {}))232 messages.update(error_messages or {})233 self.error_messages = messages234 235 self.parent: Field | Schema | None = None236 self.name: str | None = None237 self.root: Schema | None = None238 239 def __repr__(self) -> str:240 return (241 f"<fields.{self.__class__.__name__}(dump_default={self.dump_default!r}, "242 f"attribute={self.attribute!r}, "243 f"validate={self.validate}, required={self.required}, "244 f"load_only={self.load_only}, dump_only={self.dump_only}, "245 f"load_default={self.load_default}, allow_none={self.allow_none}, "246 f"error_messages={self.error_messages})>"247 )248 249 def __deepcopy__(self, memo):250 return copy.copy(self)251 252 def get_value(253 self,254 obj: typing.Any,255 attr: str,256 accessor: (257 typing.Callable[[typing.Any, str, typing.Any], typing.Any] | None258 ) = None,259 default: typing.Any = missing_,260 ):261 """Return the value for a given key from an object.262 263 :param obj: The object to get the value from.264 :param attr: The attribute/key in `obj` to get the value from.265 :param accessor: A callable used to retrieve the value of `attr` from266 the object `obj`. Defaults to `marshmallow.utils.get_value`.267 """268 accessor_func = accessor or utils.get_value269 check_key = attr if self.attribute is None else self.attribute270 return accessor_func(obj, check_key, default)271 272 def _validate(self, value: typing.Any):273 """Perform validation on ``value``. Raise a :exc:`ValidationError` if validation274 does not succeed.275 """276 self._validate_all(value)277 278 @property279 def _validate_all(self) -> typing.Callable[[typing.Any], None]:280 return And(*self.validators, error=self.error_messages["validator_failed"])281 282 def make_error(self, key: str, **kwargs) -> ValidationError:283 """Helper method to make a `ValidationError` with an error message284 from ``self.error_messages``.285 """286 try:287 msg = self.error_messages[key]288 except KeyError as error:289 class_name = self.__class__.__name__290 message = (291 f"ValidationError raised by `{class_name}`, but error key `{key}` does "292 "not exist in the `error_messages` dictionary."293 )294 raise AssertionError(message) from error295 if isinstance(msg, (str, bytes)):296 msg = msg.format(**kwargs)297 return ValidationError(msg)298 299 def fail(self, key: str, **kwargs):300 """Helper method that raises a `ValidationError` with an error message301 from ``self.error_messages``.302 303 .. deprecated:: 3.0.0304 Use `make_error <marshmallow.fields.Field.make_error>` instead.305 """306 warnings.warn(307 f'`Field.fail` is deprecated. Use `raise self.make_error("{key}", ...)` instead.',308 RemovedInMarshmallow4Warning,309 stacklevel=2,310 )311 raise self.make_error(key=key, **kwargs)312 313 def _validate_missing(self, value: typing.Any) -> None:314 """Validate missing values. Raise a :exc:`ValidationError` if315 `value` should be considered missing.316 """317 if value is missing_ and self.required:318 raise self.make_error("required")319 if value is None and not self.allow_none:320 raise self.make_error("null")321 322 def serialize(323 self,324 attr: str,325 obj: typing.Any,326 accessor: (327 typing.Callable[[typing.Any, str, typing.Any], typing.Any] | None328 ) = None,329 **kwargs,330 ):331 """Pulls the value for the given key from the object, applies the332 field's formatting and returns the result.333 334 :param attr: The attribute/key to get from the object.335 :param obj: The object to access the attribute/key from.336 :param accessor: Function used to access values from ``obj``.337 :param kwargs: Field-specific keyword arguments.338 """339 if self._CHECK_ATTRIBUTE:340 value = self.get_value(obj, attr, accessor=accessor)341 if value is missing_:342 default = self.dump_default343 value = default() if callable(default) else default344 if value is missing_:345 return value346 else:347 value = None348 return self._serialize(value, attr, obj, **kwargs)349 350 def deserialize(351 self,352 value: typing.Any,353 attr: str | None = None,354 data: typing.Mapping[str, typing.Any] | None = None,355 **kwargs,356 ):357 """Deserialize ``value``.358 359 :param value: The value to deserialize.360 :param attr: The attribute/key in `data` to deserialize.361 :param data: The raw input data passed to `Schema.load <marshmallow.Schema.load>`.362 :param kwargs: Field-specific keyword arguments.363 :raise ValidationError: If an invalid value is passed or if a required value364 is missing.365 """366 # Validate required fields, deserialize, then validate367 # deserialized value368 self._validate_missing(value)369 if value is missing_:370 _miss = self.load_default371 return _miss() if callable(_miss) else _miss372 if self.allow_none and value is None:373 return None374 output = self._deserialize(value, attr, data, **kwargs)375 self._validate(output)376 return output377 378 # Methods for concrete classes to override.379 380 def _bind_to_schema(self, field_name: str, schema: Schema | Field) -> None:381 """Update field with values from its parent schema. Called by382 `Schema._bind_field <marshmallow.Schema._bind_field>`.383 384 :param field_name: Field name set in schema.385 :param schema: Parent object.386 """387 self.parent = self.parent or schema388 self.name = self.name or field_name389 self.root = self.root or (390 self.parent.root if isinstance(self.parent, FieldABC) else self.parent391 )392 393 def _serialize(394 self, value: typing.Any, attr: str | None, obj: typing.Any, **kwargs395 ) -> typing.Any:396 """Serializes ``value`` to a basic Python datatype. Noop by default.397 Concrete :class:`Field` classes should implement this method.398 399 Example: ::400 401 class TitleCase(Field):402 def _serialize(self, value, attr, obj, **kwargs):403 if not value:404 return ""405 return str(value).title()406 407 :param value: The value to be serialized.408 :param attr: The attribute or key on the object to be serialized.409 :param obj: The object the value was pulled from.410 :param kwargs: Field-specific keyword arguments.411 :return: The serialized value412 """413 return value414 415 def _deserialize(416 self,417 value: typing.Any,418 attr: str | None,419 data: typing.Mapping[str, typing.Any] | None,420 **kwargs,421 ) -> typing.Any:422 """Deserialize value. Concrete :class:`Field` classes should implement this method.423 424 :param value: The value to be deserialized.425 :param attr: The attribute/key in `data` to be deserialized.426 :param data: The raw input data passed to the `Schema.load <marshmallow.Schema.load>`.427 :param kwargs: Field-specific keyword arguments.428 :raise ValidationError: In case of formatting or validation failure.429 :return: The deserialized value.430 431 .. versionchanged:: 3.0.0432 Added ``**kwargs`` to signature.433 """434 return value435 436 # Properties437 438 @property439 def context(self) -> dict | None:440 """The context dictionary for the parent `Schema <marshmallow.Schema>`."""441 if self.parent:442 return self.parent.context443 return None444 445 # the default and missing properties are provided for compatibility and446 # emit warnings when they are accessed and set447 @property448 def default(self):449 warnings.warn(450 "The 'default' attribute of fields is deprecated. "451 "Use 'dump_default' instead.",452 RemovedInMarshmallow4Warning,453 stacklevel=2,454 )455 return self.dump_default456 457 @default.setter458 def default(self, value):459 warnings.warn(460 "The 'default' attribute of fields is deprecated. "461 "Use 'dump_default' instead.",462 RemovedInMarshmallow4Warning,463 stacklevel=2,464 )465 self.dump_default = value466 467 @property468 def missing(self):469 warnings.warn(470 "The 'missing' attribute of fields is deprecated. "471 "Use 'load_default' instead.",472 RemovedInMarshmallow4Warning,473 stacklevel=2,474 )475 return self.load_default476 477 @missing.setter478 def missing(self, value):479 warnings.warn(480 "The 'missing' attribute of fields is deprecated. "481 "Use 'load_default' instead.",482 RemovedInMarshmallow4Warning,483 stacklevel=2,484 )485 self.load_default = value486 487 488class Raw(Field):489 """Field that applies no formatting."""490 491 492class Nested(Field):493 """Allows you to nest a :class:`Schema <marshmallow.Schema>`494 inside a field.495 496 Examples: ::497 498 class ChildSchema(Schema):499 id = fields.Str()500 name = fields.Str()501 # Use lambda functions when you need two-way nesting or self-nesting502 parent = fields.Nested(lambda: ParentSchema(only=("id",)), dump_only=True)503 siblings = fields.List(504 fields.Nested(lambda: ChildSchema(only=("id", "name")))505 )506 507 508 class ParentSchema(Schema):509 id = fields.Str()510 children = fields.List(511 fields.Nested(ChildSchema(only=("id", "parent", "siblings")))512 )513 spouse = fields.Nested(lambda: ParentSchema(only=("id",)))514 515 When passing a `Schema <marshmallow.Schema>` instance as the first argument,516 the instance's ``exclude``, ``only``, and ``many`` attributes will be respected.517 518 Therefore, when passing the ``exclude``, ``only``, or ``many`` arguments to `fields.Nested`,519 you should pass a `Schema <marshmallow.Schema>` class (not an instance) as the first argument.520 521 ::522 523 # Yes524 author = fields.Nested(UserSchema, only=("id", "name"))525 526 # No527 author = fields.Nested(UserSchema(), only=("id", "name"))528 529 :param nested: `Schema <marshmallow.Schema>` instance, class, class name (string), dictionary, or callable that530 returns a `Schema <marshmallow.Schema>` or dictionary.531 Dictionaries are converted with `Schema.from_dict <marshmallow.Schema.from_dict>`.532 :param exclude: A list or tuple of fields to exclude.533 :param only: A list or tuple of fields to marshal. If `None`, all fields are marshalled.534 This parameter takes precedence over ``exclude``.535 :param many: Whether the field is a collection of objects.536 :param unknown: Whether to exclude, include, or raise an error for unknown537 fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`.538 :param kwargs: The same keyword arguments that :class:`Field` receives.539 """540 541 #: Default error messages.542 default_error_messages = {"type": "Invalid type."}543 544 def __init__(545 self,546 nested: (547 Schema548 | SchemaMeta549 | str550 | dict[str, Field]551 | typing.Callable[[], Schema | SchemaMeta | dict[str, Field]]552 ),553 *,554 dump_default: typing.Any = missing_,555 default: typing.Any = missing_,556 only: types.StrSequenceOrSet | None = None,557 exclude: types.StrSequenceOrSet = (),558 many: bool = False,559 unknown: str | None = None,560 **kwargs,561 ):562 # Raise error if only or exclude is passed as string, not list of strings563 if only is not None and not is_collection(only):564 raise StringNotCollectionError('"only" should be a collection of strings.')565 if not is_collection(exclude):566 raise StringNotCollectionError(567 '"exclude" should be a collection of strings.'568 )569 if nested == "self":570 warnings.warn(571 "Passing 'self' to `Nested` is deprecated. "572 "Use `Nested(lambda: MySchema(...))` instead.",573 RemovedInMarshmallow4Warning,574 stacklevel=2,575 )576 self.nested = nested577 self.only = only578 self.exclude = exclude579 self.many = many580 self.unknown = unknown581 self._schema: Schema | None = None # Cached Schema instance582 super().__init__(default=default, dump_default=dump_default, **kwargs)583 584 @property585 def schema(self) -> Schema:586 """The nested `Schema <marshmallow.Schema>` object.587 588 .. versionchanged:: 1.0.0589 Renamed from ``serializer`` to ``schema``.590 """591 if not self._schema:592 # Inherit context from parent.593 context = getattr(self.parent, "context", {})594 if callable(self.nested) and not isinstance(self.nested, type):595 nested = self.nested()596 else:597 nested = typing.cast("Schema", self.nested)598 # defer the import of `marshmallow.schema` to avoid circular imports599 from marshmallow.schema import Schema600 601 if isinstance(nested, dict):602 nested = Schema.from_dict(nested)603 604 if isinstance(nested, Schema):605 self._schema = copy.copy(nested)606 self._schema.context.update(context)607 # Respect only and exclude passed from parent and re-initialize fields608 set_class = typing.cast(type[set], self._schema.set_class)609 if self.only is not None:610 if self._schema.only is not None:611 original = self._schema.only612 else: # only=None -> all fields613 original = self._schema.fields.keys()614 self._schema.only = set_class(self.only) & set_class(original)615 if self.exclude:616 original = self._schema.exclude617 self._schema.exclude = set_class(self.exclude) | set_class(original)618 self._schema._init_fields()619 else:620 if isinstance(nested, type) and issubclass(nested, Schema):621 schema_class: type[Schema] = nested622 elif not isinstance(nested, (str, bytes)):623 raise ValueError(624 "`Nested` fields must be passed a "625 f"`Schema`, not {nested.__class__}."626 )627 elif nested == "self":628 schema_class = typing.cast(Schema, self.root).__class__629 else:630 schema_class = class_registry.get_class(nested, all=False)631 self._schema = schema_class(632 many=self.many,633 only=self.only,634 exclude=self.exclude,635 context=context,636 load_only=self._nested_normalized_option("load_only"),637 dump_only=self._nested_normalized_option("dump_only"),638 )639 return self._schema640 641 def _nested_normalized_option(self, option_name: str) -> list[str]:642 nested_field = f"{self.name}."643 return [644 field.split(nested_field, 1)[1]645 for field in getattr(self.root, option_name, set())646 if field.startswith(nested_field)647 ]648 649 def _serialize(self, nested_obj, attr, obj, **kwargs):650 # Load up the schema first. This allows a RegistryError to be raised651 # if an invalid schema name was passed652 schema = self.schema653 if nested_obj is None:654 return None655 many = schema.many or self.many656 return schema.dump(nested_obj, many=many)657 658 def _test_collection(self, value: typing.Any) -> None:659 many = self.schema.many or self.many660 if many and not utils.is_collection(value):661 raise self.make_error("type", input=value, type=value.__class__.__name__)662 663 def _load(664 self, value: typing.Any, partial: bool | types.StrSequenceOrSet | None = None665 ):666 try:667 valid_data = self.schema.load(value, unknown=self.unknown, partial=partial)668 except ValidationError as error:669 raise ValidationError(670 error.messages, valid_data=error.valid_data671 ) from error672 return valid_data673 674 def _deserialize(675 self,676 value: typing.Any,677 attr: str | None,678 data: typing.Mapping[str, typing.Any] | None,679 partial: bool | types.StrSequenceOrSet | None = None,680 **kwargs,681 ) -> typing.Any:682 """Same as :meth:`Field._deserialize` with additional ``partial`` argument.683 684 :param partial: For nested schemas, the ``partial``685 parameter passed to `marshmallow.Schema.load`.686 687 .. versionchanged:: 3.0.0688 Add ``partial`` parameter.689 """690 self._test_collection(value)691 return self._load(value, partial=partial)692 693 694class Pluck(Nested):695 """Allows you to replace nested data with one of the data's fields.696 697 Example: ::698 699 from marshmallow import Schema, fields700 701 702 class ArtistSchema(Schema):703 id = fields.Int()704 name = fields.Str()705 706 707 class AlbumSchema(Schema):708 artist = fields.Pluck(ArtistSchema, "id")709 710 711 in_data = {"artist": 42}712 loaded = AlbumSchema().load(in_data) # => {'artist': {'id': 42}}713 dumped = AlbumSchema().dump(loaded) # => {'artist': 42}714 715 :param nested: The Schema class or class name (string)716 to nest, or ``"self"`` to nest the `Schema <marshmallow.Schema>` within itself.717 :param field_name: The key to pluck a value from.718 :param kwargs: The same keyword arguments that :class:`Nested` receives.719 """720 721 def __init__(722 self,723 nested: Schema | SchemaMeta | str | typing.Callable[[], Schema],724 field_name: str,725 *,726 many: bool = False,727 unknown: str | None = None,728 **kwargs,729 ):730 super().__init__(731 nested, only=(field_name,), many=many, unknown=unknown, **kwargs732 )733 self.field_name = field_name734 735 @property736 def _field_data_key(self) -> str:737 only_field = self.schema.fields[self.field_name]738 return only_field.data_key or self.field_name739 740 def _serialize(self, nested_obj, attr, obj, **kwargs):741 ret = super()._serialize(nested_obj, attr, obj, **kwargs)742 if ret is None:743 return None744 if self.many:745 return utils.pluck(ret, key=self._field_data_key)746 return ret[self._field_data_key]747 748 def _deserialize(self, value, attr, data, partial=None, **kwargs):749 self._test_collection(value)750 if self.many:751 value = [{self._field_data_key: v} for v in value]752 else:753 value = {self._field_data_key: value}754 return self._load(value, partial=partial)755 756 757class List(Field):758 """A list field, composed with another `Field` class or759 instance.760 761 Example: ::762 763 numbers = fields.List(fields.Float())764 765 :param cls_or_instance: A field class or instance.766 :param kwargs: The same keyword arguments that :class:`Field` receives.767 768 .. versionchanged:: 3.0.0rc9769 Does not serialize scalar values to single-item lists.770 """771 772 #: Default error messages.773 default_error_messages = {"invalid": "Not a valid list."}774 775 def __init__(self, cls_or_instance: Field | type[Field], **kwargs):776 super().__init__(**kwargs)777 try:778 self.inner = resolve_field_instance(cls_or_instance)779 except FieldInstanceResolutionError as error:780 raise ValueError(781 "The list elements must be a subclass or instance of "782 "marshmallow.base.FieldABC."783 ) from error784 if isinstance(self.inner, Nested):785 self.only = self.inner.only786 self.exclude = self.inner.exclude787 788 def _bind_to_schema(self, field_name: str, schema: Schema | Field) -> None:789 super()._bind_to_schema(field_name, schema)790 self.inner = copy.deepcopy(self.inner)791 self.inner._bind_to_schema(field_name, self)792 if isinstance(self.inner, Nested):793 self.inner.only = self.only794 self.inner.exclude = self.exclude795 796 def _serialize(self, value, attr, obj, **kwargs) -> list[typing.Any] | None:797 if value is None:798 return None799 return [self.inner._serialize(each, attr, obj, **kwargs) for each in value]800 801 def _deserialize(self, value, attr, data, **kwargs) -> list[typing.Any]:802 if not utils.is_collection(value):803 raise self.make_error("invalid")804 805 result = []806 errors = {}807 for idx, each in enumerate(value):808 try:809 result.append(self.inner.deserialize(each, **kwargs))810 except ValidationError as error:811 if error.valid_data is not None:812 result.append(error.valid_data)813 errors.update({idx: error.messages})814 if errors:815 raise ValidationError(errors, valid_data=result)816 return result817 818 819class Tuple(Field):820 """A tuple field, composed of a fixed number of other `Field` classes or821 instances822 823 Example: ::824 825 row = Tuple((fields.String(), fields.Integer(), fields.Float()))826 827 .. note::828 Because of the structured nature of `collections.namedtuple` and829 `typing.NamedTuple`, using a Schema within a Nested field for them is830 more appropriate than using a `Tuple` field.831 832 :param tuple_fields: An iterable of field classes or833 instances.834 :param kwargs: The same keyword arguments that :class:`Field` receives.835 836 .. versionadded:: 3.0.0rc4837 """838 839 #: Default error messages.840 default_error_messages = {"invalid": "Not a valid tuple."}841 842 def __init__(843 self,844 tuple_fields: typing.Iterable[Field] | typing.Iterable[type[Field]],845 **kwargs,846 ):847 super().__init__(**kwargs)848 if not utils.is_collection(tuple_fields):849 raise ValueError(850 "tuple_fields must be an iterable of Field classes or instances."851 )852 853 try:854 self.tuple_fields = [855 resolve_field_instance(cls_or_instance)856 for cls_or_instance in tuple_fields857 ]858 except FieldInstanceResolutionError as error:859 raise ValueError(860 'Elements of "tuple_fields" must be subclasses or '861 "instances of marshmallow.base.FieldABC."862 ) from error863 864 self.validate_length = Length(equal=len(self.tuple_fields))865 866 def _bind_to_schema(self, field_name: str, schema: Schema | Field) -> None:867 super()._bind_to_schema(field_name, schema)868 new_tuple_fields = []869 for field in self.tuple_fields:870 new_field = copy.deepcopy(field)871 new_field._bind_to_schema(field_name, self)872 new_tuple_fields.append(new_field)873 874 self.tuple_fields = new_tuple_fields875 876 def _serialize(self, value, attr, obj, **kwargs) -> tuple | None:877 if value is None:878 return None879 880 return tuple(881 field._serialize(each, attr, obj, **kwargs)882 for field, each in zip(self.tuple_fields, value)883 )884 885 def _deserialize(self, value, attr, data, **kwargs) -> tuple:886 if not utils.is_collection(value):887 raise self.make_error("invalid")888 889 self.validate_length(value)890 891 result = []892 errors = {}893 894 for idx, (field, each) in enumerate(zip(self.tuple_fields, value)):895 try:896 result.append(field.deserialize(each, **kwargs))897 except ValidationError as error:898 if error.valid_data is not None:899 result.append(error.valid_data)900 errors.update({idx: error.messages})901 if errors:902 raise ValidationError(errors, valid_data=result)903 904 return tuple(result)905 906 907class String(Field):908 """A string field.909 910 :param kwargs: The same keyword arguments that :class:`Field` receives.911 """912 913 #: Default error messages.914 default_error_messages = {915 "invalid": "Not a valid string.",916 "invalid_utf8": "Not a valid utf-8 string.",917 }918 919 def _serialize(self, value, attr, obj, **kwargs) -> str | None:920 if value is None:921 return None922 return utils.ensure_text_type(value)923 924 def _deserialize(self, value, attr, data, **kwargs) -> typing.Any:925 if not isinstance(value, (str, bytes)):926 raise self.make_error("invalid")927 try:928 return utils.ensure_text_type(value)929 except UnicodeDecodeError as error:930 raise self.make_error("invalid_utf8") from error931 932 933class UUID(String):934 """A UUID field."""935 936 #: Default error messages.937 default_error_messages = {"invalid_uuid": "Not a valid UUID."}938 939 def _validated(self, value) -> uuid.UUID | None:940 """Format the value or raise a :exc:`ValidationError` if an error occurs."""941 if value is None:942 return None943 if isinstance(value, uuid.UUID):944 return value945 try:946 if isinstance(value, bytes) and len(value) == 16:947 return uuid.UUID(bytes=value)948 return uuid.UUID(value)949 except (ValueError, AttributeError, TypeError) as error:950 raise self.make_error("invalid_uuid") from error951 952 def _deserialize(self, value, attr, data, **kwargs) -> uuid.UUID | None:953 return self._validated(value)954 955 956_NumType = typing.TypeVar("_NumType")957 958 959class Number(Field, typing.Generic[_NumType]):960 """Base class for number fields.961 962 :param as_string: If `True`, format the serialized value as a string.963 :param kwargs: The same keyword arguments that :class:`Field` receives.964 965 .. versionchanged:: 3.24.0966 `Number <marshmallow.fields.Number>` should no longer be used as a field within a `Schema <marshmallow.Schema>`.967 Use `Integer <marshmallow.fields.Integer>`, `Float <marshmallow.fields.Float>`, or `Decimal <marshmallow.fields.Decimal>` instead.968 """969 970 num_type: type = float971 972 #: Default error messages.973 default_error_messages = {974 "invalid": "Not a valid number.",975 "too_large": "Number too large.",976 }977 978 def __init__(self, *, as_string: bool = False, **kwargs):979 if self.__class__ is Number:980 warnings.warn(981 "`Number` field should not be instantiated. Use `Integer`, `Float`, or `Decimal` instead.",982 ChangedInMarshmallow4Warning,983 stacklevel=2,984 )985 self.as_string = as_string986 super().__init__(**kwargs)987 988 def _format_num(self, value) -> _NumType:989 """Return the number value for value, given this field's `num_type`."""990 return self.num_type(value)991 992 def _validated(self, value: typing.Any) -> _NumType:993 """Format the value or raise a :exc:`ValidationError` if an error occurs."""994 # (value is True or value is False) is ~5x faster than isinstance(value, bool)995 if value is True or value is False:996 raise self.make_error("invalid", input=value)997 try:998 return self._format_num(value)999 except (TypeError, ValueError) as error:1000 raise self.make_error("invalid", input=value) from error1001 except OverflowError as error:1002 raise self.make_error("too_large", input=value) from error1003 1004 def _to_string(self, value: _NumType) -> str:1005 return str(value)1006 1007 def _serialize(self, value, attr, obj, **kwargs) -> str | _NumType | None:1008 """Return a string if `self.as_string=True`, otherwise return this field's `num_type`."""1009 if value is None:1010 return None1011 ret: _NumType = self._format_num(value)1012 return self._to_string(ret) if self.as_string else ret1013 1014 def _deserialize(self, value, attr, data, **kwargs) -> _NumType | None:1015 return self._validated(value)1016 1017 1018class Integer(Number[int]):1019 """An integer field.1020 1021 :param strict: If `True`, only integer types are valid.1022 Otherwise, any value castable to `int` is valid.1023 :param kwargs: The same keyword arguments that :class:`Number` receives.1024 """1025 1026 num_type = int1027 1028 #: Default error messages.1029 default_error_messages = {"invalid": "Not a valid integer."}1030 1031 def __init__(self, *, strict: bool = False, **kwargs):1032 self.strict = strict1033 super().__init__(**kwargs)1034 1035 # override Number1036 def _validated(self, value: typing.Any) -> int:1037 if self.strict and not isinstance(value, numbers.Integral):1038 raise self.make_error("invalid", input=value)1039 return super()._validated(value)1040 1041 1042class Float(Number[float]):1043 """A double as an IEEE-754 double precision string.1044 1045 :param allow_nan: If `True`, `NaN`, `Infinity` and `-Infinity` are allowed,1046 even though they are illegal according to the JSON specification.1047 :param as_string: If `True`, format the value as a string.1048 :param kwargs: The same keyword arguments that :class:`Number` receives.1049 """1050 1051 num_type = float1052 1053 #: Default error messages.1054 default_error_messages = {1055 "special": "Special numeric values (nan or infinity) are not permitted."1056 }1057 1058 def __init__(self, *, allow_nan: bool = False, as_string: bool = False, **kwargs):1059 self.allow_nan = allow_nan1060 super().__init__(as_string=as_string, **kwargs)1061 1062 def _validated(self, value: typing.Any) -> float:1063 num = super()._validated(value)1064 if self.allow_nan is False:1065 if math.isnan(num) or num == float("inf") or num == float("-inf"):1066 raise self.make_error("special")1067 return num1068 1069 1070class Decimal(Number[decimal.Decimal]):1071 """A field that (de)serializes to the Python ``decimal.Decimal`` type.1072 It's safe to use when dealing with money values, percentages, ratios1073 or other numbers where precision is critical.1074 1075 .. warning::1076 1077 This field serializes to a `decimal.Decimal` object by default. If you need1078 to render your data as JSON, keep in mind that the `json` module from the1079 standard library does not encode `decimal.Decimal`. Therefore, you must use1080 a JSON library that can handle decimals, such as `simplejson`, or serialize1081 to a string by passing ``as_string=True``.1082 1083 .. warning::1084 1085 If a JSON `float` value is passed to this field for deserialization it will1086 first be cast to its corresponding `string` value before being deserialized1087 to a `decimal.Decimal` object. The default `__str__` implementation of the1088 built-in Python `float` type may apply a destructive transformation upon1089 its input data and therefore cannot be relied upon to preserve precision.1090 To avoid this, you can instead pass a JSON `string` to be deserialized1091 directly.1092 1093 :param places: How many decimal places to quantize the value. If `None`, does1094 not quantize the value.1095 :param rounding: How to round the value during quantize, for example1096 `decimal.ROUND_UP`. If `None`, uses the rounding value from1097 the current thread's context.1098 :param allow_nan: If `True`, `NaN`, `Infinity` and `-Infinity` are allowed,1099 even though they are illegal according to the JSON specification.1100 :param as_string: If `True`, serialize to a string instead of a Python1101 `decimal.Decimal` type.1102 :param kwargs: The same keyword arguments that :class:`Number` receives.1103 1104 .. versionadded:: 1.2.01105 """1106 1107 num_type = decimal.Decimal1108 1109 #: Default error messages.1110 default_error_messages = {1111 "special": "Special numeric values (nan or infinity) are not permitted."1112 }1113 1114 def __init__(1115 self,1116 places: int | None = None,1117 rounding: str | None = None,1118 *,1119 allow_nan: bool = False,1120 as_string: bool = False,1121 **kwargs,1122 ):1123 self.places = (1124 decimal.Decimal((0, (1,), -places)) if places is not None else None1125 )1126 self.rounding = rounding1127 self.allow_nan = allow_nan1128 super().__init__(as_string=as_string, **kwargs)1129 1130 # override Number1131 def _format_num(self, value):1132 num = decimal.Decimal(str(value))1133 if self.allow_nan:1134 if num.is_nan():1135 return decimal.Decimal("NaN") # avoid sNaN, -sNaN and -NaN1136 if self.places is not None and num.is_finite():1137 num = num.quantize(self.places, rounding=self.rounding)1138 return num1139 1140 # override Number1141 def _validated(self, value: typing.Any) -> decimal.Decimal:1142 try:1143 num = super()._validated(value)1144 except decimal.InvalidOperation as error:1145 raise self.make_error("invalid") from error1146 if not self.allow_nan and (num.is_nan() or num.is_infinite()):1147 raise self.make_error("special")1148 return num1149 1150 # override Number1151 def _to_string(self, value: decimal.Decimal) -> str:1152 return format(value, "f")1153 1154 1155class Boolean(Field):1156 """A boolean field.1157 1158 :param truthy: Values that will (de)serialize to `True`. If an empty1159 set, any non-falsy value will deserialize to `True`. If `None`,1160 `marshmallow.fields.Boolean.truthy` will be used.1161 :param falsy: Values that will (de)serialize to `False`. If `None`,1162 `marshmallow.fields.Boolean.falsy` will be used.1163 :param kwargs: The same keyword arguments that :class:`Field` receives.1164 """1165 1166 #: Default truthy values.1167 truthy = {1168 "t",1169 "T",1170 "true",1171 "True",1172 "TRUE",1173 "on",1174 "On",1175 "ON",1176 "y",1177 "Y",1178 "yes",1179 "Yes",1180 "YES",1181 "1",1182 1,1183 # Equal to 11184 # True,1185 }1186 #: Default falsy values.1187 falsy = {1188 "f",1189 "F",1190 "false",1191 "False",1192 "FALSE",1193 "off",1194 "Off",1195 "OFF",1196 "n",1197 "N",1198 "no",1199 "No",1200 "NO",