Show More
@@ -60,7 +60,8 b' MayHaveGetattr = Union[HasGetAttr, DoesNotHaveGetAttr]' | |||||
60 | def _unbind_method(func: Callable) -> Union[Callable, None]: |
|
60 | def _unbind_method(func: Callable) -> Union[Callable, None]: | |
61 | """Get unbound method for given bound method. |
|
61 | """Get unbound method for given bound method. | |
62 |
|
62 | |||
63 |
Returns None if cannot get unbound method. |
|
63 | Returns None if cannot get unbound method, or method is already unbound. | |
|
64 | """ | |||
64 | owner = getattr(func, "__self__", None) |
|
65 | owner = getattr(func, "__self__", None) | |
65 | owner_class = type(owner) |
|
66 | owner_class = type(owner) | |
66 | name = getattr(func, "__name__", None) |
|
67 | name = getattr(func, "__name__", None) | |
@@ -214,7 +215,7 b' class SelectivePolicy(EvaluationPolicy):' | |||||
214 |
|
215 | |||
215 | accept = False |
|
216 | accept = False | |
216 |
|
217 | |||
217 | # Many objects do not have `__getattr__`, this is fine |
|
218 | # Many objects do not have `__getattr__`, this is fine. | |
218 | if has_original_attr is None and has_original_attribute: |
|
219 | if has_original_attr is None and has_original_attribute: | |
219 | accept = True |
|
220 | accept = True | |
220 | else: |
|
221 | else: | |
@@ -234,9 +235,10 b' class SelectivePolicy(EvaluationPolicy):' | |||||
234 | if not is_property: |
|
235 | if not is_property: | |
235 | return True |
|
236 | return True | |
236 |
|
237 | |||
237 | # Properties in allowed types are ok |
|
238 | # Properties in allowed types are ok (although we do not include any | |
|
239 | # properties in our default allow list currently). | |||
238 | if type(value) in self.allowed_getattr: |
|
240 | if type(value) in self.allowed_getattr: | |
239 | return True |
|
241 | return True # pragma: no cover | |
240 |
|
242 | |||
241 | # Properties in subclasses of allowed types may be ok if not changed |
|
243 | # Properties in subclasses of allowed types may be ok if not changed | |
242 | for module_name, *access_path in self.allowed_getattr_external: |
|
244 | for module_name, *access_path in self.allowed_getattr_external: |
@@ -22,7 +22,6 b' unsafe = partial(create_context, "unsafe")' | |||||
22 | dangerous = partial(create_context, "dangerous") |
|
22 | dangerous = partial(create_context, "dangerous") | |
23 |
|
23 | |||
24 | LIMITED_OR_HIGHER = [limited, unsafe, dangerous] |
|
24 | LIMITED_OR_HIGHER = [limited, unsafe, dangerous] | |
25 |
|
||||
26 | MINIMAL_OR_HIGHER = [minimal, *LIMITED_OR_HIGHER] |
|
25 | MINIMAL_OR_HIGHER = [minimal, *LIMITED_OR_HIGHER] | |
27 |
|
26 | |||
28 |
|
27 | |||
@@ -41,6 +40,39 b' def module_not_installed(module: str):' | |||||
41 | sys.modules[module] = to_restore |
|
40 | sys.modules[module] = to_restore | |
42 |
|
41 | |||
43 |
|
42 | |||
|
43 | def test_external_not_installed(): | |||
|
44 | """ | |||
|
45 | Because attribute check requires checking if object is not of allowed | |||
|
46 | external type, this tests logic for absence of external module. | |||
|
47 | """ | |||
|
48 | ||||
|
49 | class Custom: | |||
|
50 | def __init__(self): | |||
|
51 | self.test = 1 | |||
|
52 | ||||
|
53 | def __getattr__(self, key): | |||
|
54 | return key | |||
|
55 | ||||
|
56 | with module_not_installed("pandas"): | |||
|
57 | context = limited(x=Custom()) | |||
|
58 | with pytest.raises(GuardRejection): | |||
|
59 | guarded_eval("x.test", context) | |||
|
60 | ||||
|
61 | ||||
|
62 | @dec.skip_without("pandas") | |||
|
63 | def test_external_changed_api(monkeypatch): | |||
|
64 | """Check that the execution rejects if external API changed paths""" | |||
|
65 | import pandas as pd | |||
|
66 | ||||
|
67 | series = pd.Series([1], index=["a"]) | |||
|
68 | ||||
|
69 | with monkeypatch.context() as m: | |||
|
70 | m.delattr(pd, "Series") | |||
|
71 | context = limited(data=series) | |||
|
72 | with pytest.raises(GuardRejection): | |||
|
73 | guarded_eval("data.iloc[0]", context) | |||
|
74 | ||||
|
75 | ||||
44 | @dec.skip_without("pandas") |
|
76 | @dec.skip_without("pandas") | |
45 | def test_pandas_series_iloc(): |
|
77 | def test_pandas_series_iloc(): | |
46 | import pandas as pd |
|
78 | import pandas as pd | |
@@ -496,6 +528,7 b' def test_unbind_method():' | |||||
496 | x = X() |
|
528 | x = X() | |
497 | assert _unbind_method(x.index) is X.index |
|
529 | assert _unbind_method(x.index) is X.index | |
498 | assert _unbind_method([].index) is list.index |
|
530 | assert _unbind_method([].index) is list.index | |
|
531 | assert _unbind_method(list.index) is None | |||
499 |
|
532 | |||
500 |
|
533 | |||
501 | def test_assumption_instance_attr_do_not_matter(): |
|
534 | def test_assumption_instance_attr_do_not_matter(): |
General Comments 0
You need to be logged in to leave comments.
Login now