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.
@@ -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
- def copy_locations(new_node, old_node):
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
- def __init__(self, errors=None, warnings=None, used_names=None):
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 error discovered during transformation."""
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
- spec.values.append(ast.Tuple([], ast.Load()))
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
- spec.values[0].elts.append(el)
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(self, target, value):
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, node, target):
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(targets=[target], value=converter)]
346
- finalbody = [self.gen_del_stmt(tmp_name)]
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(self, node, name, allow_magic_methods=False):
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(self, node):
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(self, node, position=0):
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, node):
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(self, node):
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 = ast.parse(CLASS_DEF).body[0]
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(self, node):
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