Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/validators/utils.py: 81%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

37 statements  

1"""Utils.""" 

2 

3# standard 

4from functools import wraps 

5from inspect import getfullargspec 

6from itertools import chain 

7from os import environ 

8from typing import Any, Callable, Dict 

9 

10 

11class ValidationError(Exception): 

12 """Exception class when validation failure occurs.""" 

13 

14 def __init__(self, function: Callable[..., Any], arg_dict: Dict[str, Any], message: str = ""): 

15 """Initialize Validation Failure.""" 

16 if message: 

17 self.reason = message 

18 self.func = function 

19 self.__dict__.update(arg_dict) 

20 

21 def __repr__(self): 

22 """Repr Validation Failure.""" 

23 return ( 

24 f"ValidationError(func={self.func.__name__}, " 

25 + f"args={ ({k: v for (k, v) in self.__dict__.items() if k != 'func'}) })" 

26 ) 

27 

28 def __str__(self): 

29 """Str Validation Failure.""" 

30 return repr(self) 

31 

32 def __bool__(self): 

33 """Bool Validation Failure.""" 

34 return False 

35 

36 

37def _func_args_as_dict(func: Callable[..., Any], *args: Any, **kwargs: Any): 

38 """Return function's positional and key value arguments as an ordered dictionary.""" 

39 return dict( 

40 list(zip(dict.fromkeys(chain(getfullargspec(func)[0], kwargs.keys())), args)) 

41 + list(kwargs.items()) 

42 ) 

43 

44 

45def validator(func: Callable[..., Any]): 

46 """A decorator that makes given function validator. 

47 

48 Whenever the given `func` returns `False` this 

49 decorator returns `ValidationError` object. 

50 

51 Examples: 

52 >>> @validator 

53 ... def even(value): 

54 ... return not (value % 2) 

55 >>> even(4) 

56 True 

57 >>> even(5) 

58 ValidationError(func=even, args={'value': 5}) 

59 

60 Args: 

61 func: 

62 Function which is to be decorated. 

63 

64 Returns: 

65 (Callable[..., ValidationError | Literal[True]]): 

66 A decorator which returns either `ValidationError` 

67 or `Literal[True]`. 

68 

69 Raises: 

70 (ValidationError): If `r_ve` or `RAISE_VALIDATION_ERROR` is `True` 

71 """ 

72 

73 @wraps(func) 

74 def wrapper(*args: Any, **kwargs: Any): 

75 raise_validation_error = bool(kwargs.pop("r_ve", False)) 

76 if environ.get("RAISE_VALIDATION_ERROR", "False") == "True": 

77 raise_validation_error = True 

78 

79 try: 

80 if raise_validation_error: 

81 if func(*args, **kwargs): 

82 return True 

83 else: 

84 raise ValidationError(func, _func_args_as_dict(func, *args, **kwargs)) 

85 else: 

86 return ( 

87 True 

88 if func(*args, **kwargs) 

89 else ValidationError(func, _func_args_as_dict(func, *args, **kwargs)) 

90 ) 

91 except (ValueError, TypeError, UnicodeError) as exp: 

92 if raise_validation_error: 

93 raise ValidationError( 

94 func, _func_args_as_dict(func, *args, **kwargs), str(exp) 

95 ) from exp 

96 else: 

97 return ValidationError(func, _func_args_as_dict(func, *args, **kwargs), str(exp)) 

98 

99 return wrapper