-
Notifications
You must be signed in to change notification settings - Fork 174
Expand file tree
/
Copy pathutils.py
More file actions
102 lines (83 loc) · 3.08 KB
/
utils.py
File metadata and controls
102 lines (83 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"""Utils."""
# standard
from functools import wraps
from inspect import getfullargspec
from itertools import chain
from os import environ
from typing import Any, Callable, Dict
class ValidationError(Exception):
"""Exception class when validation failure occurs."""
def __init__(self, function: Callable[..., Any], arg_dict: Dict[str, Any], message: str = ""):
"""Initialize Validation Failure."""
if message:
self.reason = message
self.func = function
self.__dict__.update(arg_dict)
def __repr__(self):
"""Repr Validation Failure."""
return (
f"ValidationError(func={self.func.__name__}, "
+ f"args={ ({k: v for (k, v) in self.__dict__.items() if k != 'func'}) })"
)
def __str__(self):
"""Str Validation Failure."""
return repr(self)
def __bool__(self):
"""Bool Validation Failure."""
return False
def _func_args_as_dict(func: Callable[..., Any], *args: Any, **kwargs: Any):
"""Return function's positional and key value arguments as an ordered dictionary."""
return dict(
list(zip(dict.fromkeys(chain(getfullargspec(func)[0], kwargs.keys())), args))
+ list(kwargs.items())
)
def validator(func: Callable[..., Any]):
"""A decorator that makes given function validator.
Whenever the given `func` returns `False` this
decorator returns `ValidationError` object.
Examples:
>>> @validator
... def even(value):
... return not (value % 2)
>>> even(4)
True
>>> even(5)
ValidationError(func=even, args={'value': 5})
Args:
func:
Function which is to be decorated.
Returns:
(Callable[..., ValidationError | Literal[True]]):
A decorator which returns either `ValidationError`
or `Literal[True]`.
Raises:
(ValidationError): If `r_ve` or `RAISE_VALIDATION_ERROR` is `True`
"""
@wraps(func)
def wrapper(*args: Any, **kwargs: Any):
raise_validation_error = False
if "r_ve" in kwargs:
raise_validation_error = True
del kwargs["r_ve"]
if environ.get("RAISE_VALIDATION_ERROR", "False") == "True":
raise_validation_error = True
try:
if raise_validation_error:
if func(*args, **kwargs):
return True
else:
raise ValidationError(func, _func_args_as_dict(func, *args, **kwargs))
else:
return (
True
if func(*args, **kwargs)
else ValidationError(func, _func_args_as_dict(func, *args, **kwargs))
)
except (ValueError, TypeError, UnicodeError) as exp:
if raise_validation_error:
raise ValidationError(
func, _func_args_as_dict(func, *args, **kwargs), str(exp)
) from exp
else:
return ValidationError(func, _func_args_as_dict(func, *args, **kwargs), str(exp))
return wrapper