Coverage for /pythoncovmergedfiles/medio/medio/src/pydantic/pydantic/_internal/_validate_call.py: 42%

45 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-04-27 07:38 +0000

1from __future__ import annotations as _annotations 

2 

3import inspect 

4from dataclasses import dataclass 

5from functools import partial 

6from typing import Any, Callable 

7 

8import pydantic_core 

9 

10from ..config import ConfigDict 

11from . import _generate_schema, _typing_extra 

12from ._config import ConfigWrapper 

13 

14 

15@dataclass 

16class CallMarker: 

17 function: Callable[..., Any] 

18 validate_return: bool 

19 

20 

21class ValidateCallWrapper: 

22 """ 

23 This is a wrapper around a function that validates the arguments passed to it, and optionally the return value. 

24 

25 It's partially inspired by `wraps` which in turn uses `partial`, but extended to be a descriptor so 

26 these functions can be applied to instance methods, class methods, static methods, as well as normal functions. 

27 """ 

28 

29 __slots__ = ( 

30 'raw_function', 

31 '_config', 

32 '_validate_return', 

33 '__pydantic_core_schema__', 

34 '__pydantic_validator__', 

35 '__signature__', 

36 '__name__', 

37 '__qualname__', 

38 '__annotations__', 

39 '__dict__', # required for __module__ 

40 ) 

41 

42 def __init__(self, function: Callable[..., Any], config: ConfigDict | None, validate_return: bool): 

43 self.raw_function = function 

44 self._config = config 

45 self._validate_return = validate_return 

46 self.__signature__ = inspect.signature(function) 

47 if isinstance(function, partial): 

48 func = function.func 

49 self.__name__ = f'partial({func.__name__})' 

50 self.__qualname__ = f'partial({func.__qualname__})' 

51 self.__annotations__ = func.__annotations__ 

52 self.__module__ = func.__module__ 

53 self.__doc__ = func.__doc__ 

54 else: 

55 self.__name__ = function.__name__ 

56 self.__qualname__ = function.__qualname__ 

57 self.__annotations__ = function.__annotations__ 

58 self.__module__ = function.__module__ 

59 self.__doc__ = function.__doc__ 

60 

61 namespace = _typing_extra.add_module_globals(function, None) 

62 config_wrapper = ConfigWrapper(config) 

63 gen_schema = _generate_schema.GenerateSchema(config_wrapper, namespace) 

64 self.__pydantic_core_schema__ = schema = gen_schema.generate_schema(function) 

65 core_config = config_wrapper.core_config(self) 

66 self.__pydantic_validator__ = pydantic_core.SchemaValidator(schema, core_config) 

67 

68 def __call__(self, *args: Any, **kwargs: Any) -> Any: 

69 return self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args, kwargs)) 

70 

71 def __get__(self, obj: Any, objtype: type[Any] | None = None) -> ValidateCallWrapper: 

72 """ 

73 Bind the raw function and return another ValidateCallWrapper wrapping that. 

74 """ 

75 bound_function = self.raw_function.__get__(obj, objtype) 

76 return self.__class__(bound_function, self._config, self._validate_return) 

77 

78 def __repr__(self) -> str: 

79 return f'ValidateCallWrapper({self.raw_function})'