# Source code for marshmallow.schema

    # -*- coding: utf-8 -*-
    """The :class:`Schema` class, including its metaclass and options (class Meta)."""
    from __future__ import absolute_import, unicode_literals

    from collections import defaultdict, Mapping
    import copy
    import datetime as dt
    import decimal
    import inspect
    import json
    import uuid
    import warnings
    from collections import namedtuple, OrderedDict
    import functools

    from marshmallow import base, fields, utils, class_registry, marshalling
    from marshmallow.compat import with_metaclass, iteritems, text_type, binary_type
    from marshmallow.exceptions import ValidationError
    from marshmallow.orderedset import OrderedSet
    from marshmallow.decorators import (PRE_DUMP, POST_DUMP, PRE_LOAD, POST_LOAD,
                                        VALIDATES, VALIDATES_SCHEMA)
    from marshmallow.utils import missing

    #: Return type of :meth:`Schema.dump` including serialized data and errors
    MarshalResult = namedtuple('MarshalResult', ['data', 'errors'])
    #: Return type of :meth:`Schema.load`, including deserialized data and errors
    UnmarshalResult = namedtuple('UnmarshalResult', ['data', 'errors'])

    def _get_fields(attrs, field_class, pop=False, ordered=False):
        """Get fields from a class. If ordered=True, fields will sorted by creation index.

        :param attrs: Mapping of class attributes
        :param type field_class: Base field class
        :param bool pop: Remove matching fields
        """
        fields = [
            (field_name, field_value)
            for field_name, field_value in iteritems(attrs)
            if utils.is_instance_or_subclass(field_value, field_class)
        ]
        if pop:
            for field_name, _ in fields:
                del attrs[field_name]
        if ordered:
            fields.sort(key=lambda pair: pair[1]._creation_index)
        return fields

    # This function allows Schemas to inherit from non-Schema classes and ensures
    #   inheritance according to the MRO
    def _get_fields_by_mro(klass, field_class, ordered=False):
        """Collect fields from a class, following its method resolution order. The
        class itself is excluded from the search; only its parents are checked. Get
        fields from ``_declared_fields`` if available, else use ``__dict__``.

        :param type klass: Class whose fields to retrieve
        :param type field_class: Base field class
        """
        mro = inspect.getmro(klass)
        # Loop over mro in reverse to maintain correct order of fields
        return sum(
            (
                _get_fields(
                    getattr(base, '_declared_fields', base.__dict__),
                    field_class,
                    ordered=ordered
                )
                for base in mro[:0:-1]
            ),
            [],
        )

    class SchemaMeta(type):
        """Metaclass for the Schema class. Binds the declared fields to
        a ``_declared_fields`` attribute, which is a dictionary mapping attribute
        names to field objects. Also sets the ``opts`` class attribute, which is
        the Schema class's ``class Meta`` options.
        """

        def __new__(mcs, name, bases, attrs):
            meta = attrs.get('Meta')
            ordered = getattr(meta, 'ordered', False)
            if not ordered:
                # Inherit 'ordered' option
                # Warning: We loop through bases instead of MRO because we don't
                # yet have access to the class object
                # (i.e. can't call super before we have fields)
                for base_ in bases:
                    if hasattr(base_, 'Meta') and hasattr(base_.Meta, 'ordered'):
                        ordered = base_.Meta.ordered
                        break
                else:
                    ordered = False
            cls_fields = _get_fields(attrs, base.FieldABC, pop=True, ordered=ordered)
            klass = super(SchemaMeta, mcs).__new__(mcs, name, bases, attrs)
            inherited_fields = _get_fields_by_mro(klass, base.FieldABC, ordered=ordered)

            # Use getattr rather than attrs['Meta'] so that we get inheritance for free
            meta = getattr(klass, 'Meta')
            # Set klass.opts in __new__ rather than __init__ so that it is accessible in
            # get_declared_fields
            klass.opts = klass.OPTIONS_CLASS(meta, ordered=ordered)
            # Add fields specifid in the `include` class Meta option
            cls_fields += list(klass.opts.include.items())

            dict_cls = OrderedDict if ordered else dict
            # Assign _declared_fields on class
            klass._declared_fields = mcs.get_declared_fields(
                klass=klass,
                cls_fields=cls_fields,
                inherited_fields=inherited_fields,
                dict_cls=dict_cls
            )
            return klass

        @classmethod
        def get_declared_fields(mcs, klass, cls_fields, inherited_fields, dict_cls):
            """Returns a dictionary of field_name => `Field` pairs declard on the class.
            This is exposed mainly so that plugins can add additional fields, e.g. fields
            computed from class Meta options.

            :param type klass: The class object.
            :param dict cls_fields: The fields declared on the class, including those added
                by the ``include`` class Meta option.
            :param dict inherited_fileds: Inherited fields.
            :param type dict_class: Either `dict` or `OrderedDict`, depending on the whether
                the user specified `ordered=True`.
            """
            return dict_cls(inherited_fields + cls_fields)

        # NOTE: self is the class object
        def __init__(self, name, bases, attrs):
            super(SchemaMeta, self).__init__(name, bases, attrs)
            if name:
                class_registry.register(name, self)
            self._resolve_processors()

        def _resolve_processors(self):
            """Add in the decorated processors

            By doing this after constructing the class, we let standard inheritance
            do all the hard work.
            """
            mro = inspect.getmro(self)
            self._has_processors = False
            self.__processors__ = defaultdict(list)
            for attr_name in dir(self):
                # Need to look up the actual descriptor, not whatever might be
                # bound to the class. This needs to come from the __dict__ of the
                # declaring class.
                for parent in mro:
                    try:
                        attr = parent.__dict__[attr_name]
                    except KeyError:
                        continue
                    else:
                        break
                else:
                    # In case we didn't find the attribute and didn't break above.
                    # We should never hit this - it's just here for completeness
                    # to exclude the possibility of attr being undefined.
                    continue

                try:
                    processor_tags = attr.__marshmallow_tags__
                except AttributeError:
                    continue

                self._has_processors = bool(processor_tags)
                for tag in processor_tags:
                    # Use name here so we can get the bound method later, in case
                    # the processor was a descriptor or something.
                    self.__processors__[tag].append(attr_name)

    class SchemaOpts(object):
        """class Meta options for the :class:`Schema`. Defines defaults."""

        def __init__(self, meta, ordered=False):
            self.fields = getattr(meta, 'fields', ())
            if not isinstance(self.fields, (list, tuple)):
                raise ValueError("`fields` option must be a list or tuple.")
            self.additional = getattr(meta, 'additional', ())
            if not isinstance(self.additional, (list, tuple)):
                raise ValueError("`additional` option must be a list or tuple.")
            if self.fields and self.additional:
                raise ValueError("Cannot set both `fields` and `additional` options"
                                " for the same Schema.")
            self.exclude = getattr(meta, 'exclude', ())
            if not isinstance(self.exclude, (list, tuple)):
                raise ValueError("`exclude` must be a list or tuple.")
            self.strict = getattr(meta, 'strict', False)
            self.dateformat = getattr(meta, 'dateformat', None)
            if hasattr(meta, 'json_module'):
                warnings.warn(
                    'The json_module class Meta option is deprecated. Use render_module instead.',
                    DeprecationWarning
                )
                render_module = getattr(meta, 'json_module', json)
            else:
                render_module = json
            self.render_module = getattr(meta, 'render_module', render_module)
            self.ordered = getattr(meta, 'ordered', ordered)
            self.index_errors = getattr(meta, 'index_errors', True)
            self.include = getattr(meta, 'include', {})
            self.load_only = getattr(meta, 'load_only', ())
            self.dump_only = getattr(meta, 'dump_only', ())

    class BaseSchema(base.SchemaABC):
        """Base schema class with which to define custom schemas.

        Example usage:

        .. code-block:: python

            import datetime as dt
            from marshmallow import Schema, fields

            class Album(object):
                def __init__(self, title, release_date):
                    self.title = title
                    self.release_date = release_date

            class AlbumSchema(Schema):
                title = fields.Str()
                release_date = fields.Date()

            # Or, equivalently
            class AlbumSchema2(Schema):
                class Meta:
                    fields = ("title", "release_date")

            album = Album("Beggars Banquet", dt.date(1968, 12, 6))
            schema = AlbumSchema()
            data, errors = schema.dump(album)
            data  # {'release_date': '1968-12-06', 'title': 'Beggars Banquet'}

        :param tuple only: A list or tuple of fields to serialize. If `None`, all
            fields will be serialized. Nested fields can be represented with dot delimiters.
        :param tuple exclude: A list or tuple of fields to exclude from the
            serialized result. Nested fields can be represented with dot delimiters.
        :param str prefix: Optional prefix that will be prepended to all the
            serialized field names.
        :param bool strict: If `True`, raise errors if invalid data are passed in
            instead of failing silently and storing the errors.
        :param bool many: Should be set to `True` if ``obj`` is a collection
            so that the object will be serialized to a list.
        :param dict context: Optional context passed to :class:`fields.Method` and
            :class:`fields.Function` fields.
        :param tuple load_only: A list or tuple of fields to skip during serialization
        :param tuple dump_only: A list or tuple of fields to skip during
            deserialization, read-only fields
        :param bool|tuple partial: Whether to ignore missing fields. If its value
            is an iterable, only missing fields listed in that iterable will be
            ignored.

        .. versionchanged:: 2.0.0
            `__validators__`, `__preprocessors__`, and `__data_handlers__` are removed in favor of
            `marshmallow.decorators.validates_schema`,
            `marshmallow.decorators.pre_load` and `marshmallow.decorators.post_dump`.
            `__accessor__` and `__error_handler__` are deprecated. Implement the
            `handle_error` and `get_attribute` methods instead.
            """
        TYPE_MAPPING = {
            text_type: fields.String,
            binary_type: fields.String,
            dt.datetime: fields.DateTime,
            float: fields.Float,
            bool: fields.Boolean,
            tuple: fields.Raw,
            list: fields.Raw,
            set: fields.Raw,
            int: fields.Integer,
            uuid.UUID: fields.UUID,
            dt.time: fields.Time,
            dt.date: fields.Date,
            dt.timedelta: fields.TimeDelta,
            decimal.Decimal: fields.Decimal,
        }

        OPTIONS_CLASS = SchemaOpts

        class Meta(object):
            """Options object for a Schema.

            Example usage: ::

                class Meta:
                    fields = ("id", "email", "date_created")
                    exclude = ("password", "secret_attribute")

            Available options:

            - ``fields``: Tuple or list of fields to include in the serialized result.
            - ``additional``: Tuple or list of fields to include *in addition* to the
                explicitly declared fields. ``additional`` and ``fields`` are
                mutually-exclusive options.
            - ``include``: Dictionary of additional fields to include in the schema. It is
                usually better to define fields as class variables, but you may need to
                use this option, e.g., if your fields are Python keywords. May be an
                `OrderedDict`.
            - ``exclude``: Tuple or list of fields to exclude in the serialized result.
                Nested fields can be represented with dot delimiters.
            - ``dateformat``: Date format for all DateTime fields that do not have their
                date format explicitly specified.
            - ``strict``: If `True`, raise errors during marshalling rather than
                storing them.
            - ``render_module``: Module to use for `loads` and `dumps`. Defaults to
                `json` from the standard library.
                Defaults to the ``json`` module in the stdlib.
            - ``ordered``: If `True`, order serialization output according to the
                order in which fields were declared. Output of `Schema.dump` will be a
                `collections.OrderedDict`.
            - ``index_errors``: If `True`, errors dictionaries will include the index
                of invalid items in a collection.
            - ``load_only``: Tuple or list of fields to exclude from serialized results.
            - ``dump_only``: Tuple or list of fields to exclude from deserialization
            """
            pass

        def __init__(self, only=(), exclude=(), prefix='', strict=None,
                     many=False, context=None, load_only=(), dump_only=(),
                     partial=False):
            # copy declared fields from metaclass
            self.declared_fields = copy.deepcopy(self._declared_fields)
            self.many = many
            self.only = only
            self.exclude = exclude
            self.prefix = prefix
            self.strict = strict if strict is not None else self.opts.strict
            self.ordered = self.opts.ordered
            self.load_only = set(load_only) or set(self.opts.load_only)
            self.dump_only = set(dump_only) or set(self.opts.dump_only)
            self.partial = partial
            #: Dictionary mapping field_names -> :class:`Field` objects
            self.fields = self.dict_class()
            #: Callable marshalling object
            self._marshal = marshalling.Marshaller(
                prefix=self.prefix
            )
            #: Callable unmarshalling object
            self._unmarshal = marshalling.Unmarshaller()
            self.context = context or {}
            self._normalize_nested_options()
            self._types_seen = set()
            self._update_fields(many=many)

        def __repr__(self):
            return '<{ClassName}(many={self.many}, strict={self.strict})>'.format(
                ClassName=self.__class__.__name__, self=self
            )

        @property
        def dict_class(self):
            return OrderedDict if self.ordered else dict

        @property
        def set_class(self):
            return OrderedSet if self.ordered else set

        ##### Override-able methods #####

        def handle_error(self, error, data):
            """Custom error handler function for the schema.

            :param ValidationError error: The `ValidationError` raised during (de)serialization.
            :param data: The original input data.

            .. versionadded:: 2.0.0
            """
            pass

        def get_attribute(self, obj, attr, default):
            """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 utils.get_value(obj, attr, default)

        ##### Serialization/Deserialization API #####

        def dump(self, obj, many=None, update_fields=True, **kwargs):
            """Serialize an object to native Python data types according to this
            Schema's fields.

            :param obj: The object to serialize.
            :param bool many: Whether to serialize `obj` as a collection. If `None`, the value
                for `self.many` is used.
            :param bool update_fields: Whether to update the schema's field classes. Typically
                set to `True`, but may be `False` when serializing a homogenous collection.
                This parameter is used by `fields.Nested` to avoid multiple updates.
            :return: A tuple of the form (``data``, ``errors``)
            :rtype: `MarshalResult`, a `collections.namedtuple`

            .. versionadded:: 1.0.0
            """
            errors = {}
            many = self.many if many is None else bool(many)
            if many and utils.is_iterable_but_not_string(obj):
                obj = list(obj)

            if self._has_processors:
                try:
                    processed_obj = self._invoke_dump_processors(
                        PRE_DUMP,
                        obj,
                        many,
                        original_data=obj)
                except ValidationError as error:
                    errors = error.normalized_messages()
                    result = None
            else:
                processed_obj = obj

            if not errors:
                if update_fields:
                    obj_type = type(processed_obj)
                    if obj_type not in self._types_seen:
                        self._update_fields(processed_obj, many=many)
                        if not isinstance(processed_obj, Mapping):
                            self._types_seen.add(obj_type)

                try:
                    result = self._marshal(
                        processed_obj,
                        self.fields,
                        many=many,
                        accessor=self.get_attribute,
                        dict_class=self.dict_class,
                        index_errors=self.opts.index_errors,
                        **kwargs
                    )
                except ValidationError as error:
                    errors = self._marshal.errors
                    result = error.data

            if not errors and self._has_processors:
                try:
                    result = self._invoke_dump_processors(
                        POST_DUMP,
                        result,
                        many,
                        original_data=obj)
                except ValidationError as error:
                    errors = error.normalized_messages()
            if errors:
                exc = ValidationError(
                    errors,
                    field_names=self._marshal.error_field_names,
                    fields=self._marshal.error_fields,
                    data=obj,
                    valid_data=result,
                    **self._marshal.error_kwargs
                )
                # User-defined error handler
                self.handle_error(exc, obj)
                if self.strict:
                    raise exc

            return MarshalResult(result, errors)

        def dumps(self, obj, many=None, update_fields=True, *args, **kwargs):
            """Same as :meth:`dump`, except return a JSON-encoded string.

            :param obj: The object to serialize.
            :param bool many: Whether to serialize `obj` as a collection. If `None`, the value
                for `self.many` is used.
            :param bool update_fields: Whether to update the schema's field classes. Typically
                set to `True`, but may be `False` when serializing a homogenous collection.
                This parameter is used by `fields.Nested` to avoid multiple updates.
            :return: A tuple of the form (``data``, ``errors``)
            :rtype: `MarshalResult`, a `collections.namedtuple`

            .. versionadded:: 1.0.0
            """
            serialized, errors = self.dump(obj, many=many, update_fields=update_fields)
            ret = self.opts.render_module.dumps(serialized, *args, **kwargs)
            return MarshalResult(ret, errors)

        def load(self, data, many=None, partial=None):
            """Deserialize a data structure to an object defined by this Schema's
            fields and :meth:`make_object`.

            :param dict data: The data to deserialize.
            :param bool many: Whether to deserialize `data` as a collection. If `None`, the
                value for `self.many` is used.
            :param bool|tuple partial: Whether to ignore missing fields. If `None`,
                the value for `self.partial` is used. If its value is an iterable,
                only missing fields listed in that iterable will be ignored.
            :return: A tuple of the form (``data``, ``errors``)
            :rtype: `UnmarshalResult`, a `collections.namedtuple`

            .. versionadded:: 1.0.0
            """
            result, errors = self._do_load(data, many, partial=partial, postprocess=True)
            return UnmarshalResult(data=result, errors=errors)

        def loads(self, json_data, many=None, *args, **kwargs):
            """Same as :meth:`load`, except it takes a JSON string as input.

            :param str json_data: A JSON string of the data to deserialize.
            :param bool many: Whether to deserialize `obj` as a collection. If `None`, the
                value for `self.many` is used.
            :param bool|tuple partial: Whether to ignore missing fields. If `None`,
                the value for `self.partial` is used. If its value is an iterable,
                only missing fields listed in that iterable will be ignored.
            :return: A tuple of the form (``data``, ``errors``)
            :rtype: `UnmarshalResult`, a `collections.namedtuple`

            .. versionadded:: 1.0.0
            """
            # TODO: This avoids breaking backward compatibility if people were
            # passing in positional args after `many` for use by `json.loads`, but
            # ideally we shouldn't have to do this.
            partial = kwargs.pop('partial', None)

            data = self.opts.render_module.loads(json_data, *args, **kwargs)
            return self.load(data, many=many, partial=partial)

        def validate(self, data, many=None, partial=None):
            """Validate `data` against the schema, returning a dictionary of
            validation errors.

            :param dict data: The data to validate.
            :param bool many: Whether to validate `data` as a collection. If `None`, the
                value for `self.many` is used.
            :param bool|tuple partial: Whether to ignore missing fields. If `None`,
                the value for `self.partial` is used. If its value is an iterable,
                only missing fields listed in that iterable will be ignored.
            :return: A dictionary of validation errors.
            :rtype: dict

            .. versionadded:: 1.1.0
            """
            _, errors = self._do_load(data, many, partial=partial, postprocess=False)
            return errors

        ##### Private Helpers #####

        def _do_load(self, data, many=None, partial=None, postprocess=True):
            """Deserialize `data`, returning the deserialized result and a dictonary of
            validation errors.

            :param data: The data to deserialize.
            :param bool many: Whether to deserialize `data` as a collection. If `None`, the
                value for `self.many` is used.
            :param bool|tuple partial: Whether to validate required fields. If its value is an iterable,
                only fields listed in that iterable will be ignored will be allowed missing.
                If `True`, all fields will be allowed missing.
                If `None`, the value for `self.partial` is used.
            :param bool postprocess: Whether to run post_load methods..
            :return: A tuple of the form (`data`, `errors`)
            """
            errors = {}
            many = self.many if many is None else bool(many)
            if partial is None:
                partial = self.partial
            try:
                processed_data = self._invoke_load_processors(
                    PRE_LOAD,
                    data,
                    many,
                    original_data=data)
            except ValidationError as err:
                errors = err.normalized_messages()
                result = None
            if not errors:
                try:
                    result = self._unmarshal(
                        processed_data,
                        self.fields,
                        many=many,
                        partial=partial,
                        dict_class=self.dict_class,
                        index_errors=self.opts.index_errors,
                    )
                except ValidationError as error:
                    result = error.data
                self._invoke_field_validators(data=result, many=many)
                errors = self._unmarshal.errors
                field_errors = bool(errors)
                # Run schema-level migration
                try:
                    self._invoke_validators(pass_many=True, data=result, original_data=data, many=many,
                                            field_errors=field_errors)
                except ValidationError as err:
                    errors.update(err.messages)
                try:
                    self._invoke_validators(pass_many=False, data=result, original_data=data, many=many,
                                            field_errors=field_errors)
                except ValidationError as err:
                    errors.update(err.messages)
            # Run post processors
            if not errors and postprocess:
                try:
                    result = self._invoke_load_processors(
                        POST_LOAD,
                        result,
                        many,
                        original_data=data)
                except ValidationError as err:
                    errors = err.normalized_messages()
            if errors:
                exc = ValidationError(
                    errors,
                    field_names=self._unmarshal.error_field_names,
                    fields=self._unmarshal.error_fields,
                    data=data,
                    valid_data=result,
                    **self._unmarshal.error_kwargs
                )
                self.handle_error(exc, data)
                if self.strict:
                    raise exc

            return result, errors

        def _normalize_nested_options(self):
            """Apply then flatten nested schema options"""
            if self.only:
                # Apply the only option to nested fields.
                self.__apply_nested_option('only', self.only)
                # Remove the child field names from the only option.
                self.only = self.set_class(
                    [field.split('.', 1)[0] for field in self.only])
            excludes = set(self.opts.exclude) | set(self.exclude)
            if excludes:
                # Apply the exclude option to nested fields.
                self.__apply_nested_option('exclude', excludes)
            if self.exclude:
                # Remove the parent field names from the exclude option.
                self.exclude = self.set_class(
                    [field for field in self.exclude if '.' not in field])
            if self.opts.exclude:
                # Remove the parent field names from the meta exclude option.
                self.opts.exclude = self.set_class(
                    [field for field in self.opts.exclude if '.' not in field])

        def __apply_nested_option(self, option_name, field_names):
            """Apply nested options to nested fields"""
            # Split nested field names on the first dot.
            nested_fields = [name.split('.', 1) for name in field_names if '.' in name]
            # Partition the nested field names by parent field.
            nested_options = defaultdict(list)
            for parent, nested_names in nested_fields:
                nested_options[parent].append(nested_names)
            # Apply the nested field options.
            for key, options in iter(nested_options.items()):
                setattr(self.declared_fields[key], option_name, self.set_class(options))

        def _update_fields(self, obj=None, many=False):
            """Update fields based on the passed in object."""
            if self.only:
                # Return only fields specified in only option
                if self.opts.fields:
                    field_names = self.set_class(self.opts.fields) & self.set_class(self.only)
                else:
                    field_names = self.set_class(self.only)
            elif self.opts.fields:
                # Return fields specified in fields option
                field_names = self.set_class(self.opts.fields)
            elif self.opts.additional:
                # Return declared fields + additional fields
                field_names = (self.set_class(self.declared_fields.keys()) |
                                self.set_class(self.opts.additional))
            else:
                field_names = self.set_class(self.declared_fields.keys())

            # If "exclude" option or param is specified, remove those fields
            excludes = set(self.opts.exclude) | set(self.exclude)
            if excludes:
                field_names = field_names - excludes
            ret = self.__filter_fields(field_names, obj, many=many)
            # Set parents
            self.__set_field_attrs(ret)
            self.fields = ret
            return self.fields

        def on_bind_field(self, field_name, field_obj):
            """Hook to modify a field when it is bound to the `Schema`. No-op by default."""
            return None

        def __set_field_attrs(self, fields_dict):
            """Bind fields to the schema, setting any necessary attributes
            on the fields (e.g. parent and name).

            Also set field load_only and dump_only values if field_name was
            specified in ``class Meta``.
            """
            for field_name, field_obj in iteritems(fields_dict):
                try:
                    if field_name in self.load_only:
                        field_obj.load_only = True
                    if field_name in self.dump_only:
                        field_obj.dump_only = True
                    field_obj._add_to_schema(field_name, self)
                    self.on_bind_field(field_name, field_obj)
                except TypeError:
                    # field declared as a class, not an instance
                    if (isinstance(field_obj, type) and
                            issubclass(field_obj, base.FieldABC)):
                        msg = ('Field for "{0}" must be declared as a '
                               'Field instance, not a class. '
                               'Did you mean "fields.{1}()"?'
                               .format(field_name, field_obj.__name__))
                        raise TypeError(msg)
            return fields_dict

        def __filter_fields(self, field_names, obj, many=False):
            """Return only those field_name:field_obj pairs specified by
            ``field_names``.

            :param set field_names: Field names to include in the final
                return dictionary.
            :returns: An dict of field_name:field_obj pairs.
            """
            if obj and many:
                try:  # Homogeneous collection
                    # Prefer getitem over iter to prevent breaking serialization
                    # of objects for which iter will modify position in the collection
                    # e.g. Pymongo cursors
                    if hasattr(obj, '__getitem__') and callable(getattr(obj, '__getitem__')):
                        try:
                            obj_prototype = obj[0]
                        except KeyError:
                            obj_prototype = next(iter(obj))
                    else:
                        obj_prototype = next(iter(obj))
                except (StopIteration, IndexError):  # Nothing to serialize
                    return {k: v for k, v in self.declared_fields.items() if k in field_names}
                obj = obj_prototype
            ret = self.dict_class()
            for key in field_names:
                if key in self.declared_fields:
                    ret[key] = self.declared_fields[key]
                else:  # Implicit field creation (class Meta 'fields' or 'additional')
                    if obj:
                        attribute_type = None
                        try:
                            if isinstance(obj, Mapping):
                                attribute_type = type(obj[key])
                            else:
                                attribute_type = type(getattr(obj, key))
                        except (AttributeError, KeyError) as err:
                            err_type = type(err)
                            raise err_type(
                                '"{0}" is not a valid field for {1}.'.format(key, obj))
                        field_obj = self.TYPE_MAPPING.get(attribute_type, fields.Field)()
                    else:  # Object is None
                        field_obj = fields.Field()
                    # map key -> field (default to Raw)
                    ret[key] = field_obj
            return ret

        def _invoke_dump_processors(self, tag_name, data, many, original_data=None):
            # The pass_many post-dump processors may do things like add an envelope, so
            # invoke those after invoking the non-pass_many processors which will expect
            # to get a list of items.
            data = self._invoke_processors(tag_name, pass_many=False,
                data=data, many=many, original_data=original_data)
            data = self._invoke_processors(tag_name, pass_many=True,
                data=data, many=many, original_data=original_data)
            return data

        def _invoke_load_processors(self, tag_name, data, many, original_data=None):
            # This has to invert the order of the dump processors, so run the pass_many
            # processors first.
            data = self._invoke_processors(tag_name, pass_many=True,
                data=data, many=many, original_data=original_data)
            data = self._invoke_processors(tag_name, pass_many=False,
                data=data, many=many, original_data=original_data)
            return data

        def _invoke_field_validators(self, data, many):
            for attr_name in self.__processors__[(VALIDATES, False)]:
                validator = getattr(self, attr_name)
                validator_kwargs = validator.__marshmallow_kwargs__[(VALIDATES, False)]
                field_name = validator_kwargs['field_name']

                try:
                    field_obj = self.fields[field_name]
                except KeyError:
                    if field_name in self.declared_fields:
                        continue
                    raise ValueError('"{0}" field does not exist.'.format(field_name))

                if many:
                    for idx, item in enumerate(data):
                        try:
                            value = item[field_obj.attribute or field_name]
                        except KeyError:
                            pass
                        else:
                            validated_value = self._unmarshal.call_and_store(
                                getter_func=validator,
                                data=value,
                                field_name=field_name,
                                field_obj=field_obj,
                                index=(idx if self.opts.index_errors else None)
                            )
                            if validated_value is missing:
                                data[idx].pop(field_name, None)
                else:
                    try:
                        value = data[field_obj.attribute or field_name]
                    except KeyError:
                        pass
                    else:
                        validated_value = self._unmarshal.call_and_store(
                            getter_func=validator,
                            data=value,
                            field_name=field_name,
                            field_obj=field_obj
                        )
                        if validated_value is missing:
                            data.pop(field_name, None)

        def _invoke_validators(self, pass_many, data, original_data, many, field_errors=False):
            errors = {}
            for attr_name in self.__processors__[(VALIDATES_SCHEMA, pass_many)]:
                validator = getattr(self, attr_name)
                validator_kwargs = validator.__marshmallow_kwargs__[(VALIDATES_SCHEMA, pass_many)]
                pass_original = validator_kwargs.get('pass_original', False)

                skip_on_field_errors = validator_kwargs['skip_on_field_errors']
                if skip_on_field_errors and field_errors:
                    continue

                if pass_many:
                    validator = functools.partial(validator, many=many)
                if many and not pass_many:
                    for idx, item in enumerate(data):
                        try:
                            self._unmarshal.run_validator(validator,
                                                      item, original_data, self.fields, many=many,
                                                      index=idx, pass_original=pass_original)
                        except ValidationError as err:
                            errors.update(err.messages)
                else:
                    try:
                        self._unmarshal.run_validator(validator,
                                                  data, original_data, self.fields, many=many,
                                                  pass_original=pass_original)
                    except ValidationError as err:
                        errors.update(err.messages)
            if errors:
                raise ValidationError(errors)
            return None

        def _invoke_processors(self, tag_name, pass_many, data, many, original_data=None):
            for attr_name in self.__processors__[(tag_name, pass_many)]:
                # This will be a bound method.
                processor = getattr(self, attr_name)

                processor_kwargs = processor.__marshmallow_kwargs__[(tag_name, pass_many)]
                pass_original = processor_kwargs.get('pass_original', False)

                if pass_many:
                    if pass_original:
                        data = utils.if_none(processor(data, many, original_data), data)
                    else:
                        data = utils.if_none(processor(data, many), data)
                elif many:
                    if pass_original:
                        data = [utils.if_none(processor(item, original_data), item)
                                for item in data]
                    else:
                        data = [utils.if_none(processor(item), item) for item in data]
                else:
                    if pass_original:
                        data = utils.if_none(processor(data, original_data), data)
                    else:
                        data = utils.if_none(processor(data), data)
            return data

    class Schema(with_metaclass(SchemaMeta, BaseSchema)):
        __doc__ = BaseSchema.__doc__