Show More
@@ -31,6 +31,7 b' jobs:' | |||||
31 | run: | |
|
31 | run: | | |
32 | mypy -p IPython.terminal |
|
32 | mypy -p IPython.terminal | |
33 | mypy -p IPython.core.magics |
|
33 | mypy -p IPython.core.magics | |
|
34 | mypy -p IPython.core.guarded_eval | |||
34 | - name: Lint with pyflakes |
|
35 | - name: Lint with pyflakes | |
35 | run: | |
|
36 | run: | | |
36 | flake8 IPython/core/magics/script.py |
|
37 | flake8 IPython/core/magics/script.py |
@@ -1,4 +1,15 b'' | |||||
1 | from typing import Callable, Set, Tuple, NamedTuple, Literal, Union, TYPE_CHECKING |
|
1 | from typing import ( | |
|
2 | Any, | |||
|
3 | Callable, | |||
|
4 | Set, | |||
|
5 | Tuple, | |||
|
6 | NamedTuple, | |||
|
7 | Type, | |||
|
8 | Literal, | |||
|
9 | Union, | |||
|
10 | TYPE_CHECKING, | |||
|
11 | ) | |||
|
12 | import builtins | |||
2 | import collections |
|
13 | import collections | |
3 | import sys |
|
14 | import sys | |
4 | import ast |
|
15 | import ast | |
@@ -21,7 +32,7 b' class HasGetItem(Protocol):' | |||||
21 |
|
32 | |||
22 |
|
33 | |||
23 | class InstancesHaveGetItem(Protocol): |
|
34 | class InstancesHaveGetItem(Protocol): | |
24 | def __call__(self) -> HasGetItem: |
|
35 | def __call__(self, *args, **kwargs) -> HasGetItem: | |
25 | ... |
|
36 | ... | |
26 |
|
37 | |||
27 |
|
38 | |||
@@ -55,6 +66,7 b' def unbind_method(func: Callable) -> Union[Callable, None]:' | |||||
55 | ) |
|
66 | ) | |
56 | ): |
|
67 | ): | |
57 | return getattr(owner_class, name) |
|
68 | return getattr(owner_class, name) | |
|
69 | return None | |||
58 |
|
70 | |||
59 |
|
71 | |||
60 | @dataclass |
|
72 | @dataclass | |
@@ -137,7 +149,7 b' def has_original_dunder(' | |||||
137 |
|
149 | |||
138 | @dataclass |
|
150 | @dataclass | |
139 | class SelectivePolicy(EvaluationPolicy): |
|
151 | class SelectivePolicy(EvaluationPolicy): | |
140 |
allowed_getitem: Set[ |
|
152 | allowed_getitem: Set[InstancesHaveGetItem] = field(default_factory=set) | |
141 | allowed_getitem_external: Set[Tuple[str, ...]] = field(default_factory=set) |
|
153 | allowed_getitem_external: Set[Tuple[str, ...]] = field(default_factory=set) | |
142 | allowed_getattr: Set[MayHaveGetattr] = field(default_factory=set) |
|
154 | allowed_getattr: Set[MayHaveGetattr] = field(default_factory=set) | |
143 | allowed_getattr_external: Set[Tuple[str, ...]] = field(default_factory=set) |
|
155 | allowed_getattr_external: Set[Tuple[str, ...]] = field(default_factory=set) | |
@@ -368,8 +380,9 b' def eval_node(node: Union[ast.AST, None], context: EvaluationContext):' | |||||
368 | return context.locals_[node.id] |
|
380 | return context.locals_[node.id] | |
369 | if policy.allow_globals_access and node.id in context.globals_: |
|
381 | if policy.allow_globals_access and node.id in context.globals_: | |
370 | return context.globals_[node.id] |
|
382 | return context.globals_[node.id] | |
371 |
if policy.allow_builtins_access and node.id |
|
383 | if policy.allow_builtins_access and hasattr(builtins, node.id): | |
372 | return __builtins__[node.id] |
|
384 | # note: do not use __builtins__, it is implementation detail of Python | |
|
385 | return getattr(builtins, node.id) | |||
373 | if not policy.allow_globals_access and not policy.allow_locals_access: |
|
386 | if not policy.allow_globals_access and not policy.allow_locals_access: | |
374 | raise GuardRejection( |
|
387 | raise GuardRejection( | |
375 | f"Namespace access not allowed in {context.evaluation} mode" |
|
388 | f"Namespace access not allowed in {context.evaluation} mode" | |
@@ -413,7 +426,7 b' SUPPORTED_EXTERNAL_GETITEM = {' | |||||
413 | ("numpy", "void"), |
|
426 | ("numpy", "void"), | |
414 | } |
|
427 | } | |
415 |
|
428 | |||
416 | BUILTIN_GETITEM = { |
|
429 | BUILTIN_GETITEM: Set[InstancesHaveGetItem] = { | |
417 | dict, |
|
430 | dict, | |
418 | str, |
|
431 | str, | |
419 | bytes, |
|
432 | bytes, | |
@@ -441,8 +454,8 b' list_non_mutating_methods = ("copy", "index", "count")' | |||||
441 | set_non_mutating_methods = set(dir(set)) & set(dir(frozenset)) |
|
454 | set_non_mutating_methods = set(dir(set)) & set(dir(frozenset)) | |
442 |
|
455 | |||
443 |
|
456 | |||
444 | dict_keys = type({}.keys()) |
|
457 | dict_keys: Type[collections.abc.KeysView] = type({}.keys()) | |
445 | method_descriptor = type(list.copy) |
|
458 | method_descriptor: Any = type(list.copy) | |
446 |
|
459 | |||
447 | ALLOWED_CALLS = { |
|
460 | ALLOWED_CALLS = { | |
448 | bytes, |
|
461 | bytes, | |
@@ -479,6 +492,16 b' ALLOWED_CALLS = {' | |||||
479 | collections.Counter.most_common, |
|
492 | collections.Counter.most_common, | |
480 | } |
|
493 | } | |
481 |
|
494 | |||
|
495 | BUILTIN_GETATTR: Set[MayHaveGetattr] = { | |||
|
496 | *BUILTIN_GETITEM, | |||
|
497 | set, | |||
|
498 | frozenset, | |||
|
499 | object, | |||
|
500 | type, # `type` handles a lot of generic cases, e.g. numbers as in `int.real`. | |||
|
501 | dict_keys, | |||
|
502 | method_descriptor, | |||
|
503 | } | |||
|
504 | ||||
482 | EVALUATION_POLICIES = { |
|
505 | EVALUATION_POLICIES = { | |
483 | "minimal": EvaluationPolicy( |
|
506 | "minimal": EvaluationPolicy( | |
484 | allow_builtins_access=True, |
|
507 | allow_builtins_access=True, | |
@@ -494,15 +517,7 b' EVALUATION_POLICIES = {' | |||||
494 | # - should reject binary and unary operations if custom methods would be dispatched |
|
517 | # - should reject binary and unary operations if custom methods would be dispatched | |
495 | allowed_getitem=BUILTIN_GETITEM, |
|
518 | allowed_getitem=BUILTIN_GETITEM, | |
496 | allowed_getitem_external=SUPPORTED_EXTERNAL_GETITEM, |
|
519 | allowed_getitem_external=SUPPORTED_EXTERNAL_GETITEM, | |
497 |
allowed_getattr= |
|
520 | allowed_getattr=BUILTIN_GETATTR, | |
498 | *BUILTIN_GETITEM, |
|
|||
499 | set, |
|
|||
500 | frozenset, |
|
|||
501 | object, |
|
|||
502 | type, # `type` handles a lot of generic cases, e.g. numbers as in `int.real`. |
|
|||
503 | dict_keys, |
|
|||
504 | method_descriptor, |
|
|||
505 | }, |
|
|||
506 | allowed_getattr_external={ |
|
521 | allowed_getattr_external={ | |
507 | # pandas Series/Frame implements custom `__getattr__` |
|
522 | # pandas Series/Frame implements custom `__getattr__` | |
508 | ("pandas", "DataFrame"), |
|
523 | ("pandas", "DataFrame"), |
@@ -114,7 +114,7 b' def greedy_completion():' | |||||
114 |
|
114 | |||
115 |
|
115 | |||
116 | @contextmanager |
|
116 | @contextmanager | |
117 |
def evaluation_ |
|
117 | def evaluation_policy(evaluation: str): | |
118 | ip = get_ipython() |
|
118 | ip = get_ipython() | |
119 | evaluation_original = ip.Completer.evaluation |
|
119 | evaluation_original = ip.Completer.evaluation | |
120 | try: |
|
120 | try: | |
@@ -1253,7 +1253,7 b' class TestCompleter(unittest.TestCase):' | |||||
1253 | # nested dict completion |
|
1253 | # nested dict completion | |
1254 | assert_completion(line_buffer="nested['x'][") |
|
1254 | assert_completion(line_buffer="nested['x'][") | |
1255 |
|
1255 | |||
1256 |
with evaluation_ |
|
1256 | with evaluation_policy("minimal"): | |
1257 | with pytest.raises(AssertionError): |
|
1257 | with pytest.raises(AssertionError): | |
1258 | assert_completion(line_buffer="nested['x'][") |
|
1258 | assert_completion(line_buffer="nested['x'][") | |
1259 |
|
1259 | |||
@@ -1354,10 +1354,10 b' class TestCompleter(unittest.TestCase):' | |||||
1354 | with greedy_completion(): |
|
1354 | with greedy_completion(): | |
1355 | completes_on_nested() |
|
1355 | completes_on_nested() | |
1356 |
|
1356 | |||
1357 |
with evaluation_ |
|
1357 | with evaluation_policy("limited"): | |
1358 | completes_on_nested() |
|
1358 | completes_on_nested() | |
1359 |
|
1359 | |||
1360 |
with evaluation_ |
|
1360 | with evaluation_policy("minimal"): | |
1361 | with pytest.raises(AssertionError): |
|
1361 | with pytest.raises(AssertionError): | |
1362 | completes_on_nested() |
|
1362 | completes_on_nested() | |
1363 |
|
1363 |
@@ -199,6 +199,11 b' def test_literals(code, expected):' | |||||
199 | assert guarded_eval(code, context) == expected |
|
199 | assert guarded_eval(code, context) == expected | |
200 |
|
200 | |||
201 |
|
201 | |||
|
202 | def test_access_builtins(): | |||
|
203 | context = limited() | |||
|
204 | assert guarded_eval("round", context) == round | |||
|
205 | ||||
|
206 | ||||
202 | def test_subscript(): |
|
207 | def test_subscript(): | |
203 | context = EvaluationContext( |
|
208 | context = EvaluationContext( | |
204 | locals_={}, globals_={}, evaluation="limited", in_subscript=True |
|
209 | locals_={}, globals_={}, evaluation="limited", in_subscript=True |
General Comments 0
You need to be logged in to leave comments.
Login now