Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pure_eval/utils.py: 31%
96 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-20 06:09 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-20 06:09 +0000
1from collections import OrderedDict, deque
2from datetime import date, time, datetime
3from decimal import Decimal
4from fractions import Fraction
5import ast
6import enum
7import typing
10class CannotEval(Exception):
11 def __repr__(self):
12 return self.__class__.__name__
14 __str__ = __repr__
17def is_any(x, *args):
18 return any(
19 x is arg
20 for arg in args
21 )
24def of_type(x, *types):
25 if is_any(type(x), *types):
26 return x
27 else:
28 raise CannotEval
31def of_standard_types(x, *, check_dict_values: bool, deep: bool):
32 if is_standard_types(x, check_dict_values=check_dict_values, deep=deep):
33 return x
34 else:
35 raise CannotEval
38def is_standard_types(x, *, check_dict_values: bool, deep: bool):
39 try:
40 return _is_standard_types_deep(x, check_dict_values, deep)[0]
41 except RecursionError:
42 return False
45def _is_standard_types_deep(x, check_dict_values: bool, deep: bool):
46 typ = type(x)
47 if is_any(
48 typ,
49 str,
50 int,
51 bool,
52 float,
53 bytes,
54 complex,
55 date,
56 time,
57 datetime,
58 Fraction,
59 Decimal,
60 type(None),
61 object,
62 ):
63 return True, 0
65 if is_any(typ, tuple, frozenset, list, set, dict, OrderedDict, deque, slice):
66 if typ in [slice]:
67 length = 0
68 else:
69 length = len(x)
70 assert isinstance(deep, bool)
71 if not deep:
72 return True, length
74 if check_dict_values and typ in (dict, OrderedDict):
75 items = (v for pair in x.items() for v in pair)
76 elif typ is slice:
77 items = [x.start, x.stop, x.step]
78 else:
79 items = x
80 for item in items:
81 if length > 100000:
82 return False, length
83 is_standard, item_length = _is_standard_types_deep(
84 item, check_dict_values, deep
85 )
86 if not is_standard:
87 return False, length
88 length += item_length
89 return True, length
91 return False, 0
94class _E(enum.Enum):
95 pass
98class _C:
99 def foo(self): pass # pragma: nocover
101 def bar(self): pass # pragma: nocover
103 @classmethod
104 def cm(cls): pass # pragma: nocover
106 @staticmethod
107 def sm(): pass # pragma: nocover
110safe_name_samples = {
111 "len": len,
112 "append": list.append,
113 "__add__": list.__add__,
114 "insert": [].insert,
115 "__mul__": [].__mul__,
116 "fromkeys": dict.__dict__['fromkeys'],
117 "is_any": is_any,
118 "__repr__": CannotEval.__repr__,
119 "foo": _C().foo,
120 "bar": _C.bar,
121 "cm": _C.cm,
122 "sm": _C.sm,
123 "ast": ast,
124 "CannotEval": CannotEval,
125 "_E": _E,
126}
128typing_annotation_samples = {
129 name: getattr(typing, name)
130 for name in "List Dict Tuple Set Callable Mapping".split()
131}
133safe_name_types = tuple({
134 type(f)
135 for f in safe_name_samples.values()
136})
139typing_annotation_types = tuple({
140 type(f)
141 for f in typing_annotation_samples.values()
142})
145def eq_checking_types(a, b):
146 return type(a) is type(b) and a == b
149def ast_name(node):
150 if isinstance(node, ast.Name):
151 return node.id
152 elif isinstance(node, ast.Attribute):
153 return node.attr
154 else:
155 return None
158def safe_name(value):
159 typ = type(value)
160 if is_any(typ, *safe_name_types):
161 return value.__name__
162 elif value is typing.Optional:
163 return "Optional"
164 elif value is typing.Union:
165 return "Union"
166 elif is_any(typ, *typing_annotation_types):
167 return getattr(value, "__name__", None) or getattr(value, "_name", None)
168 else:
169 return None
172def has_ast_name(value, node):
173 value_name = safe_name(value)
174 if type(value_name) is not str:
175 return False
176 return eq_checking_types(ast_name(node), value_name)
179def copy_ast_without_context(x):
180 if isinstance(x, ast.AST):
181 kwargs = {
182 field: copy_ast_without_context(getattr(x, field))
183 for field in x._fields
184 if field != 'ctx'
185 if hasattr(x, field)
186 }
187 return type(x)(**kwargs)
188 elif isinstance(x, list):
189 return list(map(copy_ast_without_context, x))
190 else:
191 return x
194def ensure_dict(x):
195 """
196 Handles invalid non-dict inputs
197 """
198 try:
199 return dict(x)
200 except Exception:
201 return {}