Skip to main content

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_length and str_min_length.
  • String Transformation: str_strip_whitespace, str_to_lower, and str_to_upper.
  • Numeric Behavior: allow_inf_nan and coerce_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.