Skip to main content

Configuring Global Scalar Behavior

Global scalar behavior in pydantic-core is controlled via the CoreConfig TypedDict. This configuration allows you to define default validation and serialization rules for basic types like strings, floats, and temporal objects across an entire schema.

Setting Global String Constraints

You can enforce length limits and apply transformations to all string fields by passing a CoreConfig instance to the SchemaValidator.

from pydantic_core import CoreConfig, SchemaValidator, core_schema as cs

# Define global string length limits
config = CoreConfig(
str_max_length=5,
str_min_length=2,
str_strip_whitespace=True,
str_to_lower=True
)

v = SchemaValidator(cs.str_schema(), config=config)

# Valid input: length is 4, whitespace is stripped, converted to lower
assert v.validate_python(' TEST ') == 'test'

# Invalid input: exceeds str_max_length
try:
v.validate_python('too long')
except Exception as e:
print(e) # String should have at most 5 characters

Key string configuration attributes include:

  • str_max_length / str_min_length: Sets the global bounds for string length.
  • str_strip_whitespace: When True, leading and trailing whitespace is removed during validation.
  • str_to_lower / str_to_upper: Automatically converts strings to the specified case.

Controlling Float Validation and Serialization

CoreConfig manages how non-finite numbers (Infinity and NaN) are handled during both validation and JSON serialization.

Validation: allow_inf_nan

By default, pydantic-core allows non-finite floats. You can disable this globally using allow_inf_nan.

from pydantic_core import CoreConfig, SchemaValidator, core_schema as cs

# Disallow non-finite numbers globally
config = CoreConfig(allow_inf_nan=False)
v = SchemaValidator(cs.float_schema(), config=config)

# This will raise a ValidationError with type 'finite_number'
try:
v.validate_python(float('nan'))
except Exception as e:
print(e) # Input should be a finite number

Serialization: ser_json_inf_nan

JSON does not natively support NaN or Infinity. Use ser_json_inf_nan to define how these should be represented in JSON output.

from pydantic_core import CoreConfig, SchemaSerializer, core_schema as cs

# Options: 'null' (default), 'constants' (Infinity), 'strings' ("Infinity")
config = CoreConfig(ser_json_inf_nan='strings')
s = SchemaSerializer(cs.float_schema(), config=config)

assert s.to_json(float('inf')) == b'"Infinity"'
assert s.to_json(float('nan')) == b'"NaN"'

Defining Temporal Serialization Formats

Temporal types (datetime, date, time, timedelta) default to ISO 8601 serialization. You can change this globally to numeric timestamps using ser_json_temporal.

from pydantic_core import SchemaSerializer, core_schema as cs
from datetime import datetime

# Serialize all temporal types to Unix timestamps (seconds)
config = {'ser_json_temporal': 'seconds'}
s = SchemaSerializer(cs.datetime_schema(), config=config)

dt = datetime(2024, 1, 1)
# to_python with mode='json' simulates the JSON serialization process
assert s.to_python(dt, mode='json') == 1704067200.0

Available formats for ser_json_temporal:

  • 'iso8601': Standard string format (e.g., "2024-01-01T00:00:00").
  • 'seconds': Float representing Unix epoch seconds.
  • 'milliseconds': Float representing Unix epoch milliseconds.

Scoping and Precedence

Configuration settings follow a specific hierarchy. Understanding these rules is critical for troubleshooting unexpected behavior.

Field-Level Overrides

Specific constraints defined within a schema (e.g., cs.str_schema(max_length=2)) always take precedence over global CoreConfig settings.

from pydantic_core import CoreConfig, SchemaValidator, core_schema as cs

# Global max is 10, but field max is 5
config = CoreConfig(str_max_length=10)
v = SchemaValidator(cs.str_schema(max_length=5), config=config)

# This fails because the field-level constraint (5) is used
assert v.isinstance_python('123456') is False

Temporal Precedence

If both ser_json_temporal and ser_json_timedelta are provided in the configuration, ser_json_temporal takes precedence and is used for timedelta serialization as well.

# ser_json_temporal overrides ser_json_timedelta
config = {
'ser_json_temporal': 'seconds',
'ser_json_timedelta': 'iso8601'
}
# timedeltas will be serialized as seconds, not ISO 8601

Model-Specific Configuration

You can scope CoreConfig to a specific model by including it in the model_schema definition rather than passing it to the top-level validator.

v = SchemaValidator(
cs.model_schema(
cls=dict,
config=CoreConfig(str_max_length=5),
schema=cs.model_fields_schema(fields={
'name': cs.model_field(schema=cs.str_schema())
}),
)
)