Show More
@@ -60,7 +60,8 b' MayHaveGetattr = Union[HasGetAttr, DoesNotHaveGetAttr]' | |||
|
60 | 60 | def _unbind_method(func: Callable) -> Union[Callable, None]: |
|
61 | 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 | 65 | owner = getattr(func, "__self__", None) |
|
65 | 66 | owner_class = type(owner) |
|
66 | 67 | name = getattr(func, "__name__", None) |
@@ -214,7 +215,7 b' class SelectivePolicy(EvaluationPolicy):' | |||
|
214 | 215 | |
|
215 | 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 | 219 | if has_original_attr is None and has_original_attribute: |
|
219 | 220 | accept = True |
|
220 | 221 | else: |
@@ -234,9 +235,10 b' class SelectivePolicy(EvaluationPolicy):' | |||
|
234 | 235 | if not is_property: |
|
235 | 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 | 240 | if type(value) in self.allowed_getattr: |
|
239 | return True | |
|
241 | return True # pragma: no cover | |
|
240 | 242 | |
|
241 | 243 | # Properties in subclasses of allowed types may be ok if not changed |
|
242 | 244 | for module_name, *access_path in self.allowed_getattr_external: |
@@ -22,7 +22,6 b' unsafe = partial(create_context, "unsafe")' | |||
|
22 | 22 | dangerous = partial(create_context, "dangerous") |
|
23 | 23 | |
|
24 | 24 | LIMITED_OR_HIGHER = [limited, unsafe, dangerous] |
|
25 | ||
|
26 | 25 | MINIMAL_OR_HIGHER = [minimal, *LIMITED_OR_HIGHER] |
|
27 | 26 | |
|
28 | 27 | |
@@ -41,6 +40,39 b' def module_not_installed(module: str):' | |||
|
41 | 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 | 76 | @dec.skip_without("pandas") |
|
45 | 77 | def test_pandas_series_iloc(): |
|
46 | 78 | import pandas as pd |
@@ -496,6 +528,7 b' def test_unbind_method():' | |||
|
496 | 528 | x = X() |
|
497 | 529 | assert _unbind_method(x.index) is X.index |
|
498 | 530 | assert _unbind_method([].index) is list.index |
|
531 | assert _unbind_method(list.index) is None | |
|
499 | 532 | |
|
500 | 533 | |
|
501 | 534 | def test_assumption_instance_attr_do_not_matter(): |
General Comments 0
You need to be logged in to leave comments.
Login now