Validating Function Arguments
To validate function arguments and execute callables with type safety, this codebase provides ArgumentsSchema for defining parameter validation rules and CallSchema for wrapping functions with those rules.
Validating and Executing a Function
The most common way to validate function arguments is to use a CallSchema. This schema combines a Python callable with an ArgumentsSchema to validate inputs, execute the function, and optionally validate the return value.
from pydantic_core import SchemaValidator, core_schema
def my_function(a: int, b: int, c: int):
return a + b + c
# Define the schema
v = SchemaValidator({
'type': 'call',
'function': my_function,
'arguments_schema': {
'type': 'arguments',
'arguments_schema': [
{'name': 'a', 'mode': 'positional_or_keyword', 'schema': {'type': 'int'}},
{'name': 'b', 'mode': 'positional_or_keyword', 'schema': {'type': 'int'}},
{'name': 'c', 'mode': 'positional_or_keyword', 'schema': {'type': 'int'}},
],
},
'return_schema': {'type': 'int', 'le': 10},
})
# Validate and execute using positional arguments
assert v.validate_python((1, 2, 3)) == 6
# Validate and execute using keyword arguments
assert v.validate_python({'a': 1, 'b': 1, 'c': 1}) == 3
Defining Parameter Modes
You can control how arguments are accepted by setting the mode in ArgumentsParameter. This corresponds to Python's function signature capabilities.
v = SchemaValidator({
'type': 'arguments',
'arguments_schema': [
# Must be passed as a positional argument
{'name': 'a', 'mode': 'positional_only', 'schema': {'type': 'int'}},
# Can be passed as positional or keyword
{'name': 'b', 'mode': 'positional_or_keyword', 'schema': {'type': 'str'}},
# Must be passed as a keyword argument
{'name': 'c', 'mode': 'keyword_only', 'schema': {'type': 'bool'}},
],
})
# Valid: a is positional, b is positional, c is keyword
from pydantic_core import ArgsKwargs
assert v.validate_python(ArgsKwargs((1, 'hello'), {'c': True})) == ((1, 'hello'), {'c': True})
Handling Variadic Arguments
To support *args and **kwargs, use var_args_schema and var_kwargs_schema within the ArgumentsSchema.
v = SchemaValidator({
'type': 'arguments',
'arguments_schema': [
{'name': 'a', 'mode': 'positional_only', 'schema': {'type': 'int'}},
],
# Validates all extra positional arguments as integers
'var_args_schema': {'type': 'int'},
# Validates all extra keyword arguments as strings
'var_kwargs_schema': {'type': 'str'},
})
# Input: a=1, args=(2, 3), kwargs={'extra': 'info'}
input_data = ArgsKwargs((1, 2, 3), {'extra': 'info'})
args, kwargs = v.validate_python(input_data)
assert args == (1, 2, 3)
assert kwargs == {'extra': 'info'}
JSON-Friendly Validation with ArgumentsV3
While ArgumentsSchema typically expects tuples or ArgsKwargs objects, ArgumentsV3Schema is designed for dictionary-based inputs, making it ideal for JSON payloads.
from pydantic_core import SchemaValidator
# ArgumentsV3Schema expects a dict where keys are parameter names
v = SchemaValidator({
'type': 'arguments-v3',
'arguments_schema': [
{'name': 'p', 'mode': 'positional_or_keyword', 'schema': {'type': 'bool'}},
{'name': 'args', 'mode': 'var_args', 'schema': {'type': 'str'}},
{'name': 'kwargs', 'mode': 'var_kwargs_uniform', 'schema': {'type': 'int'}},
],
})
# Input is a plain dictionary
data = {
'p': True,
'args': ['arg1', 'arg2'],
'kwargs': {'extra_val': 10}
}
args, kwargs = v.validate_python(data)
assert args == (True, 'arg1', 'arg2')
assert kwargs == {'extra_val': 10}
Troubleshooting and Gotchas
Input Type Requirements
ArgumentsSchema(V2): When callingvalidate_python, the input must be atuple,list, orArgsKwargsobject. Passing a dictionary will only work if the schema can map the dictionary keys to keyword arguments (and no positional-only arguments are required).ArgumentsV3Schema: Specifically expects a dictionary. Passing a tuple will result in a validation error.
Return Validation
The return_schema in CallSchema is applied after the function has executed. If the function returns a value that fails validation, a ValidationError is raised with the location return.
def fail_return():
return "not an int"
v = SchemaValidator({
'type': 'call',
'function': fail_return,
'arguments_schema': {'type': 'arguments', 'arguments_schema': []},
'return_schema': {'type': 'int'},
})
# This will raise a ValidationError because "not an int" is not an integer
# v.validate_python(())
Positional Argument Mapping
If you define multiple positional_or_keyword arguments, pydantic-core will fill them from positional inputs first, then check keyword inputs. If a value is provided for the same parameter in both, a multiple_argument_values error is raised.
# Example of multiple values error
v = SchemaValidator({
'type': 'arguments',
'arguments_schema': [
{'name': 'a', 'mode': 'positional_or_keyword', 'schema': {'type': 'int'}},
],
})
# Error: 'a' is provided both as positional (1) and keyword (a=2)
# v.validate_python(ArgsKwargs((1,), {'a': 2}))