RestrictedPython 8.3a1.dev0__py3-none-any.whl → 8.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- RestrictedPython/Eval.py +31 -17
- RestrictedPython/Guards.py +12 -1
- RestrictedPython/Limits.py +23 -4
- RestrictedPython/PrintCollector.py +4 -4
- RestrictedPython/Utilities.py +21 -6
- RestrictedPython/_types.py +25 -0
- RestrictedPython/compile.py +104 -61
- RestrictedPython/py.typed +0 -0
- RestrictedPython/transformer.py +178 -127
- {restrictedpython-8.3a1.dev0.dist-info → restrictedpython-8.4.dist-info}/METADATA +28 -1
- restrictedpython-8.4.dist-info/RECORD +16 -0
- restrictedpython-8.3a1.dev0.dist-info/RECORD +0 -14
- {restrictedpython-8.3a1.dev0.dist-info → restrictedpython-8.4.dist-info}/WHEEL +0 -0
- {restrictedpython-8.3a1.dev0.dist-info → restrictedpython-8.4.dist-info}/licenses/LICENSE.txt +0 -0
- {restrictedpython-8.3a1.dev0.dist-info → restrictedpython-8.4.dist-info}/top_level.txt +0 -0
RestrictedPython/transformer.py
CHANGED
|
@@ -19,8 +19,12 @@ the parsed python code to create a modified AST for a byte code generation.
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
import ast
|
|
22
|
+
import collections
|
|
22
23
|
import contextlib
|
|
23
24
|
import textwrap
|
|
25
|
+
import typing
|
|
26
|
+
|
|
27
|
+
from RestrictedPython._types import T_pos_ast
|
|
24
28
|
|
|
25
29
|
|
|
26
30
|
# For AugAssign the operator must be converted to a string.
|
|
@@ -111,11 +115,15 @@ INSPECT_ATTRIBUTES = frozenset([
|
|
|
111
115
|
"cr_origin",
|
|
112
116
|
])
|
|
113
117
|
|
|
118
|
+
_T_visit_return: typing.TypeAlias = ast.AST | typing.Iterable[ast.AST] | None
|
|
119
|
+
_T = typing.TypeVar('_T', bound=ast.AST)
|
|
114
120
|
|
|
115
121
|
# When new ast nodes are generated they have no 'lineno', 'end_lineno',
|
|
116
122
|
# 'col_offset' and 'end_col_offset'. This function copies these fields from the
|
|
117
123
|
# incoming node:
|
|
118
|
-
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def copy_locations(new_node: T_pos_ast, old_node: T_pos_ast) -> None:
|
|
119
127
|
assert 'lineno' in new_node._attributes
|
|
120
128
|
new_node.lineno = old_node.lineno
|
|
121
129
|
|
|
@@ -132,12 +140,12 @@ def copy_locations(new_node, old_node):
|
|
|
132
140
|
|
|
133
141
|
|
|
134
142
|
class PrintInfo:
|
|
135
|
-
def __init__(self):
|
|
143
|
+
def __init__(self) -> None:
|
|
136
144
|
self.print_used = False
|
|
137
145
|
self.printed_used = False
|
|
138
146
|
|
|
139
147
|
@contextlib.contextmanager
|
|
140
|
-
def new_print_scope(self):
|
|
148
|
+
def new_print_scope(self) -> collections.abc.Iterator[None]:
|
|
141
149
|
old_print_used = self.print_used
|
|
142
150
|
old_printed_used = self.printed_used
|
|
143
151
|
|
|
@@ -152,8 +160,14 @@ class PrintInfo:
|
|
|
152
160
|
|
|
153
161
|
|
|
154
162
|
class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
155
|
-
|
|
156
|
-
|
|
163
|
+
errors: list[str]
|
|
164
|
+
warnings: list[str]
|
|
165
|
+
used_names: dict[str, bool]
|
|
166
|
+
|
|
167
|
+
def __init__(self,
|
|
168
|
+
errors: list[str] | None = None,
|
|
169
|
+
warnings: list[str] | None = None,
|
|
170
|
+
used_names: dict[str, bool] | None = None):
|
|
157
171
|
super().__init__()
|
|
158
172
|
self.errors = [] if errors is None else errors
|
|
159
173
|
self.warnings = [] if warnings is None else warnings
|
|
@@ -170,26 +184,26 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
170
184
|
|
|
171
185
|
self.print_info = PrintInfo()
|
|
172
186
|
|
|
173
|
-
def gen_tmp_name(self):
|
|
187
|
+
def gen_tmp_name(self) -> str:
|
|
174
188
|
# 'check_name' ensures that no variable is prefixed with '_'.
|
|
175
189
|
# => Its safe to use '_tmp..' as a temporary variable.
|
|
176
190
|
name = '_tmp%i' % self._tmp_idx
|
|
177
191
|
self._tmp_idx += 1
|
|
178
192
|
return name
|
|
179
193
|
|
|
180
|
-
def error(self, node, info):
|
|
194
|
+
def error(self, node: ast.AST, info: str) -> None:
|
|
181
195
|
"""Record a security error discovered during transformation."""
|
|
182
196
|
lineno = getattr(node, 'lineno', None)
|
|
183
197
|
self.errors.append(
|
|
184
198
|
f'Line {lineno}: {info}')
|
|
185
199
|
|
|
186
|
-
def warn(self, node, info):
|
|
187
|
-
"""Record a security
|
|
200
|
+
def warn(self, node: ast.AST, info: str) -> None:
|
|
201
|
+
"""Record a security warning discovered during transformation."""
|
|
188
202
|
lineno = getattr(node, 'lineno', None)
|
|
189
203
|
self.warnings.append(
|
|
190
204
|
f'Line {lineno}: {info}')
|
|
191
205
|
|
|
192
|
-
def guard_iter(self, node):
|
|
206
|
+
def guard_iter(self, node: ast.For | ast.comprehension) -> _T_visit_return:
|
|
193
207
|
"""
|
|
194
208
|
Converts:
|
|
195
209
|
for x in expr
|
|
@@ -220,10 +234,12 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
220
234
|
node.iter = new_iter
|
|
221
235
|
return node
|
|
222
236
|
|
|
223
|
-
def is_starred(self, ob):
|
|
237
|
+
def is_starred(self, ob: ast.AST) -> typing.TypeGuard[ast.Starred]:
|
|
238
|
+
# TODO: Change Type Annotation to typing.TypeIs[ast.Starred] when
|
|
239
|
+
# Support for Python 3.12 is dropped.
|
|
224
240
|
return isinstance(ob, ast.Starred)
|
|
225
241
|
|
|
226
|
-
def gen_unpack_spec(self, tpl):
|
|
242
|
+
def gen_unpack_spec(self, tpl: ast.Tuple) -> ast.Dict:
|
|
227
243
|
"""Generate a specification for 'guarded_unpack_sequence'.
|
|
228
244
|
|
|
229
245
|
This spec is used to protect sequence unpacking.
|
|
@@ -271,7 +287,8 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
271
287
|
spec = ast.Dict(keys=[], values=[])
|
|
272
288
|
|
|
273
289
|
spec.keys.append(ast.Constant('childs'))
|
|
274
|
-
|
|
290
|
+
val0 = ast.Tuple([], ast.Load())
|
|
291
|
+
spec.values.append(val0)
|
|
275
292
|
|
|
276
293
|
# starred elements in a sequence do not contribute into the min_len.
|
|
277
294
|
# For example a, b, *c = g
|
|
@@ -292,21 +309,26 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
292
309
|
el = ast.Tuple([], ast.Load())
|
|
293
310
|
el.elts.append(ast.Constant(idx - offset))
|
|
294
311
|
el.elts.append(self.gen_unpack_spec(val))
|
|
295
|
-
|
|
312
|
+
val0.elts.append(el)
|
|
296
313
|
|
|
297
314
|
spec.keys.append(ast.Constant('min_len'))
|
|
298
315
|
spec.values.append(ast.Constant(min_len))
|
|
299
316
|
|
|
300
317
|
return spec
|
|
301
318
|
|
|
302
|
-
def protect_unpack_sequence(
|
|
319
|
+
def protect_unpack_sequence(
|
|
320
|
+
self,
|
|
321
|
+
target: ast.Tuple,
|
|
322
|
+
value: ast.expr) -> ast.Call:
|
|
303
323
|
spec = self.gen_unpack_spec(target)
|
|
304
324
|
return ast.Call(
|
|
305
325
|
func=ast.Name('_unpack_sequence_', ast.Load()),
|
|
306
326
|
args=[value, spec, ast.Name('_getiter_', ast.Load())],
|
|
307
327
|
keywords=[])
|
|
308
328
|
|
|
309
|
-
def gen_unpack_wrapper(self,
|
|
329
|
+
def gen_unpack_wrapper(self,
|
|
330
|
+
node: ast.stmt,
|
|
331
|
+
target: ast.Tuple) -> tuple[ast.Name, ast.Try]:
|
|
310
332
|
"""Helper function to protect tuple unpacks.
|
|
311
333
|
|
|
312
334
|
node: used to copy the locations for the new nodes.
|
|
@@ -342,8 +364,9 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
342
364
|
# arg = converter
|
|
343
365
|
# finally:
|
|
344
366
|
# del tmp_arg
|
|
345
|
-
try_body = [ast.Assign(
|
|
346
|
-
|
|
367
|
+
try_body: list[ast.stmt] = [ast.Assign(
|
|
368
|
+
targets=[target], value=converter)]
|
|
369
|
+
finalbody: list[ast.stmt] = [self.gen_del_stmt(tmp_name)]
|
|
347
370
|
cleanup = ast.Try(
|
|
348
371
|
body=try_body, finalbody=finalbody, handlers=[], orelse=[])
|
|
349
372
|
|
|
@@ -355,13 +378,17 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
355
378
|
|
|
356
379
|
return (tmp_target, cleanup)
|
|
357
380
|
|
|
358
|
-
def gen_none_node(self):
|
|
381
|
+
def gen_none_node(self) -> ast.Constant:
|
|
359
382
|
return ast.Constant(None)
|
|
360
383
|
|
|
361
|
-
def gen_del_stmt(self, name_to_del):
|
|
384
|
+
def gen_del_stmt(self, name_to_del: str) -> ast.Delete:
|
|
362
385
|
return ast.Delete(targets=[ast.Name(name_to_del, ast.Del())])
|
|
363
386
|
|
|
364
|
-
def check_name(
|
|
387
|
+
def check_name(
|
|
388
|
+
self,
|
|
389
|
+
node: T_pos_ast,
|
|
390
|
+
name: str | None,
|
|
391
|
+
allow_magic_methods: bool = False) -> None:
|
|
365
392
|
"""Check names if they are allowed.
|
|
366
393
|
|
|
367
394
|
If ``allow_magic_methods is True`` names in `ALLOWED_FUNC_NAMES`
|
|
@@ -386,7 +413,12 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
386
413
|
elif name in FORBIDDEN_FUNC_NAMES:
|
|
387
414
|
self.error(node, f'"{name}" is a reserved name.')
|
|
388
415
|
|
|
389
|
-
def check_function_argument_names(
|
|
416
|
+
def check_function_argument_names(
|
|
417
|
+
self,
|
|
418
|
+
node: ast.FunctionDef | ast.AsyncFunctionDef | ast.Lambda) -> None:
|
|
419
|
+
for arg in node.args.posonlyargs:
|
|
420
|
+
self.check_name(node, arg.arg)
|
|
421
|
+
|
|
390
422
|
for arg in node.args.args:
|
|
391
423
|
self.check_name(node, arg.arg)
|
|
392
424
|
|
|
@@ -399,7 +431,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
399
431
|
for arg in node.args.kwonlyargs:
|
|
400
432
|
self.check_name(node, arg.arg)
|
|
401
433
|
|
|
402
|
-
def check_import_names(self, node):
|
|
434
|
+
def check_import_names(self, node: ast.ImportFrom | ast.Import) -> ast.AST:
|
|
403
435
|
"""Check the names being imported.
|
|
404
436
|
|
|
405
437
|
This is a protection against rebinding dunder names like
|
|
@@ -416,7 +448,10 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
416
448
|
|
|
417
449
|
return self.node_contents_visit(node)
|
|
418
450
|
|
|
419
|
-
def inject_print_collector(
|
|
451
|
+
def inject_print_collector(
|
|
452
|
+
self,
|
|
453
|
+
node: ast.Module | ast.FunctionDef,
|
|
454
|
+
position: int = 0) -> None:
|
|
420
455
|
print_used = self.print_info.print_used
|
|
421
456
|
printed_used = self.print_info.printed_used
|
|
422
457
|
|
|
@@ -449,7 +484,8 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
449
484
|
|
|
450
485
|
# Special Functions for an ast.NodeTransformer
|
|
451
486
|
|
|
452
|
-
def generic_visit(self,
|
|
487
|
+
def generic_visit(self, # type: ignore[override]
|
|
488
|
+
node: ast.AST) -> _T_visit_return:
|
|
453
489
|
"""Reject ast nodes which do not have a corresponding `visit_` method.
|
|
454
490
|
|
|
455
491
|
This is needed to prevent new ast nodes from new Python versions to be
|
|
@@ -464,18 +500,18 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
464
500
|
)
|
|
465
501
|
self.not_allowed(node)
|
|
466
502
|
|
|
467
|
-
def not_allowed(self, node):
|
|
503
|
+
def not_allowed(self, node: ast.AST) -> None:
|
|
468
504
|
self.error(
|
|
469
505
|
node,
|
|
470
506
|
f'{node.__class__.__name__} statements are not allowed.')
|
|
471
507
|
|
|
472
|
-
def node_contents_visit(self, node):
|
|
508
|
+
def node_contents_visit(self, node: _T) -> _T:
|
|
473
509
|
"""Visit the contents of a node."""
|
|
474
|
-
return super().generic_visit(node)
|
|
510
|
+
return super().generic_visit(node) # type: ignore[return-value]
|
|
475
511
|
|
|
476
512
|
# ast for Literals
|
|
477
513
|
|
|
478
|
-
def visit_Constant(self, node):
|
|
514
|
+
def visit_Constant(self, node: ast.Constant) -> _T_visit_return:
|
|
479
515
|
"""Allow constant literals.
|
|
480
516
|
|
|
481
517
|
Constant replaces Num, Str, Bytes, NameConstant and Ellipsis in
|
|
@@ -484,41 +520,46 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
484
520
|
"""
|
|
485
521
|
return self.node_contents_visit(node)
|
|
486
522
|
|
|
487
|
-
def visit_Interactive(self, node):
|
|
523
|
+
def visit_Interactive(self, node: ast.Interactive) -> _T_visit_return:
|
|
488
524
|
"""Allow single mode without restrictions."""
|
|
489
525
|
return self.node_contents_visit(node)
|
|
490
526
|
|
|
491
|
-
def visit_List(self, node):
|
|
527
|
+
def visit_List(self, node: ast.List) -> _T_visit_return:
|
|
492
528
|
"""Allow list literals without restrictions."""
|
|
493
529
|
return self.node_contents_visit(node)
|
|
494
530
|
|
|
495
|
-
def visit_Tuple(self, node):
|
|
531
|
+
def visit_Tuple(self, node: ast.Tuple) -> _T_visit_return:
|
|
496
532
|
"""Allow tuple literals without restrictions."""
|
|
497
533
|
return self.node_contents_visit(node)
|
|
498
534
|
|
|
499
|
-
def visit_Set(self, node):
|
|
535
|
+
def visit_Set(self, node: ast.Set) -> _T_visit_return:
|
|
500
536
|
"""Allow set literals without restrictions."""
|
|
501
537
|
return self.node_contents_visit(node)
|
|
502
538
|
|
|
503
|
-
def visit_Dict(self, node):
|
|
539
|
+
def visit_Dict(self, node: ast.Dict) -> _T_visit_return:
|
|
504
540
|
"""Allow dict literals without restrictions."""
|
|
505
541
|
return self.node_contents_visit(node)
|
|
506
542
|
|
|
507
|
-
def visit_FormattedValue(
|
|
543
|
+
def visit_FormattedValue(
|
|
544
|
+
self,
|
|
545
|
+
node: ast.FormattedValue) -> _T_visit_return:
|
|
508
546
|
"""Allow f-strings without restrictions."""
|
|
509
547
|
return self.node_contents_visit(node)
|
|
510
548
|
|
|
511
|
-
def visit_TemplateStr(self, node):
|
|
549
|
+
def visit_TemplateStr(self, node: ast.AST) -> _T_visit_return:
|
|
512
550
|
"""Template strings are allowed by default.
|
|
513
551
|
|
|
514
552
|
As Template strings are a very basic template mechanism, that needs
|
|
515
553
|
additional rendering logic to be useful, they are not blocked by
|
|
516
554
|
default.
|
|
517
555
|
Those rendering logic would be affected by RestrictedPython as well.
|
|
556
|
+
|
|
557
|
+
TODO: Change Type Annotation to ast.TemplateStr when
|
|
558
|
+
Support for Python 3.13 is dropped.
|
|
518
559
|
"""
|
|
519
560
|
return self.node_contents_visit(node)
|
|
520
561
|
|
|
521
|
-
def visit_Interpolation(self, node):
|
|
562
|
+
def visit_Interpolation(self, node: ast.AST) -> _T_visit_return:
|
|
522
563
|
"""Interpolations are allowed by default.
|
|
523
564
|
|
|
524
565
|
As Interpolations are part of Template Strings, they are needed
|
|
@@ -526,16 +567,19 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
526
567
|
are allowed. As a user has to provide additional rendering logic
|
|
527
568
|
to make use of Template Strings, the security implications of
|
|
528
569
|
Interpolations are limited in the context of RestrictedPython.
|
|
570
|
+
|
|
571
|
+
TODO: Change Type Annotation to ast.Interpolation when
|
|
572
|
+
Support for Python 3.13 is dropped.
|
|
529
573
|
"""
|
|
530
574
|
return self.node_contents_visit(node)
|
|
531
575
|
|
|
532
|
-
def visit_JoinedStr(self, node):
|
|
576
|
+
def visit_JoinedStr(self, node: ast.JoinedStr) -> _T_visit_return:
|
|
533
577
|
"""Allow joined string without restrictions."""
|
|
534
578
|
return self.node_contents_visit(node)
|
|
535
579
|
|
|
536
580
|
# ast for Variables
|
|
537
581
|
|
|
538
|
-
def visit_Name(self, node):
|
|
582
|
+
def visit_Name(self, node: ast.Name) -> _T_visit_return:
|
|
539
583
|
"""Prevents access to protected names.
|
|
540
584
|
|
|
541
585
|
Converts use of the name 'printed' to this expression: '_print()'
|
|
@@ -544,6 +588,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
544
588
|
node = self.node_contents_visit(node)
|
|
545
589
|
|
|
546
590
|
if isinstance(node.ctx, ast.Load):
|
|
591
|
+
new_node: T_pos_ast
|
|
547
592
|
if node.id == 'printed':
|
|
548
593
|
self.print_info.printed_used = True
|
|
549
594
|
new_node = ast.Call(
|
|
@@ -569,25 +614,25 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
569
614
|
self.check_name(node, node.id)
|
|
570
615
|
return node
|
|
571
616
|
|
|
572
|
-
def visit_Load(self, node):
|
|
617
|
+
def visit_Load(self, node: ast.Load) -> _T_visit_return:
|
|
573
618
|
"""
|
|
574
619
|
|
|
575
620
|
"""
|
|
576
621
|
return self.node_contents_visit(node)
|
|
577
622
|
|
|
578
|
-
def visit_Store(self, node):
|
|
623
|
+
def visit_Store(self, node: ast.Store) -> _T_visit_return:
|
|
579
624
|
"""
|
|
580
625
|
|
|
581
626
|
"""
|
|
582
627
|
return self.node_contents_visit(node)
|
|
583
628
|
|
|
584
|
-
def visit_Del(self, node):
|
|
629
|
+
def visit_Del(self, node: ast.Del) -> _T_visit_return:
|
|
585
630
|
"""
|
|
586
631
|
|
|
587
632
|
"""
|
|
588
633
|
return self.node_contents_visit(node)
|
|
589
634
|
|
|
590
|
-
def visit_Starred(self, node):
|
|
635
|
+
def visit_Starred(self, node: ast.Starred) -> _T_visit_return:
|
|
591
636
|
"""
|
|
592
637
|
|
|
593
638
|
"""
|
|
@@ -595,18 +640,18 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
595
640
|
|
|
596
641
|
# Expressions
|
|
597
642
|
|
|
598
|
-
def visit_Expression(self, node):
|
|
643
|
+
def visit_Expression(self, node: ast.Expression) -> _T_visit_return:
|
|
599
644
|
"""Allow Expression statements without restrictions.
|
|
600
645
|
|
|
601
646
|
They are in the AST when using the `eval` compile mode.
|
|
602
647
|
"""
|
|
603
648
|
return self.node_contents_visit(node)
|
|
604
649
|
|
|
605
|
-
def visit_Expr(self, node):
|
|
650
|
+
def visit_Expr(self, node: ast.Expr) -> _T_visit_return:
|
|
606
651
|
"""Allow Expr statements (any expression) without restrictions."""
|
|
607
652
|
return self.node_contents_visit(node)
|
|
608
653
|
|
|
609
|
-
def visit_UnaryOp(self, node):
|
|
654
|
+
def visit_UnaryOp(self, node: ast.UnaryOp) -> _T_visit_return:
|
|
610
655
|
"""
|
|
611
656
|
UnaryOp (Unary Operations) is the overall element for:
|
|
612
657
|
* Not --> which should be allowed
|
|
@@ -615,135 +660,135 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
615
660
|
"""
|
|
616
661
|
return self.node_contents_visit(node)
|
|
617
662
|
|
|
618
|
-
def visit_UAdd(self, node):
|
|
663
|
+
def visit_UAdd(self, node: ast.UAdd) -> _T_visit_return:
|
|
619
664
|
"""Allow positive notation of variables. (e.g. +var)"""
|
|
620
665
|
return self.node_contents_visit(node)
|
|
621
666
|
|
|
622
|
-
def visit_USub(self, node):
|
|
667
|
+
def visit_USub(self, node: ast.USub) -> _T_visit_return:
|
|
623
668
|
"""Allow negative notation of variables. (e.g. -var)"""
|
|
624
669
|
return self.node_contents_visit(node)
|
|
625
670
|
|
|
626
|
-
def visit_Not(self, node):
|
|
671
|
+
def visit_Not(self, node: ast.Not) -> _T_visit_return:
|
|
627
672
|
"""Allow the `not` operator."""
|
|
628
673
|
return self.node_contents_visit(node)
|
|
629
674
|
|
|
630
|
-
def visit_Invert(self, node):
|
|
675
|
+
def visit_Invert(self, node: ast.Invert) -> _T_visit_return:
|
|
631
676
|
"""Allow `~` expressions."""
|
|
632
677
|
return self.node_contents_visit(node)
|
|
633
678
|
|
|
634
|
-
def visit_BinOp(self, node):
|
|
679
|
+
def visit_BinOp(self, node: ast.BinOp) -> _T_visit_return:
|
|
635
680
|
"""Allow binary operations."""
|
|
636
681
|
return self.node_contents_visit(node)
|
|
637
682
|
|
|
638
|
-
def visit_Add(self, node):
|
|
683
|
+
def visit_Add(self, node: ast.Add) -> _T_visit_return:
|
|
639
684
|
"""Allow `+` expressions."""
|
|
640
685
|
return self.node_contents_visit(node)
|
|
641
686
|
|
|
642
|
-
def visit_Sub(self, node):
|
|
687
|
+
def visit_Sub(self, node: ast.Sub) -> _T_visit_return:
|
|
643
688
|
"""Allow `-` expressions."""
|
|
644
689
|
return self.node_contents_visit(node)
|
|
645
690
|
|
|
646
|
-
def visit_Mult(self, node):
|
|
691
|
+
def visit_Mult(self, node: ast.Mult) -> _T_visit_return:
|
|
647
692
|
"""Allow `*` expressions."""
|
|
648
693
|
return self.node_contents_visit(node)
|
|
649
694
|
|
|
650
|
-
def visit_Div(self, node):
|
|
695
|
+
def visit_Div(self, node: ast.Div) -> _T_visit_return:
|
|
651
696
|
"""Allow `/` expressions."""
|
|
652
697
|
return self.node_contents_visit(node)
|
|
653
698
|
|
|
654
|
-
def visit_FloorDiv(self, node):
|
|
699
|
+
def visit_FloorDiv(self, node: ast.FloorDiv) -> _T_visit_return:
|
|
655
700
|
"""Allow `//` expressions."""
|
|
656
701
|
return self.node_contents_visit(node)
|
|
657
702
|
|
|
658
|
-
def visit_Mod(self, node):
|
|
703
|
+
def visit_Mod(self, node: ast.Mod) -> _T_visit_return:
|
|
659
704
|
"""Allow `%` expressions."""
|
|
660
705
|
return self.node_contents_visit(node)
|
|
661
706
|
|
|
662
|
-
def visit_Pow(self, node):
|
|
707
|
+
def visit_Pow(self, node: ast.Pow) -> _T_visit_return:
|
|
663
708
|
"""Allow `**` expressions."""
|
|
664
709
|
return self.node_contents_visit(node)
|
|
665
710
|
|
|
666
|
-
def visit_LShift(self, node):
|
|
711
|
+
def visit_LShift(self, node: ast.LShift) -> _T_visit_return:
|
|
667
712
|
"""Allow `<<` expressions."""
|
|
668
713
|
return self.node_contents_visit(node)
|
|
669
714
|
|
|
670
|
-
def visit_RShift(self, node):
|
|
715
|
+
def visit_RShift(self, node: ast.RShift) -> _T_visit_return:
|
|
671
716
|
"""Allow `>>` expressions."""
|
|
672
717
|
return self.node_contents_visit(node)
|
|
673
718
|
|
|
674
|
-
def visit_BitOr(self, node):
|
|
719
|
+
def visit_BitOr(self, node: ast.BitOr) -> _T_visit_return:
|
|
675
720
|
"""Allow `|` expressions."""
|
|
676
721
|
return self.node_contents_visit(node)
|
|
677
722
|
|
|
678
|
-
def visit_BitXor(self, node):
|
|
723
|
+
def visit_BitXor(self, node: ast.BitXor) -> _T_visit_return:
|
|
679
724
|
"""Allow `^` expressions."""
|
|
680
725
|
return self.node_contents_visit(node)
|
|
681
726
|
|
|
682
|
-
def visit_BitAnd(self, node):
|
|
727
|
+
def visit_BitAnd(self, node: ast.BitAnd) -> _T_visit_return:
|
|
683
728
|
"""Allow `&` expressions."""
|
|
684
729
|
return self.node_contents_visit(node)
|
|
685
730
|
|
|
686
|
-
def visit_MatMult(self, node):
|
|
731
|
+
def visit_MatMult(self, node: ast.MatMult) -> _T_visit_return:
|
|
687
732
|
"""Allow multiplication (`@`)."""
|
|
688
733
|
return self.node_contents_visit(node)
|
|
689
734
|
|
|
690
|
-
def visit_BoolOp(self, node):
|
|
735
|
+
def visit_BoolOp(self, node: ast.BoolOp) -> _T_visit_return:
|
|
691
736
|
"""Allow bool operator without restrictions."""
|
|
692
737
|
return self.node_contents_visit(node)
|
|
693
738
|
|
|
694
|
-
def visit_And(self, node):
|
|
739
|
+
def visit_And(self, node: ast.And) -> _T_visit_return:
|
|
695
740
|
"""Allow bool operator `and` without restrictions."""
|
|
696
741
|
return self.node_contents_visit(node)
|
|
697
742
|
|
|
698
|
-
def visit_Or(self, node):
|
|
743
|
+
def visit_Or(self, node: ast.Or) -> _T_visit_return:
|
|
699
744
|
"""Allow bool operator `or` without restrictions."""
|
|
700
745
|
return self.node_contents_visit(node)
|
|
701
746
|
|
|
702
|
-
def visit_Compare(self, node):
|
|
747
|
+
def visit_Compare(self, node: ast.Compare) -> _T_visit_return:
|
|
703
748
|
"""Allow comparison expressions without restrictions."""
|
|
704
749
|
return self.node_contents_visit(node)
|
|
705
750
|
|
|
706
|
-
def visit_Eq(self, node):
|
|
751
|
+
def visit_Eq(self, node: ast.Eq) -> _T_visit_return:
|
|
707
752
|
"""Allow == expressions."""
|
|
708
753
|
return self.node_contents_visit(node)
|
|
709
754
|
|
|
710
|
-
def visit_NotEq(self, node):
|
|
755
|
+
def visit_NotEq(self, node: ast.NotEq) -> _T_visit_return:
|
|
711
756
|
"""Allow != expressions."""
|
|
712
757
|
return self.node_contents_visit(node)
|
|
713
758
|
|
|
714
|
-
def visit_Lt(self, node):
|
|
759
|
+
def visit_Lt(self, node: ast.Lt) -> _T_visit_return:
|
|
715
760
|
"""Allow < expressions."""
|
|
716
761
|
return self.node_contents_visit(node)
|
|
717
762
|
|
|
718
|
-
def visit_LtE(self, node):
|
|
763
|
+
def visit_LtE(self, node: ast.LtE) -> _T_visit_return:
|
|
719
764
|
"""Allow <= expressions."""
|
|
720
765
|
return self.node_contents_visit(node)
|
|
721
766
|
|
|
722
|
-
def visit_Gt(self, node):
|
|
767
|
+
def visit_Gt(self, node: ast.Gt) -> _T_visit_return:
|
|
723
768
|
"""Allow > expressions."""
|
|
724
769
|
return self.node_contents_visit(node)
|
|
725
770
|
|
|
726
|
-
def visit_GtE(self, node):
|
|
771
|
+
def visit_GtE(self, node: ast.GtE) -> _T_visit_return:
|
|
727
772
|
"""Allow >= expressions."""
|
|
728
773
|
return self.node_contents_visit(node)
|
|
729
774
|
|
|
730
|
-
def visit_Is(self, node):
|
|
775
|
+
def visit_Is(self, node: ast.Is) -> _T_visit_return:
|
|
731
776
|
"""Allow `is` expressions."""
|
|
732
777
|
return self.node_contents_visit(node)
|
|
733
778
|
|
|
734
|
-
def visit_IsNot(self, node):
|
|
779
|
+
def visit_IsNot(self, node: ast.IsNot) -> _T_visit_return:
|
|
735
780
|
"""Allow `is not` expressions."""
|
|
736
781
|
return self.node_contents_visit(node)
|
|
737
782
|
|
|
738
|
-
def visit_In(self, node):
|
|
783
|
+
def visit_In(self, node: ast.In) -> _T_visit_return:
|
|
739
784
|
"""Allow `in` expressions."""
|
|
740
785
|
return self.node_contents_visit(node)
|
|
741
786
|
|
|
742
|
-
def visit_NotIn(self, node):
|
|
787
|
+
def visit_NotIn(self, node: ast.NotIn) -> _T_visit_return:
|
|
743
788
|
"""Allow `not in` expressions."""
|
|
744
789
|
return self.node_contents_visit(node)
|
|
745
790
|
|
|
746
|
-
def visit_Call(self, node):
|
|
791
|
+
def visit_Call(self, node: ast.Call) -> _T_visit_return:
|
|
747
792
|
"""Checks calls with '*args' and '**kwargs'.
|
|
748
793
|
|
|
749
794
|
Note: The following happens only if '*args' or '**kwargs' is used.
|
|
@@ -785,17 +830,17 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
785
830
|
copy_locations(node.func, node.args[0])
|
|
786
831
|
return node
|
|
787
832
|
|
|
788
|
-
def visit_keyword(self, node):
|
|
833
|
+
def visit_keyword(self, node: ast.keyword) -> _T_visit_return:
|
|
789
834
|
"""
|
|
790
835
|
|
|
791
836
|
"""
|
|
792
837
|
return self.node_contents_visit(node)
|
|
793
838
|
|
|
794
|
-
def visit_IfExp(self, node):
|
|
839
|
+
def visit_IfExp(self, node: ast.IfExp) -> _T_visit_return:
|
|
795
840
|
"""Allow `if` expressions without restrictions."""
|
|
796
841
|
return self.node_contents_visit(node)
|
|
797
842
|
|
|
798
|
-
def visit_Attribute(self, node):
|
|
843
|
+
def visit_Attribute(self, node: ast.Attribute) -> _T_visit_return:
|
|
799
844
|
"""Checks and mutates attribute access/assignment.
|
|
800
845
|
|
|
801
846
|
'a.b' becomes '_getattr_(a, "b")'
|
|
@@ -851,7 +896,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
851
896
|
|
|
852
897
|
# Subscripting
|
|
853
898
|
|
|
854
|
-
def visit_Subscript(self, node):
|
|
899
|
+
def visit_Subscript(self, node: ast.Subscript) -> _T_visit_return:
|
|
855
900
|
"""Transforms all kinds of subscripts.
|
|
856
901
|
|
|
857
902
|
'foo[bar]' becomes '_getitem_(foo, bar)'
|
|
@@ -896,7 +941,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
896
941
|
raise NotImplementedError(
|
|
897
942
|
f"Unknown ctx type: {type(node.ctx)}")
|
|
898
943
|
|
|
899
|
-
def visit_Slice(self, node):
|
|
944
|
+
def visit_Slice(self, node: ast.Slice) -> _T_visit_return:
|
|
900
945
|
"""
|
|
901
946
|
|
|
902
947
|
"""
|
|
@@ -904,31 +949,31 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
904
949
|
|
|
905
950
|
# Comprehensions
|
|
906
951
|
|
|
907
|
-
def visit_ListComp(self, node):
|
|
952
|
+
def visit_ListComp(self, node: ast.ListComp) -> _T_visit_return:
|
|
908
953
|
"""
|
|
909
954
|
|
|
910
955
|
"""
|
|
911
956
|
return self.node_contents_visit(node)
|
|
912
957
|
|
|
913
|
-
def visit_SetComp(self, node):
|
|
958
|
+
def visit_SetComp(self, node: ast.SetComp) -> _T_visit_return:
|
|
914
959
|
"""
|
|
915
960
|
|
|
916
961
|
"""
|
|
917
962
|
return self.node_contents_visit(node)
|
|
918
963
|
|
|
919
|
-
def visit_GeneratorExp(self, node):
|
|
964
|
+
def visit_GeneratorExp(self, node: ast.GeneratorExp) -> _T_visit_return:
|
|
920
965
|
"""
|
|
921
966
|
|
|
922
967
|
"""
|
|
923
968
|
return self.node_contents_visit(node)
|
|
924
969
|
|
|
925
|
-
def visit_DictComp(self, node):
|
|
970
|
+
def visit_DictComp(self, node: ast.DictComp) -> _T_visit_return:
|
|
926
971
|
"""
|
|
927
972
|
|
|
928
973
|
"""
|
|
929
974
|
return self.node_contents_visit(node)
|
|
930
975
|
|
|
931
|
-
def visit_comprehension(self, node):
|
|
976
|
+
def visit_comprehension(self, node: ast.comprehension) -> _T_visit_return:
|
|
932
977
|
"""
|
|
933
978
|
|
|
934
979
|
"""
|
|
@@ -936,7 +981,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
936
981
|
|
|
937
982
|
# Statements
|
|
938
983
|
|
|
939
|
-
def visit_Assign(self, node):
|
|
984
|
+
def visit_Assign(self, node: ast.Assign) -> _T_visit_return:
|
|
940
985
|
"""
|
|
941
986
|
|
|
942
987
|
"""
|
|
@@ -985,7 +1030,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
985
1030
|
|
|
986
1031
|
return new_nodes
|
|
987
1032
|
|
|
988
|
-
def visit_AugAssign(self, node):
|
|
1033
|
+
def visit_AugAssign(self, node: ast.AugAssign) -> _T_visit_return:
|
|
989
1034
|
"""Forbid certain kinds of AugAssign
|
|
990
1035
|
|
|
991
1036
|
According to the language reference (and ast.c) the following nodes
|
|
@@ -1036,75 +1081,79 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1036
1081
|
raise NotImplementedError(
|
|
1037
1082
|
f"Unknown target type: {type(node.target)}")
|
|
1038
1083
|
|
|
1039
|
-
def visit_Raise(self, node):
|
|
1084
|
+
def visit_Raise(self, node: ast.Raise) -> _T_visit_return:
|
|
1040
1085
|
"""Allow `raise` statements without restrictions."""
|
|
1041
1086
|
return self.node_contents_visit(node)
|
|
1042
1087
|
|
|
1043
|
-
def visit_Assert(self, node):
|
|
1088
|
+
def visit_Assert(self, node: ast.Assert) -> _T_visit_return:
|
|
1044
1089
|
"""Allow assert statements without restrictions."""
|
|
1045
1090
|
return self.node_contents_visit(node)
|
|
1046
1091
|
|
|
1047
|
-
def visit_Delete(self, node):
|
|
1092
|
+
def visit_Delete(self, node: ast.Delete) -> _T_visit_return:
|
|
1048
1093
|
"""Allow `del` statements without restrictions."""
|
|
1049
1094
|
return self.node_contents_visit(node)
|
|
1050
1095
|
|
|
1051
|
-
def visit_Pass(self, node):
|
|
1096
|
+
def visit_Pass(self, node: ast.Pass) -> _T_visit_return:
|
|
1052
1097
|
"""Allow `pass` statements without restrictions."""
|
|
1053
1098
|
return self.node_contents_visit(node)
|
|
1054
1099
|
|
|
1055
1100
|
# Imports
|
|
1056
1101
|
|
|
1057
|
-
def visit_Import(self, node):
|
|
1102
|
+
def visit_Import(self, node: ast.Import) -> _T_visit_return:
|
|
1058
1103
|
"""Allow `import` statements with restrictions.
|
|
1059
1104
|
See check_import_names."""
|
|
1060
1105
|
return self.check_import_names(node)
|
|
1061
1106
|
|
|
1062
|
-
def visit_ImportFrom(self, node):
|
|
1107
|
+
def visit_ImportFrom(self, node: ast.ImportFrom) -> _T_visit_return:
|
|
1063
1108
|
"""Allow `import from` statements with restrictions.
|
|
1064
1109
|
See check_import_names."""
|
|
1065
1110
|
return self.check_import_names(node)
|
|
1066
1111
|
|
|
1067
|
-
def visit_alias(self, node):
|
|
1112
|
+
def visit_alias(self, node: ast.alias) -> _T_visit_return:
|
|
1068
1113
|
"""Allow `as` statements in import and import from statements."""
|
|
1069
1114
|
return self.node_contents_visit(node)
|
|
1070
1115
|
|
|
1071
1116
|
# Control flow
|
|
1072
1117
|
|
|
1073
|
-
def visit_If(self, node):
|
|
1118
|
+
def visit_If(self, node: ast.If) -> _T_visit_return:
|
|
1074
1119
|
"""Allow `if` statements without restrictions."""
|
|
1075
1120
|
return self.node_contents_visit(node)
|
|
1076
1121
|
|
|
1077
|
-
def visit_For(self, node):
|
|
1122
|
+
def visit_For(self, node: ast.For) -> _T_visit_return:
|
|
1078
1123
|
"""Allow `for` statements with some restrictions."""
|
|
1079
1124
|
return self.guard_iter(node)
|
|
1080
1125
|
|
|
1081
|
-
def visit_While(self, node):
|
|
1126
|
+
def visit_While(self, node: ast.While) -> _T_visit_return:
|
|
1082
1127
|
"""Allow `while` statements."""
|
|
1083
1128
|
return self.node_contents_visit(node)
|
|
1084
1129
|
|
|
1085
|
-
def visit_Break(self, node):
|
|
1130
|
+
def visit_Break(self, node: ast.Break) -> _T_visit_return:
|
|
1086
1131
|
"""Allow `break` statements without restrictions."""
|
|
1087
1132
|
return self.node_contents_visit(node)
|
|
1088
1133
|
|
|
1089
|
-
def visit_Continue(self, node):
|
|
1134
|
+
def visit_Continue(self, node: ast.Continue) -> _T_visit_return:
|
|
1090
1135
|
"""Allow `continue` statements without restrictions."""
|
|
1091
1136
|
return self.node_contents_visit(node)
|
|
1092
1137
|
|
|
1093
|
-
def visit_Try(self, node):
|
|
1138
|
+
def visit_Try(self, node: ast.Try) -> _T_visit_return:
|
|
1094
1139
|
"""Allow `try` without restrictions."""
|
|
1095
1140
|
return self.node_contents_visit(node)
|
|
1096
1141
|
|
|
1097
|
-
def visit_TryStar(self, node):
|
|
1098
|
-
"""Disallow `ExceptionGroup` due to a potential sandbox escape.
|
|
1142
|
+
def visit_TryStar(self, node: ast.AST) -> _T_visit_return:
|
|
1143
|
+
"""Disallow `ExceptionGroup` due to a potential sandbox escape.
|
|
1144
|
+
|
|
1145
|
+
TODO: Change Type Annotation to ast.TryStar when
|
|
1146
|
+
Support for Python 3.10 is dropped.
|
|
1147
|
+
"""
|
|
1099
1148
|
self.not_allowed(node)
|
|
1100
1149
|
|
|
1101
|
-
def visit_ExceptHandler(self, node):
|
|
1150
|
+
def visit_ExceptHandler(self, node: ast.ExceptHandler) -> _T_visit_return:
|
|
1102
1151
|
"""Protect exception handlers."""
|
|
1103
1152
|
node = self.node_contents_visit(node)
|
|
1104
1153
|
self.check_name(node, node.name)
|
|
1105
1154
|
return node
|
|
1106
1155
|
|
|
1107
|
-
def visit_With(self, node):
|
|
1156
|
+
def visit_With(self, node: ast.With) -> _T_visit_return:
|
|
1108
1157
|
"""Protect tuple unpacking on with statements."""
|
|
1109
1158
|
node = self.node_contents_visit(node)
|
|
1110
1159
|
|
|
@@ -1119,13 +1168,13 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1119
1168
|
|
|
1120
1169
|
return node
|
|
1121
1170
|
|
|
1122
|
-
def visit_withitem(self, node):
|
|
1171
|
+
def visit_withitem(self, node: ast.withitem) -> _T_visit_return:
|
|
1123
1172
|
"""Allow `with` statements (context managers) without restrictions."""
|
|
1124
1173
|
return self.node_contents_visit(node)
|
|
1125
1174
|
|
|
1126
1175
|
# Function and class definitions
|
|
1127
1176
|
|
|
1128
|
-
def visit_FunctionDef(self, node):
|
|
1177
|
+
def visit_FunctionDef(self, node: ast.FunctionDef) -> _T_visit_return:
|
|
1129
1178
|
"""Allow function definitions (`def`) with some restrictions."""
|
|
1130
1179
|
self.check_name(node, node.name, allow_magic_methods=True)
|
|
1131
1180
|
self.check_function_argument_names(node)
|
|
@@ -1135,44 +1184,44 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1135
1184
|
self.inject_print_collector(node)
|
|
1136
1185
|
return node
|
|
1137
1186
|
|
|
1138
|
-
def visit_Lambda(self, node):
|
|
1187
|
+
def visit_Lambda(self, node: ast.Lambda) -> _T_visit_return:
|
|
1139
1188
|
"""Allow lambda with some restrictions."""
|
|
1140
1189
|
self.check_function_argument_names(node)
|
|
1141
1190
|
return self.node_contents_visit(node)
|
|
1142
1191
|
|
|
1143
|
-
def visit_arguments(self, node):
|
|
1192
|
+
def visit_arguments(self, node: ast.arguments) -> _T_visit_return:
|
|
1144
1193
|
"""
|
|
1145
1194
|
|
|
1146
1195
|
"""
|
|
1147
1196
|
return self.node_contents_visit(node)
|
|
1148
1197
|
|
|
1149
|
-
def visit_arg(self, node):
|
|
1198
|
+
def visit_arg(self, node: ast.arg) -> _T_visit_return:
|
|
1150
1199
|
"""
|
|
1151
1200
|
|
|
1152
1201
|
"""
|
|
1153
1202
|
return self.node_contents_visit(node)
|
|
1154
1203
|
|
|
1155
|
-
def visit_Return(self, node):
|
|
1204
|
+
def visit_Return(self, node: ast.Return) -> _T_visit_return:
|
|
1156
1205
|
"""Allow `return` statements without restrictions."""
|
|
1157
1206
|
return self.node_contents_visit(node)
|
|
1158
1207
|
|
|
1159
|
-
def visit_Yield(self, node):
|
|
1208
|
+
def visit_Yield(self, node: ast.Yield) -> _T_visit_return:
|
|
1160
1209
|
"""Allow `yield`statements without restrictions."""
|
|
1161
1210
|
return self.node_contents_visit(node)
|
|
1162
1211
|
|
|
1163
|
-
def visit_YieldFrom(self, node):
|
|
1212
|
+
def visit_YieldFrom(self, node: ast.YieldFrom) -> _T_visit_return:
|
|
1164
1213
|
"""Allow `yield`statements without restrictions."""
|
|
1165
1214
|
return self.node_contents_visit(node)
|
|
1166
1215
|
|
|
1167
|
-
def visit_Global(self, node):
|
|
1216
|
+
def visit_Global(self, node: ast.Global) -> _T_visit_return:
|
|
1168
1217
|
"""Allow `global` statements without restrictions."""
|
|
1169
1218
|
return self.node_contents_visit(node)
|
|
1170
1219
|
|
|
1171
|
-
def visit_Nonlocal(self, node):
|
|
1220
|
+
def visit_Nonlocal(self, node: ast.Nonlocal) -> _T_visit_return:
|
|
1172
1221
|
"""Deny `nonlocal` statements."""
|
|
1173
1222
|
self.not_allowed(node)
|
|
1174
1223
|
|
|
1175
|
-
def visit_ClassDef(self, node):
|
|
1224
|
+
def visit_ClassDef(self, node: ast.ClassDef) -> _T_visit_return:
|
|
1176
1225
|
"""Check the name of a class definition."""
|
|
1177
1226
|
self.check_name(node, node.name)
|
|
1178
1227
|
node = self.node_contents_visit(node)
|
|
@@ -1183,13 +1232,14 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1183
1232
|
class {0.name}(metaclass=__metaclass__):
|
|
1184
1233
|
pass
|
|
1185
1234
|
'''.format(node))
|
|
1186
|
-
new_class_node =
|
|
1235
|
+
new_class_node = typing.cast(
|
|
1236
|
+
ast.ClassDef, ast.parse(CLASS_DEF).body[0])
|
|
1187
1237
|
new_class_node.body = node.body
|
|
1188
1238
|
new_class_node.bases = node.bases
|
|
1189
1239
|
new_class_node.decorator_list = node.decorator_list
|
|
1190
1240
|
return new_class_node
|
|
1191
1241
|
|
|
1192
|
-
def visit_Module(self, node):
|
|
1242
|
+
def visit_Module(self, node: ast.Module) -> _T_visit_return:
|
|
1193
1243
|
"""Add the print_collector (only if print is used) at the top."""
|
|
1194
1244
|
node = self.node_contents_visit(node)
|
|
1195
1245
|
|
|
@@ -1207,25 +1257,26 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1207
1257
|
|
|
1208
1258
|
# Async und await
|
|
1209
1259
|
|
|
1210
|
-
def visit_AsyncFunctionDef(
|
|
1260
|
+
def visit_AsyncFunctionDef(
|
|
1261
|
+
self, node: ast.AsyncFunctionDef) -> _T_visit_return:
|
|
1211
1262
|
"""Deny async functions."""
|
|
1212
1263
|
self.not_allowed(node)
|
|
1213
1264
|
|
|
1214
|
-
def visit_Await(self, node):
|
|
1265
|
+
def visit_Await(self, node: ast.Await) -> _T_visit_return:
|
|
1215
1266
|
"""Deny async functionality."""
|
|
1216
1267
|
self.not_allowed(node)
|
|
1217
1268
|
|
|
1218
|
-
def visit_AsyncFor(self, node):
|
|
1269
|
+
def visit_AsyncFor(self, node: ast.AsyncFor) -> _T_visit_return:
|
|
1219
1270
|
"""Deny async functionality."""
|
|
1220
1271
|
self.not_allowed(node)
|
|
1221
1272
|
|
|
1222
|
-
def visit_AsyncWith(self, node):
|
|
1273
|
+
def visit_AsyncWith(self, node: ast.AsyncWith) -> _T_visit_return:
|
|
1223
1274
|
"""Deny async functionality."""
|
|
1224
1275
|
self.not_allowed(node)
|
|
1225
1276
|
|
|
1226
1277
|
# Assignment expressions (walrus operator ``:=``)
|
|
1227
1278
|
# New in 3.8
|
|
1228
|
-
def visit_NamedExpr(self, node):
|
|
1279
|
+
def visit_NamedExpr(self, node: ast.NamedExpr) -> _T_visit_return:
|
|
1229
1280
|
"""Allow assignment expressions under some circumstances."""
|
|
1230
1281
|
# while the grammar requires ``node.target`` to be a ``Name``
|
|
1231
1282
|
# the abstract syntax is more permissive and allows an ``expr``.
|
|
@@ -1237,7 +1288,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1237
1288
|
node = self.node_contents_visit(node) # this checks ``node.target``
|
|
1238
1289
|
target = node.target
|
|
1239
1290
|
if not isinstance(target, ast.Name):
|
|
1240
|
-
self.error(
|
|
1291
|
+
self.error( # type: ignore[unreachable]
|
|
1241
1292
|
node,
|
|
1242
1293
|
"Assignment expressions are only allowed for simple targets")
|
|
1243
1294
|
return node
|