Module dataclasses_json.mm
View Source
# flake8: noqa import typing import warnings import sys from copy import deepcopy from dataclasses import MISSING, is_dataclass, fields as dc_fields from datetime import datetime from decimal import Decimal from uuid import UUID from enum import Enum from typing_inspect import is_union_type # type: ignore from marshmallow import fields, Schema, post_load from marshmallow_enum import EnumField # type: ignore from marshmallow.exceptions import ValidationError from dataclasses_json.core import (_is_supported_generic, _decode_dataclass, _ExtendedEncoder, _user_overrides_or_exts) from dataclasses_json.utils import (_is_collection, _is_optional, _issubclass_safe, _timestamp_to_dt_aware, _is_new_type, _get_type_origin, _handle_undefined_parameters_safe, CatchAllVar) class _TimestampField(fields.Field): def _serialize(self, value, attr, obj, **kwargs): if value is not None: return value.timestamp() else: if not self.required: return None else: raise ValidationError(self.default_error_messages["required"]) def _deserialize(self, value, attr, data, **kwargs): if value is not None: return _timestamp_to_dt_aware(value) else: if not self.required: return None else: raise ValidationError(self.default_error_messages["required"]) class _IsoField(fields.Field): def _serialize(self, value, attr, obj, **kwargs): if value is not None: return value.isoformat() else: if not self.required: return None else: raise ValidationError(self.default_error_messages["required"]) def _deserialize(self, value, attr, data, **kwargs): if value is not None: return datetime.fromisoformat(value) else: if not self.required: return None else: raise ValidationError(self.default_error_messages["required"]) class _UnionField(fields.Field): def __init__(self, desc, cls, field, *args, **kwargs): self.desc = desc self.cls = cls self.field = field super().__init__(*args, **kwargs) def _serialize(self, value, attr, obj, **kwargs): if self.allow_none and value is None: return None for type_, schema_ in self.desc.items(): if _issubclass_safe(type(value), type_): if is_dataclass(value): res = schema_._serialize(value, attr, obj, **kwargs) res['__type'] = str(type_.__name__) return res break elif isinstance(value, _get_type_origin(type_)): return schema_._serialize(value, attr, obj, **kwargs) else: warnings.warn( f'The type "{type(value).__name__}" (value: "{value}") ' f'is not in the list of possible types of typing.Union ' f'(dataclass: {self.cls.__name__}, field: {self.field.name}). ' f'Value cannot be serialized properly.') return super()._serialize(value, attr, obj, **kwargs) def _deserialize(self, value, attr, data, **kwargs): tmp_value = deepcopy(value) if isinstance(tmp_value, dict) and '__type' in tmp_value: dc_name = tmp_value['__type'] for type_, schema_ in self.desc.items(): if is_dataclass(type_) and type_.__name__ == dc_name: del tmp_value['__type'] return schema_._deserialize(tmp_value, attr, data, **kwargs) for type_, schema_ in self.desc.items(): if isinstance(tmp_value, _get_type_origin(type_)): return schema_._deserialize(tmp_value, attr, data, **kwargs) else: warnings.warn( f'The type "{type(tmp_value).__name__}" (value: "{tmp_value}") ' f'is not in the list of possible types of typing.Union ' f'(dataclass: {self.cls.__name__}, field: {self.field.name}). ' f'Value cannot be deserialized properly.') return super()._deserialize(tmp_value, attr, data, **kwargs) TYPES = { typing.Mapping: fields.Mapping, typing.MutableMapping: fields.Mapping, typing.List: fields.List, typing.Dict: fields.Dict, typing.Tuple: fields.Tuple, typing.Callable: fields.Function, typing.Any: fields.Raw, dict: fields.Dict, list: fields.List, tuple: fields.Tuple, str: fields.Str, int: fields.Int, float: fields.Float, bool: fields.Bool, datetime: _TimestampField, UUID: fields.UUID, Decimal: fields.Decimal, CatchAllVar: fields.Dict, } A = typing.TypeVar('A') JsonData = typing.Union[str, bytes, bytearray] TEncoded = typing.Dict[str, typing.Any] TOneOrMulti = typing.Union[typing.List[A], A] TOneOrMultiEncoded = typing.Union[typing.List[TEncoded], TEncoded] if sys.version_info >= (3, 7): class SchemaF(Schema, typing.Generic[A]): """Lift Schema into a type constructor""" def __init__(self, *args, **kwargs): """ Raises exception because this class should not be inherited. This class is helper only. """ super().__init__(*args, **kwargs) raise NotImplementedError() @typing.overload def dump(self, obj: typing.List[A], many: bool = None) -> typing.List[ TEncoded]: # type: ignore # mm has the wrong return type annotation (dict) so we can ignore the mypy error pass @typing.overload def dump(self, obj: A, many: bool = None) -> TEncoded: pass def dump(self, obj: TOneOrMulti, many: bool = None) -> TOneOrMultiEncoded: pass @typing.overload def dumps(self, obj: typing.List[A], many: bool = None, *args, **kwargs) -> str: pass @typing.overload def dumps(self, obj: A, many: bool = None, *args, **kwargs) -> str: pass def dumps(self, obj: TOneOrMulti, many: bool = None, *args, **kwargs) -> str: pass @typing.overload # type: ignore def load(self, data: typing.List[TEncoded], many: bool = True, partial: bool = None, unknown: str = None) -> \ typing.List[A]: # ignore the mypy error of the decorator because mm does not define lists as an allowed input type pass @typing.overload def load(self, data: TEncoded, many: None = None, partial: bool = None, unknown: str = None) -> A: pass def load(self, data: TOneOrMultiEncoded, many: bool = None, partial: bool = None, unknown: str = None) -> TOneOrMulti: pass @typing.overload # type: ignore def loads(self, json_data: JsonData, # type: ignore many: bool = True, partial: bool = None, unknown: str = None, **kwargs) -> typing.List[A]: # ignore the mypy error of the decorator because mm does not define bytes as correct input data # mm has the wrong return type annotation (dict) so we can ignore the mypy error # for the return type overlap pass @typing.overload def loads(self, json_data: JsonData, many: None = None, partial: bool = None, unknown: str = None, **kwargs) -> A: pass def loads(self, json_data: JsonData, many: bool = None, partial: bool = None, unknown: str = None, **kwargs) -> TOneOrMulti: pass SchemaType = SchemaF[A] else: SchemaType = Schema def build_type(type_, options, mixin, field, cls): def inner(type_, options): while True: if not _is_new_type(type_): break type_ = type_.__supertype__ if is_dataclass(type_): if _issubclass_safe(type_, mixin): options['field_many'] = bool( _is_supported_generic(field.type) and _is_collection( field.type)) return fields.Nested(type_.schema(), **options) else: warnings.warn(f"Nested dataclass field {field.name} of type " f"{field.type} detected in " f"{cls.__name__} that is not an instance of " f"dataclass_json. Did you mean to recursively " f"serialize this field? If so, make sure to " f"augment {type_} with either the " f"`dataclass_json` decorator or mixin.") return fields.Field(**options) origin = getattr(type_, '__origin__', type_) args = [inner(a, {}) for a in getattr(type_, '__args__', []) if a is not type(None)] if _is_optional(type_): options["allow_none"] = True if origin in TYPES: return TYPES[origin](*args, **options) if _issubclass_safe(origin, Enum): return EnumField(enum=origin, by_value=True, *args, **options) if is_union_type(type_): union_types = [a for a in getattr(type_, '__args__', []) if a is not type(None)] union_desc = dict(zip(union_types, args)) return _UnionField(union_desc, cls, field, **options) warnings.warn( f"Unknown type {type_} at {cls.__name__}.{field.name}: {field.type} " f"It's advised to pass the correct marshmallow type to `mm_field`.") return fields.Field(**options) return inner(type_, options) def schema(cls, mixin, infer_missing): schema = {} overrides = _user_overrides_or_exts(cls) # TODO check the undefined parameters and add the proper schema action # https://marshmallow.readthedocs.io/en/stable/quickstart.html for field in dc_fields(cls): metadata = (field.metadata or {}).get('dataclasses_json', {}) metadata = overrides[field.name] if metadata.mm_field is not None: schema[field.name] = metadata.mm_field else: type_ = field.type options = {} missing_key = 'missing' if infer_missing else 'default' if field.default is not MISSING: options[missing_key] = field.default elif field.default_factory is not MISSING: options[missing_key] = field.default_factory if options.get(missing_key, ...) is None: options['allow_none'] = True if _is_optional(type_): options.setdefault(missing_key, None) options['allow_none'] = True if len(type_.__args__) == 2: # Union[str, int, None] is optional too, but it has more than 1 typed field. type_ = type_.__args__[0] if metadata.letter_case is not None: options['data_key'] = metadata.letter_case(field.name) t = build_type(type_, options, mixin, field, cls) # if type(t) is not fields.Field: # If we use `isinstance` we would return nothing. if field.type != typing.Optional[CatchAllVar]: schema[field.name] = t return schema def build_schema(cls: typing.Type[A], mixin, infer_missing, partial) -> typing.Type[SchemaType]: Meta = type('Meta', (), {'fields': tuple(field.name for field in dc_fields(cls) if field.name != 'dataclass_json_config' and field.type != typing.Optional[CatchAllVar]), # TODO #180 # 'render_module': global_config.json_module }) @post_load def make_instance(self, kvs, **kwargs): return _decode_dataclass(cls, kvs, partial) def dumps(self, *args, **kwargs): if 'cls' not in kwargs: kwargs['cls'] = _ExtendedEncoder return Schema.dumps(self, *args, **kwargs) def dump(self, obj, *, many=None): many = self.many if many is None else bool(many) dumped = Schema.dump(self, obj, many=many) # TODO This is hacky, but the other option I can think of is to generate a different schema # depending on dump and load, which is even more hacky # The only problem is the catch all field, we can't statically create a schema for it # so we just update the dumped dict if many: for i, _obj in enumerate(obj): dumped[i].update( _handle_undefined_parameters_safe(cls=_obj, kvs={}, usage="dump")) else: dumped.update(_handle_undefined_parameters_safe(cls=obj, kvs={}, usage="dump")) return dumped schema_ = schema(cls, mixin, infer_missing) DataClassSchema: typing.Type[SchemaType] = type( f'{cls.__name__.capitalize()}Schema', (Schema,), {'Meta': Meta, f'make_{cls.__name__.lower()}': make_instance, 'dumps': dumps, 'dump': dump, **schema_}) return DataClassSchema
Variables
A
JsonData
SchemaType
TEncoded
TOneOrMulti
TOneOrMultiEncoded
TYPES
Functions
build_schema
def build_schema( cls: Type[~A], mixin, infer_missing, partial ) -> Type[dataclasses_json.mm.SchemaF[~A]]
View Source
def build_schema(cls: typing.Type[A], mixin, infer_missing, partial) -> typing.Type[SchemaType]: Meta = type('Meta', (), {'fields': tuple(field.name for field in dc_fields(cls) if field.name != 'dataclass_json_config' and field.type != typing.Optional[CatchAllVar]), # TODO #180 # 'render_module': global_config.json_module }) @post_load def make_instance(self, kvs, **kwargs): return _decode_dataclass(cls, kvs, partial) def dumps(self, *args, **kwargs): if 'cls' not in kwargs: kwargs['cls'] = _ExtendedEncoder return Schema.dumps(self, *args, **kwargs) def dump(self, obj, *, many=None): many = self.many if many is None else bool(many) dumped = Schema.dump(self, obj, many=many) # TODO This is hacky, but the other option I can think of is to generate a different schema # depending on dump and load, which is even more hacky # The only problem is the catch all field, we can't statically create a schema for it # so we just update the dumped dict if many: for i, _obj in enumerate(obj): dumped[i].update( _handle_undefined_parameters_safe(cls=_obj, kvs={}, usage="dump")) else: dumped.update(_handle_undefined_parameters_safe(cls=obj, kvs={}, usage="dump")) return dumped schema_ = schema(cls, mixin, infer_missing) DataClassSchema: typing.Type[SchemaType] = type( f'{cls.__name__.capitalize()}Schema', (Schema,), {'Meta': Meta, f'make_{cls.__name__.lower()}': make_instance, 'dumps': dumps, 'dump': dump, **schema_}) return DataClassSchema
build_type
def build_type( type_, options, mixin, field, cls )
View Source
def build_type(type_, options, mixin, field, cls): def inner(type_, options): while True: if not _is_new_type(type_): break type_ = type_.__supertype__ if is_dataclass(type_): if _issubclass_safe(type_, mixin): options['field_many'] = bool( _is_supported_generic(field.type) and _is_collection( field.type)) return fields.Nested(type_.schema(), **options) else: warnings.warn(f"Nested dataclass field {field.name} of type " f"{field.type} detected in " f"{cls.__name__} that is not an instance of " f"dataclass_json. Did you mean to recursively " f"serialize this field? If so, make sure to " f"augment {type_} with either the " f"`dataclass_json` decorator or mixin.") return fields.Field(**options) origin = getattr(type_, '__origin__', type_) args = [inner(a, {}) for a in getattr(type_, '__args__', []) if a is not type(None)] if _is_optional(type_): options["allow_none"] = True if origin in TYPES: return TYPES[origin](*args, **options) if _issubclass_safe(origin, Enum): return EnumField(enum=origin, by_value=True, *args, **options) if is_union_type(type_): union_types = [a for a in getattr(type_, '__args__', []) if a is not type(None)] union_desc = dict(zip(union_types, args)) return _UnionField(union_desc, cls, field, **options) warnings.warn( f"Unknown type {type_} at {cls.__name__}.{field.name}: {field.type} " f"It's advised to pass the correct marshmallow type to `mm_field`.") return fields.Field(**options) return inner(type_, options)
schema
def schema( cls, mixin, infer_missing )
View Source
def schema(cls, mixin, infer_missing): schema = {} overrides = _user_overrides_or_exts(cls) # TODO check the undefined parameters and add the proper schema action # https://marshmallow.readthedocs.io/en/stable/quickstart.html for field in dc_fields(cls): metadata = (field.metadata or {}).get('dataclasses_json', {}) metadata = overrides[field.name] if metadata.mm_field is not None: schema[field.name] = metadata.mm_field else: type_ = field.type options = {} missing_key = 'missing' if infer_missing else 'default' if field.default is not MISSING: options[missing_key] = field.default elif field.default_factory is not MISSING: options[missing_key] = field.default_factory if options.get(missing_key, ...) is None: options['allow_none'] = True if _is_optional(type_): options.setdefault(missing_key, None) options['allow_none'] = True if len(type_.__args__) == 2: # Union[str, int, None] is optional too, but it has more than 1 typed field. type_ = type_.__args__[0] if metadata.letter_case is not None: options['data_key'] = metadata.letter_case(field.name) t = build_type(type_, options, mixin, field, cls) # if type(t) is not fields.Field: # If we use `isinstance` we would return nothing. if field.type != typing.Optional[CatchAllVar]: schema[field.name] = t return schema
Classes
SchemaF
class SchemaF( *args, **kwargs )
Lift Schema into a type constructor
View Source
class SchemaF(Schema, typing.Generic[A]): """Lift Schema into a type constructor""" def __init__(self, *args, **kwargs): """ Raises exception because this class should not be inherited. This class is helper only. """ super().__init__(*args, **kwargs) raise NotImplementedError() @typing.overload def dump(self, obj: typing.List[A], many: bool = None) -> typing.List[ TEncoded]: # type: ignore # mm has the wrong return type annotation (dict) so we can ignore the mypy error pass @typing.overload def dump(self, obj: A, many: bool = None) -> TEncoded: pass def dump(self, obj: TOneOrMulti, many: bool = None) -> TOneOrMultiEncoded: pass @typing.overload def dumps(self, obj: typing.List[A], many: bool = None, *args, **kwargs) -> str: pass @typing.overload def dumps(self, obj: A, many: bool = None, *args, **kwargs) -> str: pass def dumps(self, obj: TOneOrMulti, many: bool = None, *args, **kwargs) -> str: pass @typing.overload # type: ignore def load(self, data: typing.List[TEncoded], many: bool = True, partial: bool = None, unknown: str = None) -> \ typing.List[A]: # ignore the mypy error of the decorator because mm does not define lists as an allowed input type pass @typing.overload def load(self, data: TEncoded, many: None = None, partial: bool = None, unknown: str = None) -> A: pass def load(self, data: TOneOrMultiEncoded, many: bool = None, partial: bool = None, unknown: str = None) -> TOneOrMulti: pass @typing.overload # type: ignore def loads(self, json_data: JsonData, # type: ignore many: bool = True, partial: bool = None, unknown: str = None, **kwargs) -> typing.List[A]: # ignore the mypy error of the decorator because mm does not define bytes as correct input data # mm has the wrong return type annotation (dict) so we can ignore the mypy error # for the return type overlap pass @typing.overload def loads(self, json_data: JsonData, many: None = None, partial: bool = None, unknown: str = None, **kwargs) -> A: pass def loads(self, json_data: JsonData, many: bool = None, partial: bool = None, unknown: str = None, **kwargs) -> TOneOrMulti: pass
Ancestors (in MRO)
- marshmallow.schema.Schema
- marshmallow.base.SchemaABC
- typing.Generic
Class variables
Meta
OPTIONS_CLASS
TYPE_MAPPING
error_messages
opts
Static methods
from_dict
def from_dict( fields: Dict[str, Union[marshmallow.fields.Field, type]], *, name: str = 'GeneratedSchema' ) -> type
Generate a Schema
class given a dictionary of fields.
.. code-block:: python
from marshmallow import Schema, fields PersonSchema = Schema.from_dict({"name": fields.Str()}) print(PersonSchema().load({"name": "David"})) # => {'name': 'David'}
Generated schemas are not added to the class registry and therefore cannot
be referred to by name in Nested
fields.
:param dict fields: Dictionary mapping field names to field instances.
:param str name: Optional name for the class, which will appear in
the repr
for the class.
.. versionadded:: 3.0.0
View Source
@classmethod def from_dict( cls, fields: typing.Dict[str, typing.Union[ma_fields.Field, type]], *, name: str = "GeneratedSchema" ) -> type: """Generate a `Schema` class given a dictionary of fields. .. code-block:: python from marshmallow import Schema, fields PersonSchema = Schema.from_dict({"name": fields.Str()}) print(PersonSchema().load({"name": "David"})) # => {'name': 'David'} Generated schemas are not added to the class registry and therefore cannot be referred to by name in `Nested` fields. :param dict fields: Dictionary mapping field names to field instances. :param str name: Optional name for the class, which will appear in the ``repr`` for the class. .. versionadded:: 3.0.0 """ attrs = fields.copy() attrs["Meta"] = type( "GeneratedMeta", (getattr(cls, "Meta", object),), {"register": False} ) schema_cls = type(name, (cls,), attrs) return schema_cls
Instance variables
dict_class
set_class
Methods
dump
def dump( self, obj: Union[List[~A], ~A], many: bool = None ) -> Union[List[Dict[str, Any]], Dict[str, Any]]
Serialize an object to native Python data types according to this Schema's fields.
:param obj: The object to serialize.
:param many: Whether to serialize obj
as a collection. If None
, the value
for self.many
is used.
:return: A dict of serialized data
:rtype: dict
.. versionadded:: 1.0.0
.. versionchanged:: 3.0.0b7
This method returns the serialized data rather than a (data, errors)
duple.
A :exc:ValidationError <marshmallow.exceptions.ValidationError>
is raised
if obj
is invalid.
.. versionchanged:: 3.0.0rc9
Validation no longer occurs upon serialization.
View Source
def dump(self, obj: TOneOrMulti, many: bool = None) -> TOneOrMultiEncoded: pass
dumps
def dumps( self, obj: Union[List[~A], ~A], many: bool = None, *args, **kwargs ) -> str
Same as :meth:dump
, except return a JSON-encoded string.
:param obj: The object to serialize.
:param many: Whether to serialize obj
as a collection. If None
, the value
for self.many
is used.
:return: A json
string
:rtype: str
.. versionadded:: 1.0.0
.. versionchanged:: 3.0.0b7
This method returns the serialized data rather than a (data, errors)
duple.
A :exc:ValidationError <marshmallow.exceptions.ValidationError>
is raised
if obj
is invalid.
View Source
def dumps(self, obj: TOneOrMulti, many: bool = None, *args, **kwargs) -> str: pass
get_attribute
def get_attribute( self, obj: Any, attr: str, default: Any )
Defines how to pull values from an object to serialize.
.. versionadded:: 2.0.0
.. versionchanged:: 3.0.0a1
Changed position of obj
and attr
.
View Source
def get_attribute(self, obj: typing.Any, attr: str, default: typing.Any): """Defines how to pull values from an object to serialize. .. versionadded:: 2.0.0 .. versionchanged:: 3.0.0a1 Changed position of ``obj`` and ``attr``. """ return get_value(obj, attr, default)
handle_error
def handle_error( self, error: marshmallow.exceptions.ValidationError, data: Any, *, many: bool, **kwargs )
Custom error handler function for the schema.
:param error: The ValidationError
raised during (de)serialization.
:param data: The original input data.
:param many: Value of many
on dump or load.
:param partial: Value of partial
on load.
.. versionadded:: 2.0.0
.. versionchanged:: 3.0.0rc9
Receives many
and partial
(on deserialization) as keyword arguments.
View Source
def handle_error( self, error: ValidationError, data: typing.Any, *, many: bool, **kwargs ): """Custom error handler function for the schema. :param error: The `ValidationError` raised during (de)serialization. :param data: The original input data. :param many: Value of ``many`` on dump or load. :param partial: Value of ``partial`` on load. .. versionadded:: 2.0.0 .. versionchanged:: 3.0.0rc9 Receives `many` and `partial` (on deserialization) as keyword arguments. """ pass
load
def load( self, data: Union[List[Dict[str, Any]], Dict[str, Any]], many: bool = None, partial: bool = None, unknown: str = None ) -> Union[List[~A], ~A]
Deserialize a data structure to an object defined by this Schema's fields.
:param data: The data to deserialize.
:param many: Whether to deserialize data
as a collection. If None
, the
value for self.many
is used.
:param partial: Whether to ignore missing fields and not require
any fields declared. Propagates down to Nested
fields as well. If
its value is an iterable, only missing fields listed in that iterable
will be ignored. Use dot delimiters to specify nested fields.
:param unknown: Whether to exclude, include, or raise an error for unknown
fields in the data. Use EXCLUDE
, INCLUDE
or RAISE
.
If None
, the value for self.unknown
is used.
:return: Deserialized data
.. versionadded:: 1.0.0
.. versionchanged:: 3.0.0b7
This method returns the deserialized data rather than a (data, errors)
duple.
A :exc:ValidationError <marshmallow.exceptions.ValidationError>
is raised
if invalid data are passed.
View Source
def load(self, data: TOneOrMultiEncoded, many: bool = None, partial: bool = None, unknown: str = None) -> TOneOrMulti: pass
loads
def loads( self, json_data: Union[str, bytes, bytearray], many: bool = None, partial: bool = None, unknown: str = None, **kwargs ) -> Union[List[~A], ~A]
Same as :meth:load
, except it takes a JSON string as input.
:param json_data: A JSON string of the data to deserialize.
:param many: Whether to deserialize obj
as a collection. If None
, the
value for self.many
is used.
:param partial: Whether to ignore missing fields and not require
any fields declared. Propagates down to Nested
fields as well. If
its value is an iterable, only missing fields listed in that iterable
will be ignored. Use dot delimiters to specify nested fields.
:param unknown: Whether to exclude, include, or raise an error for unknown
fields in the data. Use EXCLUDE
, INCLUDE
or RAISE
.
If None
, the value for self.unknown
is used.
:return: Deserialized data
.. versionadded:: 1.0.0
.. versionchanged:: 3.0.0b7
This method returns the deserialized data rather than a (data, errors)
duple.
A :exc:ValidationError <marshmallow.exceptions.ValidationError>
is raised
if invalid data are passed.
View Source
def loads(self, json_data: JsonData, many: bool = None, partial: bool = None, unknown: str = None, **kwargs) -> TOneOrMulti: pass
on_bind_field
def on_bind_field( self, field_name: str, field_obj: marshmallow.fields.Field ) -> None
Hook to modify a field when it is bound to the Schema
.
No-op by default.
View Source
def on_bind_field(self, field_name: str, field_obj: ma_fields.Field) -> None: """Hook to modify a field when it is bound to the `Schema`. No-op by default. """ return None
validate
def validate( self, data: Mapping, *, many: bool = None, partial: Union[bool, Sequence[str], Set[str]] = None ) -> Dict[str, List[str]]
Validate data
against the schema, returning a dictionary of
validation errors.
:param data: The data to validate.
:param many: Whether to validate data
as a collection. If None
, the
value for self.many
is used.
:param partial: Whether to ignore missing fields and not require
any fields declared. Propagates down to Nested
fields as well. If
its value is an iterable, only missing fields listed in that iterable
will be ignored. Use dot delimiters to specify nested fields.
:return: A dictionary of validation errors.
.. versionadded:: 1.1.0
View Source
def validate( self, data: typing.Mapping, *, many: bool = None, partial: typing.Union[bool, types.StrSequenceOrSet] = None ) -> typing.Dict[str, typing.List[str]]: """Validate `data` against the schema, returning a dictionary of validation errors. :param data: The data to validate. :param many: Whether to validate `data` as a collection. If `None`, the value for `self.many` is used. :param partial: Whether to ignore missing fields and not require any fields declared. Propagates down to ``Nested`` fields as well. If its value is an iterable, only missing fields listed in that iterable will be ignored. Use dot delimiters to specify nested fields. :return: A dictionary of validation errors. .. versionadded:: 1.1.0 """ try: self._do_load(data, many=many, partial=partial, postprocess=False) except ValidationError as exc: return typing.cast(typing.Dict[str, typing.List[str]], exc.messages) return {}