Validation Context and Configuration
Validation in this codebase is not just about checking types; it involves a rich system for passing configuration and runtime state through the validation pipeline. This is achieved primarily through two entities: CoreConfig, which defines global settings for a validator, and ValidationInfo, which provides runtime context to custom validator functions.
Global Configuration with CoreConfig
The CoreConfig class (defined in pydantic_core/core_schema) is a TypedDict that specifies how a SchemaValidator should behave across all fields. When you instantiate a SchemaValidator, you can provide a config object to set these global rules.
Common configuration options include:
strict: When set toTrue, the validator will not attempt to coerce types (e.g., it won't turn the string"123"into an integer).extra_fields_behavior: Controls how to handle fields not defined in the schema (e.g.,'allow','forbid', or'ignore').str_max_length/str_min_length: Sets global constraints for all string fields unless overridden by a specific field's schema.hide_input_in_errors: A security-focused setting that prevents the original input data from being included inValidationErrormessages.
Example: Setting Global Config
In this example, we set a global title and strict mode via CoreConfig.
from pydantic_core import CoreConfig, SchemaValidator, core_schema
config = CoreConfig(title='MyValidator', strict=True)
v = SchemaValidator(core_schema.int_schema(), config=config)
# This will fail because strict=True prevents string-to-int coercion
# v.validate_python('123') -> Raises ValidationError
Runtime Context with ValidationInfo
While CoreConfig is static for the lifetime of a SchemaValidator, ValidationInfo provides dynamic, runtime information to custom validator functions. If you use "with info" validator functions (like with_info_before_validator_function), the second argument passed to your function will be an instance of ValidationInfo.
The ValidationInfo protocol provides access to:
config: TheCoreConfigobject used to initialize the validator.context: Arbitrary data passed at runtime via thecontextargument ofvalidate_python.mode: Indicates whether the input is'python'or'json'.data: A dictionary containing other fields that have already been validated (useful for cross-field validation).field_name: The name of the field currently being validated.
Accessing Context and Config
The following pattern, found in pydantic-core/tests/validators/test_function.py, demonstrates how a custom validator can inspect both the global configuration and the runtime context.
from pydantic_core import CoreConfig, SchemaValidator, core_schema
def validator_func(input_value, info: core_schema.ValidationInfo):
# Access global config
assert info.config.get('title') == 'hello'
# Access runtime context
assert info.context == {'user_id': 123}
return input_value
v = SchemaValidator(
core_schema.with_info_before_validator_function(validator_func, core_schema.str_schema()),
config=CoreConfig(title='hello')
)
# Passing context at runtime
v.validate_python('some input', context={'user_id': 123})
Cross-Field Validation and Field Metadata
One of the most powerful features of ValidationInfo is its ability to facilitate cross-field validation through the data and field_name properties.
info.data: In the context of aTypedDictor a model,info.datacontains the values of fields that have already been successfully validated. This allows a field's validation logic to depend on the value of another field.info.field_name: This tells the validator which specific field it is currently processing.
Example: Cross-Field Validation
This example (adapted from pydantic-core/tests/validators/test_function.py) shows a validator for field x accessing the value of other_field.
from typing import Any
from pydantic_core import SchemaValidator, core_schema
def check_dependency(input_value: Any, info: core_schema.ValidationInfo) -> Any:
# info.field_name will be 'x'
# info.data will contain {'other_field': 1}
if info.data.get('other_field') == 1:
return f'Validated {info.field_name} with dependency: {input_value}'
return input_value
v = SchemaValidator(
core_schema.typed_dict_schema({
'other_field': core_schema.typed_dict_field(core_schema.int_schema()),
'x': core_schema.typed_dict_field(
core_schema.with_info_after_validator_function(check_dependency, core_schema.str_schema())
),
})
)
result = v.validate_python({'other_field': 1, 'x': 'hello'})
# result == {'other_field': 1, 'x': 'Validated x with dependency: hello'}
Validation Modes
The info.mode property allows validators to behave differently depending on whether they are processing Python objects or JSON strings. This is particularly useful when certain coercions or checks are only appropriate for one input type.
def mode_aware_validator(input_value, info: core_schema.ValidationInfo):
if info.mode == 'json':
# Perform specific logic for JSON inputs
pass
return input_value
By combining the static settings in CoreConfig with the dynamic state in ValidationInfo, the validation engine provides a flexible environment for implementing complex, context-aware validation logic.