Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
fields.py2154 linesDownload Raw Back to marshmallow
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",

Showing the first 1,200 of 2154 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai