@@ -47,8 +47,8 @@ def parse(source, filename='<unknown>', mode='exec', *,
47
47
elif feature_version is None :
48
48
feature_version = - 1
49
49
# Else it should be an int giving the minor version for 3.x.
50
- return compile (source , filename , mode , flags )
51
- # _feature_version=feature_version)
50
+ return compile (source , filename , mode , flags ,
51
+ _feature_version = feature_version )
52
52
53
53
54
54
def literal_eval (node_or_string ):
@@ -59,11 +59,14 @@ def literal_eval(node_or_string):
59
59
sets, booleans, and None.
60
60
"""
61
61
if isinstance (node_or_string , str ):
62
- node_or_string = parse (node_or_string , mode = 'eval' )
62
+ node_or_string = parse (node_or_string . lstrip ( " \t " ) , mode = 'eval' )
63
63
if isinstance (node_or_string , Expression ):
64
64
node_or_string = node_or_string .body
65
65
def _raise_malformed_node (node ):
66
- raise ValueError (f'malformed node or string: { node !r} ' )
66
+ msg = "malformed node or string"
67
+ if lno := getattr (node , 'lineno' , None ):
68
+ msg += f' on line { lno } '
69
+ raise ValueError (msg + f': { node !r} ' )
67
70
def _convert_num (node ):
68
71
if not isinstance (node , Constant ) or type (node .value ) not in (int , float , complex ):
69
72
_raise_malformed_node (node )
@@ -794,6 +797,9 @@ def traverse(self, node):
794
797
else :
795
798
super ().visit (node )
796
799
800
+ # Note: as visit() resets the output text, do NOT rely on
801
+ # NodeVisitor.generic_visit to handle any nodes (as it calls back in to
802
+ # the subclass visit() method, which resets self._source to an empty list)
797
803
def visit (self , node ):
798
804
"""Outputs a source code string that, if converted back to an ast
799
805
(using ast.parse) will generate an AST equivalent to *node*"""
@@ -1483,6 +1489,13 @@ def visit_Slice(self, node):
1483
1489
self .write (":" )
1484
1490
self .traverse (node .step )
1485
1491
1492
+ def visit_Match (self , node ):
1493
+ self .fill ("match " )
1494
+ self .traverse (node .subject )
1495
+ with self .block ():
1496
+ for case in node .cases :
1497
+ self .traverse (case )
1498
+
1486
1499
def visit_arg (self , node ):
1487
1500
self .write (node .arg )
1488
1501
if node .annotation :
@@ -1567,6 +1580,94 @@ def visit_withitem(self, node):
1567
1580
self .write (" as " )
1568
1581
self .traverse (node .optional_vars )
1569
1582
1583
+ def visit_match_case (self , node ):
1584
+ self .fill ("case " )
1585
+ self .traverse (node .pattern )
1586
+ if node .guard :
1587
+ self .write (" if " )
1588
+ self .traverse (node .guard )
1589
+ with self .block ():
1590
+ self .traverse (node .body )
1591
+
1592
+ def visit_MatchValue (self , node ):
1593
+ self .traverse (node .value )
1594
+
1595
+ def visit_MatchSingleton (self , node ):
1596
+ self ._write_constant (node .value )
1597
+
1598
+ def visit_MatchSequence (self , node ):
1599
+ with self .delimit ("[" , "]" ):
1600
+ self .interleave (
1601
+ lambda : self .write (", " ), self .traverse , node .patterns
1602
+ )
1603
+
1604
+ def visit_MatchStar (self , node ):
1605
+ name = node .name
1606
+ if name is None :
1607
+ name = "_"
1608
+ self .write (f"*{ name } " )
1609
+
1610
+ def visit_MatchMapping (self , node ):
1611
+ def write_key_pattern_pair (pair ):
1612
+ k , p = pair
1613
+ self .traverse (k )
1614
+ self .write (": " )
1615
+ self .traverse (p )
1616
+
1617
+ with self .delimit ("{" , "}" ):
1618
+ keys = node .keys
1619
+ self .interleave (
1620
+ lambda : self .write (", " ),
1621
+ write_key_pattern_pair ,
1622
+ zip (keys , node .patterns , strict = True ),
1623
+ )
1624
+ rest = node .rest
1625
+ if rest is not None :
1626
+ if keys :
1627
+ self .write (", " )
1628
+ self .write (f"**{ rest } " )
1629
+
1630
+ def visit_MatchClass (self , node ):
1631
+ self .set_precedence (_Precedence .ATOM , node .cls )
1632
+ self .traverse (node .cls )
1633
+ with self .delimit ("(" , ")" ):
1634
+ patterns = node .patterns
1635
+ self .interleave (
1636
+ lambda : self .write (", " ), self .traverse , patterns
1637
+ )
1638
+ attrs = node .kwd_attrs
1639
+ if attrs :
1640
+ def write_attr_pattern (pair ):
1641
+ attr , pattern = pair
1642
+ self .write (f"{ attr } =" )
1643
+ self .traverse (pattern )
1644
+
1645
+ if patterns :
1646
+ self .write (", " )
1647
+ self .interleave (
1648
+ lambda : self .write (", " ),
1649
+ write_attr_pattern ,
1650
+ zip (attrs , node .kwd_patterns , strict = True ),
1651
+ )
1652
+
1653
+ def visit_MatchAs (self , node ):
1654
+ name = node .name
1655
+ pattern = node .pattern
1656
+ if name is None :
1657
+ self .write ("_" )
1658
+ elif pattern is None :
1659
+ self .write (node .name )
1660
+ else :
1661
+ with self .require_parens (_Precedence .TEST , node ):
1662
+ self .set_precedence (_Precedence .BOR , node .pattern )
1663
+ self .traverse (node .pattern )
1664
+ self .write (f" as { node .name } " )
1665
+
1666
+ def visit_MatchOr (self , node ):
1667
+ with self .require_parens (_Precedence .BOR , node ):
1668
+ self .set_precedence (_Precedence .BOR .next (), * node .patterns )
1669
+ self .interleave (lambda : self .write (" | " ), self .traverse , node .patterns )
1670
+
1570
1671
def unparse (ast_obj ):
1571
1672
unparser = _Unparser ()
1572
1673
return unparser .visit (ast_obj )
0 commit comments