Coverage for pydantic/_internal/_validate_call.py: 100.00%
69 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-07-01 21:48 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-07-01 21:48 +0000
1from __future__ import annotations as _annotations 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
3import functools 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
4import inspect 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
5from collections.abc import Awaitable 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
6from functools import partial 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
7from typing import Any, Callable 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
9import pydantic_core 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
11from ..config import ConfigDict 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
12from ..plugin._schema_validator import create_schema_validator 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
13from ._config import ConfigWrapper 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
14from ._generate_schema import GenerateSchema, ValidateCallSupportedTypes 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
15from ._namespace_utils import MappingNamespace, NsResolver, ns_for_function 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
18def extract_function_name(func: ValidateCallSupportedTypes) -> str: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
19 """Extract the name of a `ValidateCallSupportedTypes` object."""
20 return f'partial({func.func.__name__})' if isinstance(func, functools.partial) else func.__name__ 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
23def extract_function_qualname(func: ValidateCallSupportedTypes) -> str: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
24 """Extract the qualname of a `ValidateCallSupportedTypes` object."""
25 return f'partial({func.func.__qualname__})' if isinstance(func, functools.partial) else func.__qualname__ 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
28def update_wrapper_attributes(wrapped: ValidateCallSupportedTypes, wrapper: Callable[..., Any]): 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
29 """Update the `wrapper` function with the attributes of the `wrapped` function. Return the updated function."""
30 if inspect.iscoroutinefunction(wrapped): 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
32 @functools.wraps(wrapped) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
33 async def wrapper_function(*args, **kwargs): # type: ignore 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
34 return await wrapper(*args, **kwargs) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
35 else:
37 @functools.wraps(wrapped) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
38 def wrapper_function(*args, **kwargs): 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
39 return wrapper(*args, **kwargs) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
41 # We need to manually update this because `partial` object has no `__name__` and `__qualname__`.
42 wrapper_function.__name__ = extract_function_name(wrapped) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
43 wrapper_function.__qualname__ = extract_function_qualname(wrapped) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
44 wrapper_function.raw_function = wrapped # type: ignore 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
46 return wrapper_function 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
49class ValidateCallWrapper: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
50 """This is a wrapper around a function that validates the arguments passed to it, and optionally the return value."""
52 __slots__ = ( 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
53 'function',
54 'validate_return',
55 'schema_type',
56 'module',
57 'qualname',
58 'ns_resolver',
59 'config_wrapper',
60 '__pydantic_complete__',
61 '__pydantic_validator__',
62 '__return_pydantic_validator__',
63 )
65 def __init__( 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
66 self,
67 function: ValidateCallSupportedTypes,
68 config: ConfigDict | None,
69 validate_return: bool,
70 parent_namespace: MappingNamespace | None,
71 ) -> None:
72 self.function = function 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
73 self.validate_return = validate_return 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
74 if isinstance(function, partial): 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
75 self.schema_type = function.func 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
76 self.module = function.func.__module__ 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
77 else:
78 self.schema_type = function 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
79 self.module = function.__module__ 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
80 self.qualname = extract_function_qualname(function) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
82 self.ns_resolver = NsResolver( 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
83 namespaces_tuple=ns_for_function(self.schema_type, parent_namespace=parent_namespace)
84 )
85 self.config_wrapper = ConfigWrapper(config) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
86 if not self.config_wrapper.defer_build: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
87 self._create_validators() 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
88 else:
89 self.__pydantic_complete__ = False 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
91 def _create_validators(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
92 gen_schema = GenerateSchema(self.config_wrapper, self.ns_resolver) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
93 schema = gen_schema.clean_schema(gen_schema.generate_schema(self.function)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
94 core_config = self.config_wrapper.core_config(title=self.qualname) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
96 self.__pydantic_validator__ = create_schema_validator( 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
97 schema,
98 self.schema_type,
99 self.module,
100 self.qualname,
101 'validate_call',
102 core_config,
103 self.config_wrapper.plugin_settings,
104 )
105 if self.validate_return: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
106 signature = inspect.signature(self.function) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
107 return_type = signature.return_annotation if signature.return_annotation is not signature.empty else Any 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
108 gen_schema = GenerateSchema(self.config_wrapper, self.ns_resolver) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
109 schema = gen_schema.clean_schema(gen_schema.generate_schema(return_type)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
110 validator = create_schema_validator( 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
111 schema,
112 self.schema_type,
113 self.module,
114 self.qualname,
115 'validate_call',
116 core_config,
117 self.config_wrapper.plugin_settings,
118 )
119 if inspect.iscoroutinefunction(self.function): 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
121 async def return_val_wrapper(aw: Awaitable[Any]) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
122 return validator.validate_python(await aw) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
124 self.__return_pydantic_validator__ = return_val_wrapper 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
125 else:
126 self.__return_pydantic_validator__ = validator.validate_python 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
127 else:
128 self.__return_pydantic_validator__ = None 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
130 self.__pydantic_complete__ = True 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
132 def __call__(self, *args: Any, **kwargs: Any) -> Any: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
133 if not self.__pydantic_complete__: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
134 self._create_validators() 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
136 res = self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args, kwargs)) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
137 if self.__return_pydantic_validator__: 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
138 return self.__return_pydantic_validator__(res) 1abcdefghijklmnopqrstuvwxyzABCDEFGHI
139 else:
140 return res 1abcdefghijklmnopqrstuvwxyzABCDEFGHI