<commit_before>.. _extending:
.. module:: marshmallow

Extending Schemas
=================

Handling Errors
---------------

By default, :meth:`Schema.dump` and :meth:`Schema.load` will return validation errors as a dictionary (unless ``strict`` mode is enabled).

You can register a custom error-handling function for a :class:`Schema` using the :meth:`Schema.error_handler` decorator. The function receives the schema instance, the errors dictionary, and the original object to be serialized.


.. code-block:: python

    import logging
    from marshmallow import Schema, fields

    class AppError(Exception):
        pass

    class UserSchema(Schema):
        email = fields.Email()

    # Log and raise our custom exception when serialization
    # or deserialization fails
    @UserSchema.error_handler
    def handle_errors(schema, errors, obj):
        logging.error(errors)
        raise AppError('An error occurred while serializing {0}'.format(obj))

    invalid = User('Foo Bar', email='invalid-email')
    schema = UserSchema()
    schema.dump(invalid)  # raises AppError
    schema.load({'email': 'invalid-email'})  # raises AppError

.. _schemavalidation:

Schema-level Validation
-----------------------

You can register schema-level validation functions for a :class:`Schema` using the :meth:`Schema.validator` decorator. The function receives the schema instance and the input data
as arguments. Schema-level validation errors will be stored on the ``_schema`` key of the errors dictonary.

.. code-block:: python

    from marshmallow import Schema, fields, ValidationError

    class NumberSchema(Schema):
        field_a = fields.Integer()
        field_b = fields.Integer()

    @NumberSchema.validator
    def validate_numbers(schema, input_data):
        if input_data['field_b'] >= input_data['field_a']:
            raise ValidationError('field_a must be greater than field_b')

    schema = NumberSchema()
    result, errors = schema.load({'field_a': 2, 'field_b': 1})
    errors['_schema'] # => ["field_a must be greater than field_b"]


Storing Errors on Specific Fields
+++++++++++++++++++++++++++++++++

If you want to store schema-level validation errors on a specific field, you can pass a field name to the :exc:`ValidationError`.

.. code-block:: python

    @NumberSchema.validator
    def validate_numbers(schema, input_data):
        if input_data['field_b'] >= input_data['field_a']:
            # Store error on field_a
            raise ValidationError('field_a must be greater than field_b', 'field_a')

    schema = NumberSchema()
    result, errors = schema.load({'field_a': 2, 'field_b': 1})
    errors['field_a'] # => ["field_a must be greater than field_b"]

Pre-processing Input Data
-------------------------

Data pre-processing functions can be registered using :meth:`Schema.preprocessor`. A pre-processing function receives the schema instace and the input data as arguments and must return the dictionary of processed data.
<commit_msg>Document optional raw_data argument.<commit_after>.. _extending:
.. module:: marshmallow

Extending Schemas
=================

Handling Errors
---------------

By default, :meth:`Schema.dump` and :meth:`Schema.load` will return validation errors as a dictionary (unless ``strict`` mode is enabled).

You can register a custom error-handling function for a :class:`Schema` using the :meth:`Schema.error_handler` decorator. The function receives the schema instance, the errors dictionary, and the original object to be serialized.


.. code-block:: python

    import logging
    from marshmallow import Schema, fields

    class AppError(Exception):
        pass

    class UserSchema(Schema):
        email = fields.Email()

    # Log and raise our custom exception when serialization
    # or deserialization fails
    @UserSchema.error_handler
    def handle_errors(schema, errors, obj):
        logging.error(errors)
        raise AppError('An error occurred while serializing {0}'.format(obj))

    invalid = User('Foo Bar', email='invalid-email')
    schema = UserSchema()
    schema.dump(invalid)  # raises AppError
    schema.load({'email': 'invalid-email'})  # raises AppError

.. _schemavalidation:

Schema-level Validation
-----------------------

You can register schema-level validation functions for a :class:`Schema` using the :meth:`Schema.validator` decorator. The function receives the schema instance and the input data
as arguments. Schema-level validation errors will be stored on the ``_schema`` key of the errors dictonary.

.. code-block:: python

    from marshmallow import Schema, fields, ValidationError

    class NumberSchema(Schema):
        field_a = fields.Integer()
        field_b = fields.Integer()

    @NumberSchema.validator
    def validate_numbers(schema, input_data):
        if input_data['field_b'] >= input_data['field_a']:
            raise ValidationError('field_a must be greater than field_b')

    schema = NumberSchema()
    result, errors = schema.load({'field_a': 2, 'field_b': 1})
    errors['_schema'] # => ["field_a must be greater than field_b"]


Validating Raw Input Data
+++++++++++++++++++++++++

Normally, unspecified field names are ignored by the validator. If you would like access to the raw input (e.g. to fail validation if an unknown field name is sent), an optional third argument will contain the raw input data.

.. code-block:: python

    @NumberSchema.validator
    def check_unknown_fields(schema, input_data, raw_data):
        for k in raw_data:
            if k not in schema.fields:
                raise ValidationError('Unknown field name')

    schema = NumberSchema()
    result, errors = schema.load({'field_c': 0})
    errors['_schema'] # => ["Unknown field name"]


Storing Errors on Specific Fields
+++++++++++++++++++++++++++++++++

If you want to store schema-level validation errors on a specific field, you can pass a field name to the :exc:`ValidationError`.

.. code-block:: python

    @NumberSchema.validator
    def validate_numbers(schema, input_data):
        if input_data['field_b'] >= input_data['field_a']:
            # Store error on field_a
            raise ValidationError('field_a must be greater than field_b', 'field_a')

    schema = NumberSchema()
    result, errors = schema.load({'field_a': 2, 'field_b': 1})
    errors['field_a'] # => ["field_a must be greater than field_b"]

Pre-processing Input Data
-------------------------

Data pre-processing functions can be registered using :meth:`Schema.preprocessor`. A pre-processing function receives the schema instace and the input data as arguments and must return the dictionary of processed data.

{'fraction_non_alphanumeric': 0.12719627571707465, 'fraction_numerical': 0.001651899684637333, 'mean_word_length': 3.536784741144414, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6567735', 'n_tokens_mistral': 1805, 'n_tokens_neox': 1718, 'n_words': 650}