##// END OF EJS Templates
Handle the case of built-ins, add tests
krassowski -
Show More
@@ -600,8 +600,17 b' def eval_node(node: Union[ast.AST, None], context: EvaluationContext):'
600 not_stringized = not isinstance(sig.return_annotation, str)
600 not_stringized = not isinstance(sig.return_annotation, str)
601 if not_empty and not_stringized:
601 if not_empty and not_stringized:
602 duck = Duck()
602 duck = Duck()
603 duck.__class__ = sig.return_annotation
603 # if allow-listed builtin is on type annotation, instantiate it
604 return duck
604 if policy.can_call(sig.return_annotation) and not node.keywords:
605 args = [eval_node(arg, context) for arg in node.args]
606 return sig.return_annotation(*args)
607 try:
608 # if custom class is in type annotation, mock it;
609 # this only works for heat types, not builtins
610 duck.__class__ = sig.return_annotation
611 return duck
612 except TypeError:
613 pass
605 raise GuardRejection(
614 raise GuardRejection(
606 "Call for",
615 "Call for",
607 func, # not joined to avoid calling `repr`
616 func, # not joined to avoid calling `repr`
@@ -253,16 +253,36 b' def test_method_descriptor():'
253 assert guarded_eval("list.copy.__name__", context) == "copy"
253 assert guarded_eval("list.copy.__name__", context) == "copy"
254
254
255
255
256 class HeapType:
257 pass
258
259
260 class CallCreatesHeapType:
261 def __call__(self) -> HeapType:
262 return HeapType()
263
264
265 class CallCreatesBuiltin:
266 def __call__(self) -> frozenset:
267 return frozenset()
268
269
256 @pytest.mark.parametrize(
270 @pytest.mark.parametrize(
257 "data,good,bad,expected",
271 "data,good,bad,expected, equality",
258 [
272 [
259 [[1, 2, 3], "data.index(2)", "data.append(4)", 1],
273 [[1, 2, 3], "data.index(2)", "data.append(4)", 1, True],
260 [{"a": 1}, "data.keys().isdisjoint({})", "data.update()", True],
274 [{"a": 1}, "data.keys().isdisjoint({})", "data.update()", True, True],
275 [CallCreatesHeapType(), "data()", "data.__class__()", HeapType, False],
276 [CallCreatesBuiltin(), "data()", "data.__class__()", frozenset, False],
261 ],
277 ],
262 )
278 )
263 def test_evaluates_calls(data, good, bad, expected):
279 def test_evaluates_calls(data, good, bad, expected, equality):
264 context = limited(data=data)
280 context = limited(data=data)
265 assert guarded_eval(good, context) == expected
281 value = guarded_eval(good, context)
282 if equality:
283 assert value == expected
284 else:
285 assert isinstance(value, expected)
266
286
267 with pytest.raises(GuardRejection):
287 with pytest.raises(GuardRejection):
268 guarded_eval(bad, context)
288 guarded_eval(bad, context)
@@ -534,7 +554,7 b' def test_unbind_method():'
534 def test_assumption_instance_attr_do_not_matter():
554 def test_assumption_instance_attr_do_not_matter():
535 """This is semi-specified in Python documentation.
555 """This is semi-specified in Python documentation.
536
556
537 However, since the specification says 'not guaranted
557 However, since the specification says 'not guaranteed
538 to work' rather than 'is forbidden to work', future
558 to work' rather than 'is forbidden to work', future
539 versions could invalidate this assumptions. This test
559 versions could invalidate this assumptions. This test
540 is meant to catch such a change if it ever comes true.
560 is meant to catch such a change if it ever comes true.
General Comments 0
You need to be logged in to leave comments. Login now