@@ -525,17 +525,38 @@ def test_field_attr_existence(self):
525525 if name == 'Index' :
526526 continue
527527 if self ._is_ast_node (name , item ):
528- x = item ( )
528+ x = self . _construct_ast_class ( item )
529529 if isinstance (x , ast .AST ):
530530 self .assertIs (type (x ._fields ), tuple )
531531
532+ def _construct_ast_class (self , cls ):
533+ kwargs = {}
534+ for name , typ in cls .__annotations__ .items ():
535+ if typ is str :
536+ kwargs [name ] = 'capybara'
537+ elif typ is int :
538+ kwargs [name ] = 42
539+ elif typ is object :
540+ kwargs [name ] = b'capybara'
541+ elif isinstance (typ , type ) and issubclass (typ , ast .AST ):
542+ kwargs [name ] = self ._construct_ast_class (typ )
543+ return cls (** kwargs )
544+
532545 def test_arguments (self ):
533546 x = ast .arguments ()
534547 self .assertEqual (x ._fields , ('posonlyargs' , 'args' , 'vararg' , 'kwonlyargs' ,
535548 'kw_defaults' , 'kwarg' , 'defaults' ))
536-
537- with self .assertRaises (AttributeError ):
538- x .args
549+ self .assertEqual (x .__annotations__ , {
550+ 'posonlyargs' : list [ast .arg ],
551+ 'args' : list [ast .arg ],
552+ 'vararg' : ast .arg | None ,
553+ 'kwonlyargs' : list [ast .arg ],
554+ 'kw_defaults' : list [ast .expr ],
555+ 'kwarg' : ast .arg | None ,
556+ 'defaults' : list [ast .expr ],
557+ })
558+
559+ self .assertEqual (x .args , [])
539560 self .assertIsNone (x .vararg )
540561
541562 x = ast .arguments (* range (1 , 8 ))
@@ -551,7 +572,7 @@ def test_field_attr_writable_deprecated(self):
551572 self .assertEqual (x ._fields , 666 )
552573
553574 def test_field_attr_writable (self ):
554- x = ast .Constant ()
575+ x = ast .Constant (1 )
555576 # We can assign to _fields
556577 x ._fields = 666
557578 self .assertEqual (x ._fields , 666 )
@@ -611,15 +632,22 @@ def test_classattrs_deprecated(self):
611632
612633 self .assertEqual ([str (w .message ) for w in wlog ], [
613634 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead' ,
635+ "Constant.__init__ missing 1 required positional argument: 'value'. This will become "
636+ 'an error in Python 3.15.' ,
614637 'Attribute n is deprecated and will be removed in Python 3.14; use value instead' ,
615638 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead' ,
616639 'Attribute n is deprecated and will be removed in Python 3.14; use value instead' ,
617640 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead' ,
641+ "Constant.__init__ missing 1 required positional argument: 'value'. This will become "
642+ 'an error in Python 3.15.' ,
618643 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead' ,
619644 'Attribute n is deprecated and will be removed in Python 3.14; use value instead' ,
620645 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead' ,
621646 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead' ,
622647 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead' ,
648+ "Constant.__init__ got an unexpected keyword argument 'foo'. Support for "
649+ 'arbitrary keyword arguments is deprecated and will be removed in Python '
650+ '3.15.' ,
623651 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead' ,
624652 'Attribute n is deprecated and will be removed in Python 3.14; use value instead' ,
625653 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead' ,
@@ -636,7 +664,8 @@ def test_classattrs_deprecated(self):
636664 ])
637665
638666 def test_classattrs (self ):
639- x = ast .Constant ()
667+ with self .assertWarns (DeprecationWarning ):
668+ x = ast .Constant ()
640669 self .assertEqual (x ._fields , ('value' , 'kind' ))
641670
642671 with self .assertRaises (AttributeError ):
@@ -651,7 +680,7 @@ def test_classattrs(self):
651680 with self .assertRaises (AttributeError ):
652681 x .foobar
653682
654- x = ast .Constant (lineno = 2 )
683+ x = ast .Constant (lineno = 2 , value = 3 )
655684 self .assertEqual (x .lineno , 2 )
656685
657686 x = ast .Constant (42 , lineno = 0 )
@@ -662,8 +691,9 @@ def test_classattrs(self):
662691 self .assertRaises (TypeError , ast .Constant , 1 , None , 2 )
663692 self .assertRaises (TypeError , ast .Constant , 1 , None , 2 , lineno = 0 )
664693
665- # Arbitrary keyword arguments are supported
666- self .assertEqual (ast .Constant (1 , foo = 'bar' ).foo , 'bar' )
694+ # Arbitrary keyword arguments are supported (but deprecated)
695+ with self .assertWarns (DeprecationWarning ):
696+ self .assertEqual (ast .Constant (1 , foo = 'bar' ).foo , 'bar' )
667697
668698 with self .assertRaisesRegex (TypeError , "Constant got multiple values for argument 'value'" ):
669699 ast .Constant (1 , value = 2 )
@@ -815,11 +845,11 @@ def test_isinstance(self):
815845 assertBytesDeprecated (self .assertNotIsInstance , Constant ('42' ), Bytes )
816846 assertNameConstantDeprecated (self .assertNotIsInstance , Constant (42 ), NameConstant )
817847 assertEllipsisDeprecated (self .assertNotIsInstance , Constant (42 ), Ellipsis )
818- assertNumDeprecated (self .assertNotIsInstance , Constant (), Num )
819- assertStrDeprecated (self .assertNotIsInstance , Constant (), Str )
820- assertBytesDeprecated (self .assertNotIsInstance , Constant (), Bytes )
821- assertNameConstantDeprecated (self .assertNotIsInstance , Constant (), NameConstant )
822- assertEllipsisDeprecated (self .assertNotIsInstance , Constant (), Ellipsis )
848+ assertNumDeprecated (self .assertNotIsInstance , Constant (None ), Num )
849+ assertStrDeprecated (self .assertNotIsInstance , Constant (None ), Str )
850+ assertBytesDeprecated (self .assertNotIsInstance , Constant (None ), Bytes )
851+ assertNameConstantDeprecated (self .assertNotIsInstance , Constant (1 ), NameConstant )
852+ assertEllipsisDeprecated (self .assertNotIsInstance , Constant (None ), Ellipsis )
823853
824854 class S (str ): pass
825855 with assertStrDeprecated ():
@@ -888,8 +918,9 @@ def test_module(self):
888918 self .assertEqual (x .body , body )
889919
890920 def test_nodeclasses (self ):
891- # Zero arguments constructor explicitly allowed
892- x = ast .BinOp ()
921+ # Zero arguments constructor explicitly allowed (but deprecated)
922+ with self .assertWarns (DeprecationWarning ):
923+ x = ast .BinOp ()
893924 self .assertEqual (x ._fields , ('left' , 'op' , 'right' ))
894925
895926 # Random attribute allowed too
@@ -927,8 +958,9 @@ def test_nodeclasses(self):
927958 self .assertEqual (x .right , 3 )
928959 self .assertEqual (x .lineno , 0 )
929960
930- # Random kwargs also allowed
931- x = ast .BinOp (1 , 2 , 3 , foobarbaz = 42 )
961+ # Random kwargs also allowed (but deprecated)
962+ with self .assertWarns (DeprecationWarning ):
963+ x = ast .BinOp (1 , 2 , 3 , foobarbaz = 42 )
932964 self .assertEqual (x .foobarbaz , 42 )
933965
934966 def test_no_fields (self ):
@@ -941,8 +973,9 @@ def test_pickling(self):
941973
942974 for protocol in range (pickle .HIGHEST_PROTOCOL + 1 ):
943975 for ast in (compile (i , "?" , "exec" , 0x400 ) for i in exec_tests ):
944- ast2 = pickle .loads (pickle .dumps (ast , protocol ))
945- self .assertEqual (to_tuple (ast2 ), to_tuple (ast ))
976+ with self .subTest (ast = ast , protocol = protocol ):
977+ ast2 = pickle .loads (pickle .dumps (ast , protocol ))
978+ self .assertEqual (to_tuple (ast2 ), to_tuple (ast ))
946979
947980 def test_invalid_sum (self ):
948981 pos = dict (lineno = 2 , col_offset = 3 )
@@ -1310,8 +1343,9 @@ def test_copy_location(self):
13101343 'lineno=1, col_offset=4, end_lineno=1, end_col_offset=5), lineno=1, '
13111344 'col_offset=0, end_lineno=1, end_col_offset=5))'
13121345 )
1313- src = ast .Call (col_offset = 1 , lineno = 1 , end_lineno = 1 , end_col_offset = 1 )
1314- new = ast .copy_location (src , ast .Call (col_offset = None , lineno = None ))
1346+ func = ast .Name ('spam' , ast .Load ())
1347+ src = ast .Call (col_offset = 1 , lineno = 1 , end_lineno = 1 , end_col_offset = 1 , func = func )
1348+ new = ast .copy_location (src , ast .Call (col_offset = None , lineno = None , func = func ))
13151349 self .assertIsNone (new .end_lineno )
13161350 self .assertIsNone (new .end_col_offset )
13171351 self .assertEqual (new .lineno , 1 )
@@ -1570,15 +1604,15 @@ def test_level_as_none(self):
15701604 self .assertIn ('sleep' , ns )
15711605
15721606 def test_recursion_direct (self ):
1573- e = ast .UnaryOp (op = ast .Not (), lineno = 0 , col_offset = 0 )
1607+ e = ast .UnaryOp (op = ast .Not (), lineno = 0 , col_offset = 0 , operand = ast . Constant ( 1 ) )
15741608 e .operand = e
15751609 with self .assertRaises (RecursionError ):
15761610 with support .infinite_recursion ():
15771611 compile (ast .Expression (e ), "<test>" , "eval" )
15781612
15791613 def test_recursion_indirect (self ):
1580- e = ast .UnaryOp (op = ast .Not (), lineno = 0 , col_offset = 0 )
1581- f = ast .UnaryOp (op = ast .Not (), lineno = 0 , col_offset = 0 )
1614+ e = ast .UnaryOp (op = ast .Not (), lineno = 0 , col_offset = 0 , operand = ast . Constant ( 1 ) )
1615+ f = ast .UnaryOp (op = ast .Not (), lineno = 0 , col_offset = 0 , operand = ast . Constant ( 1 ) )
15821616 e .operand = f
15831617 f .operand = e
15841618 with self .assertRaises (RecursionError ):
@@ -2866,6 +2900,23 @@ def visit_Call(self, node: ast.Call):
28662900 self .assertASTTransformation (PrintToLog , code , expected )
28672901
28682902
2903+ class ASTConstructorTests (unittest .TestCase ):
2904+ """Test the autogenerated constructors for AST nodes."""
2905+
2906+ def test_FunctionDef (self ):
2907+ args = ast .arguments ()
2908+ self .assertEqual (args .args , [])
2909+ self .assertEqual (args .posonlyargs , [])
2910+ with self .assertWarnsRegex (DeprecationWarning ,
2911+ r"FunctionDef\.__init__ missing 1 required positional argument: 'name'" ):
2912+ node = ast .FunctionDef (args = args )
2913+ self .assertFalse (hasattr (node , "name" ))
2914+ self .assertEqual (node .decorator_list , [])
2915+ node = ast .FunctionDef (name = 'foo' , args = args )
2916+ self .assertEqual (node .name , 'foo' )
2917+ self .assertEqual (node .decorator_list , [])
2918+
2919+
28692920@support .cpython_only
28702921class ModuleStateTests (unittest .TestCase ):
28712922 # bpo-41194, bpo-41261, bpo-41631: The _ast module uses a global state.
0 commit comments