Tuple Schemas
Tuple schemas in pydantic-core provide a flexible way to validate Python tuples, supporting both fixed-size positional collections and variadic (variable-length) collections. The primary interface for defining these schemas is the tuple_schema factory function, which produces a TupleSchema configuration.
Core Concepts
The TupleSchema (defined in pydantic_core/core_schema.py) is a TypedDict that centralizes tuple validation logic. Unlike lists, tuples in Python often carry semantic meaning based on the position of their elements. pydantic-core handles this through two primary modes:
- Positional (Fixed-size): Each element at a specific index must match a corresponding schema.
- Variadic (Variable-length): A specific schema is applied to all elements (or all remaining elements) in the tuple.
The tuple_schema Factory
The tuple_schema function is the unified entry point for creating tuple validators. It replaces the older, specialized tuple_positional_schema and tuple_variable_schema functions.
from pydantic_core import core_schema
# Basic positional tuple: tuple[int, str]
schema = core_schema.tuple_schema(
[core_schema.int_schema(), core_schema.str_schema()]
)
Positional Tuples
A positional tuple is defined by providing a list of schemas to items_schema. By default, the input must have exactly the same number of elements as there are schemas in items_schema.
from pydantic_core import SchemaValidator, core_schema
schema = core_schema.tuple_schema(
[core_schema.int_schema(), core_schema.str_schema()]
)
v = SchemaValidator(schema)
# Valid input
assert v.validate_python((1, 'hello')) == (1, 'hello')
Variadic Tuples
Variadic tuples (equivalent to Python's tuple[T, ...]) are implemented using the variadic_item_index parameter. This index points to the element in items_schema that should be used to validate all "extra" items in the input.
To create a purely variadic tuple where every item is an integer:
from pydantic_core import SchemaValidator, core_schema
schema = core_schema.tuple_schema(
[core_schema.int_schema()],
variadic_item_index=0
)
v = SchemaValidator(schema)
assert v.validate_python((1, 2, 3, 4)) == (1, 2, 3, 4)
Mixed Positional and Variadic
You can combine fixed positions with a variadic tail. For example, a tuple that starts with an int and a str, followed by any number of float values:
from pydantic_core import SchemaValidator, core_schema
schema = core_schema.tuple_schema(
[
core_schema.int_schema(),
core_schema.str_schema(),
core_schema.float_schema()
],
variadic_item_index=2,
)
v = SchemaValidator(schema)
# (int, str, float, float, ...)
assert v.validate_python((1, 'hello', 1.5, 2.5, 3.5)) == (1, 'hello', 1.5, 2.5, 3.5)
In this configuration, the schema at index 2 (float_schema) is applied to the third element and every element thereafter.
Validation Constraints
TupleSchema supports several constraints to fine-tune validation behavior:
Length Constraints
For variadic tuples, you can enforce minimum and maximum lengths using min_length and max_length.
schema = core_schema.tuple_schema(
[core_schema.int_schema()],
variadic_item_index=0,
min_length=2,
max_length=4
)
Strict Mode
When strict=True, the validator requires the input to be a literal Python tuple. In the default lax mode, pydantic-core accepts other iterables (like list, deque, or generators) and coerces them into a tuple.
Fail Fast
The fail_fast parameter (found in pydantic-core/tests/validators/test_tuple.py) determines whether validation should stop immediately upon encountering the first error within the tuple elements.
schema = core_schema.tuple_schema(
[core_schema.str_schema(), core_schema.int_schema()],
fail_fast=True
)
Input Handling and Coercion
In non-strict mode, pydantic-core is permissive with tuple inputs. It can validate and coerce various iterable types:
- Lists:
[1, 2]becomes(1, 2). - Generators: Elements are consumed and collected into a tuple.
- Strings: Note that strings are not treated as iterables for tuple validation to avoid accidental character-by-character splitting.
Validated Generators
When a generator_schema is used as an item within a tuple, pydantic-core maintains lazy evaluation. As noted in pydantic_core/core_schema.py, ValidationErrors for generator items are raised only when the violating value is actually read, rather than during the initial tuple validation.
Internal Implementation and Deprecations
The current implementation of tuple_schema in pydantic_core/core_schema.py is a unified factory. The older functions tuple_positional_schema and tuple_variable_schema are now thin wrappers around tuple_schema:
tuple_positional_schemamaps itsextras_schemato avariadic_item_indexat the end of theitems_schemalist.tuple_variable_schemamaps its singleitems_schemato avariadic_item_index=0.
Developers are encouraged to use tuple_schema directly for all tuple validation needs.