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

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 

8 

9 

10class CannotEval(Exception): 

11 def __repr__(self): 

12 return self.__class__.__name__ 

13 

14 __str__ = __repr__ 

15 

16 

17def is_any(x, *args): 

18 return any( 

19 x is arg 

20 for arg in args 

21 ) 

22 

23 

24def of_type(x, *types): 

25 if is_any(type(x), *types): 

26 return x 

27 else: 

28 raise CannotEval 

29 

30 

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 

36 

37 

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 

43 

44 

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 

64 

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 

73 

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 

90 

91 return False, 0 

92 

93 

94class _E(enum.Enum): 

95 pass 

96 

97 

98class _C: 

99 def foo(self): pass # pragma: nocover 

100 

101 def bar(self): pass # pragma: nocover 

102 

103 @classmethod 

104 def cm(cls): pass # pragma: nocover 

105 

106 @staticmethod 

107 def sm(): pass # pragma: nocover 

108 

109 

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} 

127 

128typing_annotation_samples = { 

129 name: getattr(typing, name) 

130 for name in "List Dict Tuple Set Callable Mapping".split() 

131} 

132 

133safe_name_types = tuple({ 

134 type(f) 

135 for f in safe_name_samples.values() 

136}) 

137 

138 

139typing_annotation_types = tuple({ 

140 type(f) 

141 for f in typing_annotation_samples.values() 

142}) 

143 

144 

145def eq_checking_types(a, b): 

146 return type(a) is type(b) and a == b 

147 

148 

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 

156 

157 

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 

170 

171 

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) 

177 

178 

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 

192 

193 

194def ensure_dict(x): 

195 """ 

196 Handles invalid non-dict inputs 

197 """ 

198 try: 

199 return dict(x) 

200 except Exception: 

201 return {}