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