Global String and Numeric Constraints
In this codebase, constraints for strings and numeric types are managed through a hierarchical system. Developers can define global defaults using the CoreConfig class, which are then applied to all relevant fields unless specifically overridden within individual schemas like StringSchema, FloatSchema, or DecimalSchema.
Global Configuration with CoreConfig
The CoreConfig class (found in pydantic_core/core_schema.py) serves as the central repository for validation and serialization settings. When initializing a SchemaValidator, the config parameter allows you to set broad behaviors that affect how strings and numbers are processed across the entire schema.
Key global attributes include:
- String Length:
str_max_lengthandstr_min_length. - String Transformation:
str_strip_whitespace,str_to_lower, andstr_to_upper. - Numeric Behavior:
allow_inf_nanandcoerce_numbers_to_str.
For example, setting a global maximum string length ensures that every string field in the schema adheres to that limit:
from pydantic_core import CoreConfig, SchemaValidator
from pydantic_core import core_schema as cs
# Global string constraint via CoreConfig
config = CoreConfig(str_max_length=5)
v = SchemaValidator(cs.str_schema(), config=config)
assert v.isinstance_python('test') is True
assert v.isinstance_python('test long') is False
String Processing and Constraints
The StringSchema allows for fine-grained control over string validation. While it inherits defaults from CoreConfig, it can explicitly define its own constraints which take precedence.
Whitespace and Case Conversion
String processing options like strip_whitespace, to_lower, and to_upper are applied during the validation phase. In this codebase, these transformations typically occur before length validation, allowing a string like " foo " to pass a max_length=3 check if strip_whitespace is enabled.
# String processing: strip and case conversion
v = SchemaValidator(cs.str_schema(strip_whitespace=True, to_upper=True))
assert v.validate_python(' fooBar ') == 'FOOBAR'
Type Coercion
The coerce_numbers_to_str setting (available in both CoreConfig and StringSchema) determines if numeric types should be automatically converted to strings. However, this behavior is suppressed when strict mode is enabled, either globally in CoreConfig or locally in the StringSchema.
Numeric Constraints: Floats vs. Decimals
The handling of special numeric values like Infinity and NaN (Not a Number) differs by default between floating-point numbers and decimals.
Floating-Point Numbers
In FloatSchema, the allow_inf_nan attribute defaults to True. This reflects standard IEEE 754 behavior where these values are common in scientific computing.
# Disallowing infinity and NaN in floats
v = SchemaValidator(cs.float_schema(allow_inf_nan=False))
# This will raise a ValidationError for 'nan', 'inf', or '-inf'
Decimal Numbers
In contrast, DecimalSchema defaults allow_inf_nan to False. This is a safety measure often required in financial contexts where NaN or Infinity could lead to critical calculation errors.
Note on Decimal Precision: In this implementation, allow_inf_nan=True is incompatible with precision constraints. If you define max_digits or decimal_places in a DecimalSchema, you cannot allow Infinity or NaN values.
Constraint Precedence
The codebase follows a "most specific wins" rule. Settings defined directly within a StringSchema, FloatSchema, or DecimalSchema always override the global defaults provided in CoreConfig.
# Field-level priority over global config
v = SchemaValidator(
cs.str_schema(max_length=5),
config=CoreConfig(str_max_length=10)
)
# The local max_length of 5 is enforced, ignoring the global 10
assert v.isinstance_python('test') is True
assert v.isinstance_python('test long') is False
This hierarchy allows developers to establish a "secure by default" configuration (e.g., global string length limits) while opting into more permissive or specific behaviors for individual fields where necessary.