Skip to main content

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:

  1. Positional (Fixed-size): Each element at a specific index must match a corresponding schema.
  2. 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_schema maps its extras_schema to a variadic_item_index at the end of the items_schema list.
  • tuple_variable_schema maps its single items_schema to a variadic_item_index=0.

Developers are encouraged to use tuple_schema directly for all tuple validation needs.