RestrictedPython 8.3__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 +175 -127
- {restrictedpython-8.3.dist-info → restrictedpython-8.4.dist-info}/METADATA +17 -1
- restrictedpython-8.4.dist-info/RECORD +16 -0
- restrictedpython-8.3.dist-info/RECORD +0 -14
- {restrictedpython-8.3.dist-info → restrictedpython-8.4.dist-info}/WHEEL +0 -0
- {restrictedpython-8.3.dist-info → restrictedpython-8.4.dist-info}/licenses/LICENSE.txt +0 -0
- {restrictedpython-8.3.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,9 @@ 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:
|
|
390
419
|
for arg in node.args.posonlyargs:
|
|
391
420
|
self.check_name(node, arg.arg)
|
|
392
421
|
|
|
@@ -402,7 +431,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
402
431
|
for arg in node.args.kwonlyargs:
|
|
403
432
|
self.check_name(node, arg.arg)
|
|
404
433
|
|
|
405
|
-
def check_import_names(self, node):
|
|
434
|
+
def check_import_names(self, node: ast.ImportFrom | ast.Import) -> ast.AST:
|
|
406
435
|
"""Check the names being imported.
|
|
407
436
|
|
|
408
437
|
This is a protection against rebinding dunder names like
|
|
@@ -419,7 +448,10 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
419
448
|
|
|
420
449
|
return self.node_contents_visit(node)
|
|
421
450
|
|
|
422
|
-
def inject_print_collector(
|
|
451
|
+
def inject_print_collector(
|
|
452
|
+
self,
|
|
453
|
+
node: ast.Module | ast.FunctionDef,
|
|
454
|
+
position: int = 0) -> None:
|
|
423
455
|
print_used = self.print_info.print_used
|
|
424
456
|
printed_used = self.print_info.printed_used
|
|
425
457
|
|
|
@@ -452,7 +484,8 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
452
484
|
|
|
453
485
|
# Special Functions for an ast.NodeTransformer
|
|
454
486
|
|
|
455
|
-
def generic_visit(self,
|
|
487
|
+
def generic_visit(self, # type: ignore[override]
|
|
488
|
+
node: ast.AST) -> _T_visit_return:
|
|
456
489
|
"""Reject ast nodes which do not have a corresponding `visit_` method.
|
|
457
490
|
|
|
458
491
|
This is needed to prevent new ast nodes from new Python versions to be
|
|
@@ -467,18 +500,18 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
467
500
|
)
|
|
468
501
|
self.not_allowed(node)
|
|
469
502
|
|
|
470
|
-
def not_allowed(self, node):
|
|
503
|
+
def not_allowed(self, node: ast.AST) -> None:
|
|
471
504
|
self.error(
|
|
472
505
|
node,
|
|
473
506
|
f'{node.__class__.__name__} statements are not allowed.')
|
|
474
507
|
|
|
475
|
-
def node_contents_visit(self, node):
|
|
508
|
+
def node_contents_visit(self, node: _T) -> _T:
|
|
476
509
|
"""Visit the contents of a node."""
|
|
477
|
-
return super().generic_visit(node)
|
|
510
|
+
return super().generic_visit(node) # type: ignore[return-value]
|
|
478
511
|
|
|
479
512
|
# ast for Literals
|
|
480
513
|
|
|
481
|
-
def visit_Constant(self, node):
|
|
514
|
+
def visit_Constant(self, node: ast.Constant) -> _T_visit_return:
|
|
482
515
|
"""Allow constant literals.
|
|
483
516
|
|
|
484
517
|
Constant replaces Num, Str, Bytes, NameConstant and Ellipsis in
|
|
@@ -487,41 +520,46 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
487
520
|
"""
|
|
488
521
|
return self.node_contents_visit(node)
|
|
489
522
|
|
|
490
|
-
def visit_Interactive(self, node):
|
|
523
|
+
def visit_Interactive(self, node: ast.Interactive) -> _T_visit_return:
|
|
491
524
|
"""Allow single mode without restrictions."""
|
|
492
525
|
return self.node_contents_visit(node)
|
|
493
526
|
|
|
494
|
-
def visit_List(self, node):
|
|
527
|
+
def visit_List(self, node: ast.List) -> _T_visit_return:
|
|
495
528
|
"""Allow list literals without restrictions."""
|
|
496
529
|
return self.node_contents_visit(node)
|
|
497
530
|
|
|
498
|
-
def visit_Tuple(self, node):
|
|
531
|
+
def visit_Tuple(self, node: ast.Tuple) -> _T_visit_return:
|
|
499
532
|
"""Allow tuple literals without restrictions."""
|
|
500
533
|
return self.node_contents_visit(node)
|
|
501
534
|
|
|
502
|
-
def visit_Set(self, node):
|
|
535
|
+
def visit_Set(self, node: ast.Set) -> _T_visit_return:
|
|
503
536
|
"""Allow set literals without restrictions."""
|
|
504
537
|
return self.node_contents_visit(node)
|
|
505
538
|
|
|
506
|
-
def visit_Dict(self, node):
|
|
539
|
+
def visit_Dict(self, node: ast.Dict) -> _T_visit_return:
|
|
507
540
|
"""Allow dict literals without restrictions."""
|
|
508
541
|
return self.node_contents_visit(node)
|
|
509
542
|
|
|
510
|
-
def visit_FormattedValue(
|
|
543
|
+
def visit_FormattedValue(
|
|
544
|
+
self,
|
|
545
|
+
node: ast.FormattedValue) -> _T_visit_return:
|
|
511
546
|
"""Allow f-strings without restrictions."""
|
|
512
547
|
return self.node_contents_visit(node)
|
|
513
548
|
|
|
514
|
-
def visit_TemplateStr(self, node):
|
|
549
|
+
def visit_TemplateStr(self, node: ast.AST) -> _T_visit_return:
|
|
515
550
|
"""Template strings are allowed by default.
|
|
516
551
|
|
|
517
552
|
As Template strings are a very basic template mechanism, that needs
|
|
518
553
|
additional rendering logic to be useful, they are not blocked by
|
|
519
554
|
default.
|
|
520
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.
|
|
521
559
|
"""
|
|
522
560
|
return self.node_contents_visit(node)
|
|
523
561
|
|
|
524
|
-
def visit_Interpolation(self, node):
|
|
562
|
+
def visit_Interpolation(self, node: ast.AST) -> _T_visit_return:
|
|
525
563
|
"""Interpolations are allowed by default.
|
|
526
564
|
|
|
527
565
|
As Interpolations are part of Template Strings, they are needed
|
|
@@ -529,16 +567,19 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
529
567
|
are allowed. As a user has to provide additional rendering logic
|
|
530
568
|
to make use of Template Strings, the security implications of
|
|
531
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.
|
|
532
573
|
"""
|
|
533
574
|
return self.node_contents_visit(node)
|
|
534
575
|
|
|
535
|
-
def visit_JoinedStr(self, node):
|
|
576
|
+
def visit_JoinedStr(self, node: ast.JoinedStr) -> _T_visit_return:
|
|
536
577
|
"""Allow joined string without restrictions."""
|
|
537
578
|
return self.node_contents_visit(node)
|
|
538
579
|
|
|
539
580
|
# ast for Variables
|
|
540
581
|
|
|
541
|
-
def visit_Name(self, node):
|
|
582
|
+
def visit_Name(self, node: ast.Name) -> _T_visit_return:
|
|
542
583
|
"""Prevents access to protected names.
|
|
543
584
|
|
|
544
585
|
Converts use of the name 'printed' to this expression: '_print()'
|
|
@@ -547,6 +588,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
547
588
|
node = self.node_contents_visit(node)
|
|
548
589
|
|
|
549
590
|
if isinstance(node.ctx, ast.Load):
|
|
591
|
+
new_node: T_pos_ast
|
|
550
592
|
if node.id == 'printed':
|
|
551
593
|
self.print_info.printed_used = True
|
|
552
594
|
new_node = ast.Call(
|
|
@@ -572,25 +614,25 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
572
614
|
self.check_name(node, node.id)
|
|
573
615
|
return node
|
|
574
616
|
|
|
575
|
-
def visit_Load(self, node):
|
|
617
|
+
def visit_Load(self, node: ast.Load) -> _T_visit_return:
|
|
576
618
|
"""
|
|
577
619
|
|
|
578
620
|
"""
|
|
579
621
|
return self.node_contents_visit(node)
|
|
580
622
|
|
|
581
|
-
def visit_Store(self, node):
|
|
623
|
+
def visit_Store(self, node: ast.Store) -> _T_visit_return:
|
|
582
624
|
"""
|
|
583
625
|
|
|
584
626
|
"""
|
|
585
627
|
return self.node_contents_visit(node)
|
|
586
628
|
|
|
587
|
-
def visit_Del(self, node):
|
|
629
|
+
def visit_Del(self, node: ast.Del) -> _T_visit_return:
|
|
588
630
|
"""
|
|
589
631
|
|
|
590
632
|
"""
|
|
591
633
|
return self.node_contents_visit(node)
|
|
592
634
|
|
|
593
|
-
def visit_Starred(self, node):
|
|
635
|
+
def visit_Starred(self, node: ast.Starred) -> _T_visit_return:
|
|
594
636
|
"""
|
|
595
637
|
|
|
596
638
|
"""
|
|
@@ -598,18 +640,18 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
598
640
|
|
|
599
641
|
# Expressions
|
|
600
642
|
|
|
601
|
-
def visit_Expression(self, node):
|
|
643
|
+
def visit_Expression(self, node: ast.Expression) -> _T_visit_return:
|
|
602
644
|
"""Allow Expression statements without restrictions.
|
|
603
645
|
|
|
604
646
|
They are in the AST when using the `eval` compile mode.
|
|
605
647
|
"""
|
|
606
648
|
return self.node_contents_visit(node)
|
|
607
649
|
|
|
608
|
-
def visit_Expr(self, node):
|
|
650
|
+
def visit_Expr(self, node: ast.Expr) -> _T_visit_return:
|
|
609
651
|
"""Allow Expr statements (any expression) without restrictions."""
|
|
610
652
|
return self.node_contents_visit(node)
|
|
611
653
|
|
|
612
|
-
def visit_UnaryOp(self, node):
|
|
654
|
+
def visit_UnaryOp(self, node: ast.UnaryOp) -> _T_visit_return:
|
|
613
655
|
"""
|
|
614
656
|
UnaryOp (Unary Operations) is the overall element for:
|
|
615
657
|
* Not --> which should be allowed
|
|
@@ -618,135 +660,135 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
618
660
|
"""
|
|
619
661
|
return self.node_contents_visit(node)
|
|
620
662
|
|
|
621
|
-
def visit_UAdd(self, node):
|
|
663
|
+
def visit_UAdd(self, node: ast.UAdd) -> _T_visit_return:
|
|
622
664
|
"""Allow positive notation of variables. (e.g. +var)"""
|
|
623
665
|
return self.node_contents_visit(node)
|
|
624
666
|
|
|
625
|
-
def visit_USub(self, node):
|
|
667
|
+
def visit_USub(self, node: ast.USub) -> _T_visit_return:
|
|
626
668
|
"""Allow negative notation of variables. (e.g. -var)"""
|
|
627
669
|
return self.node_contents_visit(node)
|
|
628
670
|
|
|
629
|
-
def visit_Not(self, node):
|
|
671
|
+
def visit_Not(self, node: ast.Not) -> _T_visit_return:
|
|
630
672
|
"""Allow the `not` operator."""
|
|
631
673
|
return self.node_contents_visit(node)
|
|
632
674
|
|
|
633
|
-
def visit_Invert(self, node):
|
|
675
|
+
def visit_Invert(self, node: ast.Invert) -> _T_visit_return:
|
|
634
676
|
"""Allow `~` expressions."""
|
|
635
677
|
return self.node_contents_visit(node)
|
|
636
678
|
|
|
637
|
-
def visit_BinOp(self, node):
|
|
679
|
+
def visit_BinOp(self, node: ast.BinOp) -> _T_visit_return:
|
|
638
680
|
"""Allow binary operations."""
|
|
639
681
|
return self.node_contents_visit(node)
|
|
640
682
|
|
|
641
|
-
def visit_Add(self, node):
|
|
683
|
+
def visit_Add(self, node: ast.Add) -> _T_visit_return:
|
|
642
684
|
"""Allow `+` expressions."""
|
|
643
685
|
return self.node_contents_visit(node)
|
|
644
686
|
|
|
645
|
-
def visit_Sub(self, node):
|
|
687
|
+
def visit_Sub(self, node: ast.Sub) -> _T_visit_return:
|
|
646
688
|
"""Allow `-` expressions."""
|
|
647
689
|
return self.node_contents_visit(node)
|
|
648
690
|
|
|
649
|
-
def visit_Mult(self, node):
|
|
691
|
+
def visit_Mult(self, node: ast.Mult) -> _T_visit_return:
|
|
650
692
|
"""Allow `*` expressions."""
|
|
651
693
|
return self.node_contents_visit(node)
|
|
652
694
|
|
|
653
|
-
def visit_Div(self, node):
|
|
695
|
+
def visit_Div(self, node: ast.Div) -> _T_visit_return:
|
|
654
696
|
"""Allow `/` expressions."""
|
|
655
697
|
return self.node_contents_visit(node)
|
|
656
698
|
|
|
657
|
-
def visit_FloorDiv(self, node):
|
|
699
|
+
def visit_FloorDiv(self, node: ast.FloorDiv) -> _T_visit_return:
|
|
658
700
|
"""Allow `//` expressions."""
|
|
659
701
|
return self.node_contents_visit(node)
|
|
660
702
|
|
|
661
|
-
def visit_Mod(self, node):
|
|
703
|
+
def visit_Mod(self, node: ast.Mod) -> _T_visit_return:
|
|
662
704
|
"""Allow `%` expressions."""
|
|
663
705
|
return self.node_contents_visit(node)
|
|
664
706
|
|
|
665
|
-
def visit_Pow(self, node):
|
|
707
|
+
def visit_Pow(self, node: ast.Pow) -> _T_visit_return:
|
|
666
708
|
"""Allow `**` expressions."""
|
|
667
709
|
return self.node_contents_visit(node)
|
|
668
710
|
|
|
669
|
-
def visit_LShift(self, node):
|
|
711
|
+
def visit_LShift(self, node: ast.LShift) -> _T_visit_return:
|
|
670
712
|
"""Allow `<<` expressions."""
|
|
671
713
|
return self.node_contents_visit(node)
|
|
672
714
|
|
|
673
|
-
def visit_RShift(self, node):
|
|
715
|
+
def visit_RShift(self, node: ast.RShift) -> _T_visit_return:
|
|
674
716
|
"""Allow `>>` expressions."""
|
|
675
717
|
return self.node_contents_visit(node)
|
|
676
718
|
|
|
677
|
-
def visit_BitOr(self, node):
|
|
719
|
+
def visit_BitOr(self, node: ast.BitOr) -> _T_visit_return:
|
|
678
720
|
"""Allow `|` expressions."""
|
|
679
721
|
return self.node_contents_visit(node)
|
|
680
722
|
|
|
681
|
-
def visit_BitXor(self, node):
|
|
723
|
+
def visit_BitXor(self, node: ast.BitXor) -> _T_visit_return:
|
|
682
724
|
"""Allow `^` expressions."""
|
|
683
725
|
return self.node_contents_visit(node)
|
|
684
726
|
|
|
685
|
-
def visit_BitAnd(self, node):
|
|
727
|
+
def visit_BitAnd(self, node: ast.BitAnd) -> _T_visit_return:
|
|
686
728
|
"""Allow `&` expressions."""
|
|
687
729
|
return self.node_contents_visit(node)
|
|
688
730
|
|
|
689
|
-
def visit_MatMult(self, node):
|
|
731
|
+
def visit_MatMult(self, node: ast.MatMult) -> _T_visit_return:
|
|
690
732
|
"""Allow multiplication (`@`)."""
|
|
691
733
|
return self.node_contents_visit(node)
|
|
692
734
|
|
|
693
|
-
def visit_BoolOp(self, node):
|
|
735
|
+
def visit_BoolOp(self, node: ast.BoolOp) -> _T_visit_return:
|
|
694
736
|
"""Allow bool operator without restrictions."""
|
|
695
737
|
return self.node_contents_visit(node)
|
|
696
738
|
|
|
697
|
-
def visit_And(self, node):
|
|
739
|
+
def visit_And(self, node: ast.And) -> _T_visit_return:
|
|
698
740
|
"""Allow bool operator `and` without restrictions."""
|
|
699
741
|
return self.node_contents_visit(node)
|
|
700
742
|
|
|
701
|
-
def visit_Or(self, node):
|
|
743
|
+
def visit_Or(self, node: ast.Or) -> _T_visit_return:
|
|
702
744
|
"""Allow bool operator `or` without restrictions."""
|
|
703
745
|
return self.node_contents_visit(node)
|
|
704
746
|
|
|
705
|
-
def visit_Compare(self, node):
|
|
747
|
+
def visit_Compare(self, node: ast.Compare) -> _T_visit_return:
|
|
706
748
|
"""Allow comparison expressions without restrictions."""
|
|
707
749
|
return self.node_contents_visit(node)
|
|
708
750
|
|
|
709
|
-
def visit_Eq(self, node):
|
|
751
|
+
def visit_Eq(self, node: ast.Eq) -> _T_visit_return:
|
|
710
752
|
"""Allow == expressions."""
|
|
711
753
|
return self.node_contents_visit(node)
|
|
712
754
|
|
|
713
|
-
def visit_NotEq(self, node):
|
|
755
|
+
def visit_NotEq(self, node: ast.NotEq) -> _T_visit_return:
|
|
714
756
|
"""Allow != expressions."""
|
|
715
757
|
return self.node_contents_visit(node)
|
|
716
758
|
|
|
717
|
-
def visit_Lt(self, node):
|
|
759
|
+
def visit_Lt(self, node: ast.Lt) -> _T_visit_return:
|
|
718
760
|
"""Allow < expressions."""
|
|
719
761
|
return self.node_contents_visit(node)
|
|
720
762
|
|
|
721
|
-
def visit_LtE(self, node):
|
|
763
|
+
def visit_LtE(self, node: ast.LtE) -> _T_visit_return:
|
|
722
764
|
"""Allow <= expressions."""
|
|
723
765
|
return self.node_contents_visit(node)
|
|
724
766
|
|
|
725
|
-
def visit_Gt(self, node):
|
|
767
|
+
def visit_Gt(self, node: ast.Gt) -> _T_visit_return:
|
|
726
768
|
"""Allow > expressions."""
|
|
727
769
|
return self.node_contents_visit(node)
|
|
728
770
|
|
|
729
|
-
def visit_GtE(self, node):
|
|
771
|
+
def visit_GtE(self, node: ast.GtE) -> _T_visit_return:
|
|
730
772
|
"""Allow >= expressions."""
|
|
731
773
|
return self.node_contents_visit(node)
|
|
732
774
|
|
|
733
|
-
def visit_Is(self, node):
|
|
775
|
+
def visit_Is(self, node: ast.Is) -> _T_visit_return:
|
|
734
776
|
"""Allow `is` expressions."""
|
|
735
777
|
return self.node_contents_visit(node)
|
|
736
778
|
|
|
737
|
-
def visit_IsNot(self, node):
|
|
779
|
+
def visit_IsNot(self, node: ast.IsNot) -> _T_visit_return:
|
|
738
780
|
"""Allow `is not` expressions."""
|
|
739
781
|
return self.node_contents_visit(node)
|
|
740
782
|
|
|
741
|
-
def visit_In(self, node):
|
|
783
|
+
def visit_In(self, node: ast.In) -> _T_visit_return:
|
|
742
784
|
"""Allow `in` expressions."""
|
|
743
785
|
return self.node_contents_visit(node)
|
|
744
786
|
|
|
745
|
-
def visit_NotIn(self, node):
|
|
787
|
+
def visit_NotIn(self, node: ast.NotIn) -> _T_visit_return:
|
|
746
788
|
"""Allow `not in` expressions."""
|
|
747
789
|
return self.node_contents_visit(node)
|
|
748
790
|
|
|
749
|
-
def visit_Call(self, node):
|
|
791
|
+
def visit_Call(self, node: ast.Call) -> _T_visit_return:
|
|
750
792
|
"""Checks calls with '*args' and '**kwargs'.
|
|
751
793
|
|
|
752
794
|
Note: The following happens only if '*args' or '**kwargs' is used.
|
|
@@ -788,17 +830,17 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
788
830
|
copy_locations(node.func, node.args[0])
|
|
789
831
|
return node
|
|
790
832
|
|
|
791
|
-
def visit_keyword(self, node):
|
|
833
|
+
def visit_keyword(self, node: ast.keyword) -> _T_visit_return:
|
|
792
834
|
"""
|
|
793
835
|
|
|
794
836
|
"""
|
|
795
837
|
return self.node_contents_visit(node)
|
|
796
838
|
|
|
797
|
-
def visit_IfExp(self, node):
|
|
839
|
+
def visit_IfExp(self, node: ast.IfExp) -> _T_visit_return:
|
|
798
840
|
"""Allow `if` expressions without restrictions."""
|
|
799
841
|
return self.node_contents_visit(node)
|
|
800
842
|
|
|
801
|
-
def visit_Attribute(self, node):
|
|
843
|
+
def visit_Attribute(self, node: ast.Attribute) -> _T_visit_return:
|
|
802
844
|
"""Checks and mutates attribute access/assignment.
|
|
803
845
|
|
|
804
846
|
'a.b' becomes '_getattr_(a, "b")'
|
|
@@ -854,7 +896,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
854
896
|
|
|
855
897
|
# Subscripting
|
|
856
898
|
|
|
857
|
-
def visit_Subscript(self, node):
|
|
899
|
+
def visit_Subscript(self, node: ast.Subscript) -> _T_visit_return:
|
|
858
900
|
"""Transforms all kinds of subscripts.
|
|
859
901
|
|
|
860
902
|
'foo[bar]' becomes '_getitem_(foo, bar)'
|
|
@@ -899,7 +941,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
899
941
|
raise NotImplementedError(
|
|
900
942
|
f"Unknown ctx type: {type(node.ctx)}")
|
|
901
943
|
|
|
902
|
-
def visit_Slice(self, node):
|
|
944
|
+
def visit_Slice(self, node: ast.Slice) -> _T_visit_return:
|
|
903
945
|
"""
|
|
904
946
|
|
|
905
947
|
"""
|
|
@@ -907,31 +949,31 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
907
949
|
|
|
908
950
|
# Comprehensions
|
|
909
951
|
|
|
910
|
-
def visit_ListComp(self, node):
|
|
952
|
+
def visit_ListComp(self, node: ast.ListComp) -> _T_visit_return:
|
|
911
953
|
"""
|
|
912
954
|
|
|
913
955
|
"""
|
|
914
956
|
return self.node_contents_visit(node)
|
|
915
957
|
|
|
916
|
-
def visit_SetComp(self, node):
|
|
958
|
+
def visit_SetComp(self, node: ast.SetComp) -> _T_visit_return:
|
|
917
959
|
"""
|
|
918
960
|
|
|
919
961
|
"""
|
|
920
962
|
return self.node_contents_visit(node)
|
|
921
963
|
|
|
922
|
-
def visit_GeneratorExp(self, node):
|
|
964
|
+
def visit_GeneratorExp(self, node: ast.GeneratorExp) -> _T_visit_return:
|
|
923
965
|
"""
|
|
924
966
|
|
|
925
967
|
"""
|
|
926
968
|
return self.node_contents_visit(node)
|
|
927
969
|
|
|
928
|
-
def visit_DictComp(self, node):
|
|
970
|
+
def visit_DictComp(self, node: ast.DictComp) -> _T_visit_return:
|
|
929
971
|
"""
|
|
930
972
|
|
|
931
973
|
"""
|
|
932
974
|
return self.node_contents_visit(node)
|
|
933
975
|
|
|
934
|
-
def visit_comprehension(self, node):
|
|
976
|
+
def visit_comprehension(self, node: ast.comprehension) -> _T_visit_return:
|
|
935
977
|
"""
|
|
936
978
|
|
|
937
979
|
"""
|
|
@@ -939,7 +981,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
939
981
|
|
|
940
982
|
# Statements
|
|
941
983
|
|
|
942
|
-
def visit_Assign(self, node):
|
|
984
|
+
def visit_Assign(self, node: ast.Assign) -> _T_visit_return:
|
|
943
985
|
"""
|
|
944
986
|
|
|
945
987
|
"""
|
|
@@ -988,7 +1030,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
988
1030
|
|
|
989
1031
|
return new_nodes
|
|
990
1032
|
|
|
991
|
-
def visit_AugAssign(self, node):
|
|
1033
|
+
def visit_AugAssign(self, node: ast.AugAssign) -> _T_visit_return:
|
|
992
1034
|
"""Forbid certain kinds of AugAssign
|
|
993
1035
|
|
|
994
1036
|
According to the language reference (and ast.c) the following nodes
|
|
@@ -1039,75 +1081,79 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1039
1081
|
raise NotImplementedError(
|
|
1040
1082
|
f"Unknown target type: {type(node.target)}")
|
|
1041
1083
|
|
|
1042
|
-
def visit_Raise(self, node):
|
|
1084
|
+
def visit_Raise(self, node: ast.Raise) -> _T_visit_return:
|
|
1043
1085
|
"""Allow `raise` statements without restrictions."""
|
|
1044
1086
|
return self.node_contents_visit(node)
|
|
1045
1087
|
|
|
1046
|
-
def visit_Assert(self, node):
|
|
1088
|
+
def visit_Assert(self, node: ast.Assert) -> _T_visit_return:
|
|
1047
1089
|
"""Allow assert statements without restrictions."""
|
|
1048
1090
|
return self.node_contents_visit(node)
|
|
1049
1091
|
|
|
1050
|
-
def visit_Delete(self, node):
|
|
1092
|
+
def visit_Delete(self, node: ast.Delete) -> _T_visit_return:
|
|
1051
1093
|
"""Allow `del` statements without restrictions."""
|
|
1052
1094
|
return self.node_contents_visit(node)
|
|
1053
1095
|
|
|
1054
|
-
def visit_Pass(self, node):
|
|
1096
|
+
def visit_Pass(self, node: ast.Pass) -> _T_visit_return:
|
|
1055
1097
|
"""Allow `pass` statements without restrictions."""
|
|
1056
1098
|
return self.node_contents_visit(node)
|
|
1057
1099
|
|
|
1058
1100
|
# Imports
|
|
1059
1101
|
|
|
1060
|
-
def visit_Import(self, node):
|
|
1102
|
+
def visit_Import(self, node: ast.Import) -> _T_visit_return:
|
|
1061
1103
|
"""Allow `import` statements with restrictions.
|
|
1062
1104
|
See check_import_names."""
|
|
1063
1105
|
return self.check_import_names(node)
|
|
1064
1106
|
|
|
1065
|
-
def visit_ImportFrom(self, node):
|
|
1107
|
+
def visit_ImportFrom(self, node: ast.ImportFrom) -> _T_visit_return:
|
|
1066
1108
|
"""Allow `import from` statements with restrictions.
|
|
1067
1109
|
See check_import_names."""
|
|
1068
1110
|
return self.check_import_names(node)
|
|
1069
1111
|
|
|
1070
|
-
def visit_alias(self, node):
|
|
1112
|
+
def visit_alias(self, node: ast.alias) -> _T_visit_return:
|
|
1071
1113
|
"""Allow `as` statements in import and import from statements."""
|
|
1072
1114
|
return self.node_contents_visit(node)
|
|
1073
1115
|
|
|
1074
1116
|
# Control flow
|
|
1075
1117
|
|
|
1076
|
-
def visit_If(self, node):
|
|
1118
|
+
def visit_If(self, node: ast.If) -> _T_visit_return:
|
|
1077
1119
|
"""Allow `if` statements without restrictions."""
|
|
1078
1120
|
return self.node_contents_visit(node)
|
|
1079
1121
|
|
|
1080
|
-
def visit_For(self, node):
|
|
1122
|
+
def visit_For(self, node: ast.For) -> _T_visit_return:
|
|
1081
1123
|
"""Allow `for` statements with some restrictions."""
|
|
1082
1124
|
return self.guard_iter(node)
|
|
1083
1125
|
|
|
1084
|
-
def visit_While(self, node):
|
|
1126
|
+
def visit_While(self, node: ast.While) -> _T_visit_return:
|
|
1085
1127
|
"""Allow `while` statements."""
|
|
1086
1128
|
return self.node_contents_visit(node)
|
|
1087
1129
|
|
|
1088
|
-
def visit_Break(self, node):
|
|
1130
|
+
def visit_Break(self, node: ast.Break) -> _T_visit_return:
|
|
1089
1131
|
"""Allow `break` statements without restrictions."""
|
|
1090
1132
|
return self.node_contents_visit(node)
|
|
1091
1133
|
|
|
1092
|
-
def visit_Continue(self, node):
|
|
1134
|
+
def visit_Continue(self, node: ast.Continue) -> _T_visit_return:
|
|
1093
1135
|
"""Allow `continue` statements without restrictions."""
|
|
1094
1136
|
return self.node_contents_visit(node)
|
|
1095
1137
|
|
|
1096
|
-
def visit_Try(self, node):
|
|
1138
|
+
def visit_Try(self, node: ast.Try) -> _T_visit_return:
|
|
1097
1139
|
"""Allow `try` without restrictions."""
|
|
1098
1140
|
return self.node_contents_visit(node)
|
|
1099
1141
|
|
|
1100
|
-
def visit_TryStar(self, node):
|
|
1101
|
-
"""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
|
+
"""
|
|
1102
1148
|
self.not_allowed(node)
|
|
1103
1149
|
|
|
1104
|
-
def visit_ExceptHandler(self, node):
|
|
1150
|
+
def visit_ExceptHandler(self, node: ast.ExceptHandler) -> _T_visit_return:
|
|
1105
1151
|
"""Protect exception handlers."""
|
|
1106
1152
|
node = self.node_contents_visit(node)
|
|
1107
1153
|
self.check_name(node, node.name)
|
|
1108
1154
|
return node
|
|
1109
1155
|
|
|
1110
|
-
def visit_With(self, node):
|
|
1156
|
+
def visit_With(self, node: ast.With) -> _T_visit_return:
|
|
1111
1157
|
"""Protect tuple unpacking on with statements."""
|
|
1112
1158
|
node = self.node_contents_visit(node)
|
|
1113
1159
|
|
|
@@ -1122,13 +1168,13 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1122
1168
|
|
|
1123
1169
|
return node
|
|
1124
1170
|
|
|
1125
|
-
def visit_withitem(self, node):
|
|
1171
|
+
def visit_withitem(self, node: ast.withitem) -> _T_visit_return:
|
|
1126
1172
|
"""Allow `with` statements (context managers) without restrictions."""
|
|
1127
1173
|
return self.node_contents_visit(node)
|
|
1128
1174
|
|
|
1129
1175
|
# Function and class definitions
|
|
1130
1176
|
|
|
1131
|
-
def visit_FunctionDef(self, node):
|
|
1177
|
+
def visit_FunctionDef(self, node: ast.FunctionDef) -> _T_visit_return:
|
|
1132
1178
|
"""Allow function definitions (`def`) with some restrictions."""
|
|
1133
1179
|
self.check_name(node, node.name, allow_magic_methods=True)
|
|
1134
1180
|
self.check_function_argument_names(node)
|
|
@@ -1138,44 +1184,44 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1138
1184
|
self.inject_print_collector(node)
|
|
1139
1185
|
return node
|
|
1140
1186
|
|
|
1141
|
-
def visit_Lambda(self, node):
|
|
1187
|
+
def visit_Lambda(self, node: ast.Lambda) -> _T_visit_return:
|
|
1142
1188
|
"""Allow lambda with some restrictions."""
|
|
1143
1189
|
self.check_function_argument_names(node)
|
|
1144
1190
|
return self.node_contents_visit(node)
|
|
1145
1191
|
|
|
1146
|
-
def visit_arguments(self, node):
|
|
1192
|
+
def visit_arguments(self, node: ast.arguments) -> _T_visit_return:
|
|
1147
1193
|
"""
|
|
1148
1194
|
|
|
1149
1195
|
"""
|
|
1150
1196
|
return self.node_contents_visit(node)
|
|
1151
1197
|
|
|
1152
|
-
def visit_arg(self, node):
|
|
1198
|
+
def visit_arg(self, node: ast.arg) -> _T_visit_return:
|
|
1153
1199
|
"""
|
|
1154
1200
|
|
|
1155
1201
|
"""
|
|
1156
1202
|
return self.node_contents_visit(node)
|
|
1157
1203
|
|
|
1158
|
-
def visit_Return(self, node):
|
|
1204
|
+
def visit_Return(self, node: ast.Return) -> _T_visit_return:
|
|
1159
1205
|
"""Allow `return` statements without restrictions."""
|
|
1160
1206
|
return self.node_contents_visit(node)
|
|
1161
1207
|
|
|
1162
|
-
def visit_Yield(self, node):
|
|
1208
|
+
def visit_Yield(self, node: ast.Yield) -> _T_visit_return:
|
|
1163
1209
|
"""Allow `yield`statements without restrictions."""
|
|
1164
1210
|
return self.node_contents_visit(node)
|
|
1165
1211
|
|
|
1166
|
-
def visit_YieldFrom(self, node):
|
|
1212
|
+
def visit_YieldFrom(self, node: ast.YieldFrom) -> _T_visit_return:
|
|
1167
1213
|
"""Allow `yield`statements without restrictions."""
|
|
1168
1214
|
return self.node_contents_visit(node)
|
|
1169
1215
|
|
|
1170
|
-
def visit_Global(self, node):
|
|
1216
|
+
def visit_Global(self, node: ast.Global) -> _T_visit_return:
|
|
1171
1217
|
"""Allow `global` statements without restrictions."""
|
|
1172
1218
|
return self.node_contents_visit(node)
|
|
1173
1219
|
|
|
1174
|
-
def visit_Nonlocal(self, node):
|
|
1220
|
+
def visit_Nonlocal(self, node: ast.Nonlocal) -> _T_visit_return:
|
|
1175
1221
|
"""Deny `nonlocal` statements."""
|
|
1176
1222
|
self.not_allowed(node)
|
|
1177
1223
|
|
|
1178
|
-
def visit_ClassDef(self, node):
|
|
1224
|
+
def visit_ClassDef(self, node: ast.ClassDef) -> _T_visit_return:
|
|
1179
1225
|
"""Check the name of a class definition."""
|
|
1180
1226
|
self.check_name(node, node.name)
|
|
1181
1227
|
node = self.node_contents_visit(node)
|
|
@@ -1186,13 +1232,14 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1186
1232
|
class {0.name}(metaclass=__metaclass__):
|
|
1187
1233
|
pass
|
|
1188
1234
|
'''.format(node))
|
|
1189
|
-
new_class_node =
|
|
1235
|
+
new_class_node = typing.cast(
|
|
1236
|
+
ast.ClassDef, ast.parse(CLASS_DEF).body[0])
|
|
1190
1237
|
new_class_node.body = node.body
|
|
1191
1238
|
new_class_node.bases = node.bases
|
|
1192
1239
|
new_class_node.decorator_list = node.decorator_list
|
|
1193
1240
|
return new_class_node
|
|
1194
1241
|
|
|
1195
|
-
def visit_Module(self, node):
|
|
1242
|
+
def visit_Module(self, node: ast.Module) -> _T_visit_return:
|
|
1196
1243
|
"""Add the print_collector (only if print is used) at the top."""
|
|
1197
1244
|
node = self.node_contents_visit(node)
|
|
1198
1245
|
|
|
@@ -1210,25 +1257,26 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1210
1257
|
|
|
1211
1258
|
# Async und await
|
|
1212
1259
|
|
|
1213
|
-
def visit_AsyncFunctionDef(
|
|
1260
|
+
def visit_AsyncFunctionDef(
|
|
1261
|
+
self, node: ast.AsyncFunctionDef) -> _T_visit_return:
|
|
1214
1262
|
"""Deny async functions."""
|
|
1215
1263
|
self.not_allowed(node)
|
|
1216
1264
|
|
|
1217
|
-
def visit_Await(self, node):
|
|
1265
|
+
def visit_Await(self, node: ast.Await) -> _T_visit_return:
|
|
1218
1266
|
"""Deny async functionality."""
|
|
1219
1267
|
self.not_allowed(node)
|
|
1220
1268
|
|
|
1221
|
-
def visit_AsyncFor(self, node):
|
|
1269
|
+
def visit_AsyncFor(self, node: ast.AsyncFor) -> _T_visit_return:
|
|
1222
1270
|
"""Deny async functionality."""
|
|
1223
1271
|
self.not_allowed(node)
|
|
1224
1272
|
|
|
1225
|
-
def visit_AsyncWith(self, node):
|
|
1273
|
+
def visit_AsyncWith(self, node: ast.AsyncWith) -> _T_visit_return:
|
|
1226
1274
|
"""Deny async functionality."""
|
|
1227
1275
|
self.not_allowed(node)
|
|
1228
1276
|
|
|
1229
1277
|
# Assignment expressions (walrus operator ``:=``)
|
|
1230
1278
|
# New in 3.8
|
|
1231
|
-
def visit_NamedExpr(self, node):
|
|
1279
|
+
def visit_NamedExpr(self, node: ast.NamedExpr) -> _T_visit_return:
|
|
1232
1280
|
"""Allow assignment expressions under some circumstances."""
|
|
1233
1281
|
# while the grammar requires ``node.target`` to be a ``Name``
|
|
1234
1282
|
# the abstract syntax is more permissive and allows an ``expr``.
|
|
@@ -1240,7 +1288,7 @@ class RestrictingNodeTransformer(ast.NodeTransformer):
|
|
|
1240
1288
|
node = self.node_contents_visit(node) # this checks ``node.target``
|
|
1241
1289
|
target = node.target
|
|
1242
1290
|
if not isinstance(target, ast.Name):
|
|
1243
|
-
self.error(
|
|
1291
|
+
self.error( # type: ignore[unreachable]
|
|
1244
1292
|
node,
|
|
1245
1293
|
"Assignment expressions are only allowed for simple targets")
|
|
1246
1294
|
return node
|