##// END OF EJS Templates
Check types with mypy
krassowski -
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[HasGetItem] = field(default_factory=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 in __builtins__:
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_level(evaluation: str):
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_level("minimal"):
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_level("limited"):
1357 with evaluation_policy("limited"):
1358 completes_on_nested()
1358 completes_on_nested()
1359
1359
1360 with evaluation_level("minimal"):
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