@@ -674,6 +674,7 @@ def __init__(self):
674
674
self ._type_ignores = {}
675
675
self ._indent = 0
676
676
self ._in_try_star = False
677
+ self ._in_interactive = False
677
678
678
679
def interleave (self , inter , f , seq ):
679
680
"""Call f on each item in seq, calling inter() in between."""
@@ -702,11 +703,20 @@ def maybe_newline(self):
702
703
if self ._source :
703
704
self .write ("\n " )
704
705
705
- def fill (self , text = "" ):
706
+ def maybe_semicolon (self ):
707
+ """Adds a "; " delimiter if it isn't the start of generated source"""
708
+ if self ._source :
709
+ self .write ("; " )
710
+
711
+ def fill (self , text = "" , * , allow_semicolon = True ):
706
712
"""Indent a piece of text and append it, according to the current
707
- indentation level"""
708
- self .maybe_newline ()
709
- self .write (" " * self ._indent + text )
713
+ indentation level, or only delineate with semicolon if applicable"""
714
+ if self ._in_interactive and not self ._indent and allow_semicolon :
715
+ self .maybe_semicolon ()
716
+ self .write (text )
717
+ else :
718
+ self .maybe_newline ()
719
+ self .write (" " * self ._indent + text )
710
720
711
721
def write (self , * text ):
712
722
"""Add new source parts"""
@@ -812,8 +822,17 @@ def visit_Module(self, node):
812
822
ignore .lineno : f"ignore{ ignore .tag } "
813
823
for ignore in node .type_ignores
814
824
}
815
- self ._write_docstring_and_traverse_body (node )
816
- self ._type_ignores .clear ()
825
+ try :
826
+ self ._write_docstring_and_traverse_body (node )
827
+ finally :
828
+ self ._type_ignores .clear ()
829
+
830
+ def visit_Interactive (self , node ):
831
+ self ._in_interactive = True
832
+ try :
833
+ self ._write_docstring_and_traverse_body (node )
834
+ finally :
835
+ self ._in_interactive = False
817
836
818
837
def visit_FunctionType (self , node ):
819
838
with self .delimit ("(" , ")" ):
@@ -945,17 +964,17 @@ def visit_Raise(self, node):
945
964
self .traverse (node .cause )
946
965
947
966
def do_visit_try (self , node ):
948
- self .fill ("try" )
967
+ self .fill ("try" , allow_semicolon = False )
949
968
with self .block ():
950
969
self .traverse (node .body )
951
970
for ex in node .handlers :
952
971
self .traverse (ex )
953
972
if node .orelse :
954
- self .fill ("else" )
973
+ self .fill ("else" , allow_semicolon = False )
955
974
with self .block ():
956
975
self .traverse (node .orelse )
957
976
if node .finalbody :
958
- self .fill ("finally" )
977
+ self .fill ("finally" , allow_semicolon = False )
959
978
with self .block ():
960
979
self .traverse (node .finalbody )
961
980
@@ -976,7 +995,7 @@ def visit_TryStar(self, node):
976
995
self ._in_try_star = prev_in_try_star
977
996
978
997
def visit_ExceptHandler (self , node ):
979
- self .fill ("except*" if self ._in_try_star else "except" )
998
+ self .fill ("except*" if self ._in_try_star else "except" , allow_semicolon = False )
980
999
if node .type :
981
1000
self .write (" " )
982
1001
self .traverse (node .type )
@@ -989,9 +1008,9 @@ def visit_ExceptHandler(self, node):
989
1008
def visit_ClassDef (self , node ):
990
1009
self .maybe_newline ()
991
1010
for deco in node .decorator_list :
992
- self .fill ("@" )
1011
+ self .fill ("@" , allow_semicolon = False )
993
1012
self .traverse (deco )
994
- self .fill ("class " + node .name )
1013
+ self .fill ("class " + node .name , allow_semicolon = False )
995
1014
if hasattr (node , "type_params" ):
996
1015
self ._type_params_helper (node .type_params )
997
1016
with self .delimit_if ("(" , ")" , condition = node .bases or node .keywords ):
@@ -1021,10 +1040,10 @@ def visit_AsyncFunctionDef(self, node):
1021
1040
def _function_helper (self , node , fill_suffix ):
1022
1041
self .maybe_newline ()
1023
1042
for deco in node .decorator_list :
1024
- self .fill ("@" )
1043
+ self .fill ("@" , allow_semicolon = False )
1025
1044
self .traverse (deco )
1026
1045
def_str = fill_suffix + " " + node .name
1027
- self .fill (def_str )
1046
+ self .fill (def_str , allow_semicolon = False )
1028
1047
if hasattr (node , "type_params" ):
1029
1048
self ._type_params_helper (node .type_params )
1030
1049
with self .delimit ("(" , ")" ):
@@ -1075,54 +1094,54 @@ def visit_AsyncFor(self, node):
1075
1094
self ._for_helper ("async for " , node )
1076
1095
1077
1096
def _for_helper (self , fill , node ):
1078
- self .fill (fill )
1097
+ self .fill (fill , allow_semicolon = False )
1079
1098
self .set_precedence (_Precedence .TUPLE , node .target )
1080
1099
self .traverse (node .target )
1081
1100
self .write (" in " )
1082
1101
self .traverse (node .iter )
1083
1102
with self .block (extra = self .get_type_comment (node )):
1084
1103
self .traverse (node .body )
1085
1104
if node .orelse :
1086
- self .fill ("else" )
1105
+ self .fill ("else" , allow_semicolon = False )
1087
1106
with self .block ():
1088
1107
self .traverse (node .orelse )
1089
1108
1090
1109
def visit_If (self , node ):
1091
- self .fill ("if " )
1110
+ self .fill ("if " , allow_semicolon = False )
1092
1111
self .traverse (node .test )
1093
1112
with self .block ():
1094
1113
self .traverse (node .body )
1095
1114
# collapse nested ifs into equivalent elifs.
1096
1115
while node .orelse and len (node .orelse ) == 1 and isinstance (node .orelse [0 ], If ):
1097
1116
node = node .orelse [0 ]
1098
- self .fill ("elif " )
1117
+ self .fill ("elif " , allow_semicolon = False )
1099
1118
self .traverse (node .test )
1100
1119
with self .block ():
1101
1120
self .traverse (node .body )
1102
1121
# final else
1103
1122
if node .orelse :
1104
- self .fill ("else" )
1123
+ self .fill ("else" , allow_semicolon = False )
1105
1124
with self .block ():
1106
1125
self .traverse (node .orelse )
1107
1126
1108
1127
def visit_While (self , node ):
1109
- self .fill ("while " )
1128
+ self .fill ("while " , allow_semicolon = False )
1110
1129
self .traverse (node .test )
1111
1130
with self .block ():
1112
1131
self .traverse (node .body )
1113
1132
if node .orelse :
1114
- self .fill ("else" )
1133
+ self .fill ("else" , allow_semicolon = False )
1115
1134
with self .block ():
1116
1135
self .traverse (node .orelse )
1117
1136
1118
1137
def visit_With (self , node ):
1119
- self .fill ("with " )
1138
+ self .fill ("with " , allow_semicolon = False )
1120
1139
self .interleave (lambda : self .write (", " ), self .traverse , node .items )
1121
1140
with self .block (extra = self .get_type_comment (node )):
1122
1141
self .traverse (node .body )
1123
1142
1124
1143
def visit_AsyncWith (self , node ):
1125
- self .fill ("async with " )
1144
+ self .fill ("async with " , allow_semicolon = False )
1126
1145
self .interleave (lambda : self .write (", " ), self .traverse , node .items )
1127
1146
with self .block (extra = self .get_type_comment (node )):
1128
1147
self .traverse (node .body )
@@ -1264,7 +1283,7 @@ def visit_Name(self, node):
1264
1283
self .write (node .id )
1265
1284
1266
1285
def _write_docstring (self , node ):
1267
- self .fill ()
1286
+ self .fill (allow_semicolon = False )
1268
1287
if node .kind == "u" :
1269
1288
self .write ("u" )
1270
1289
self ._write_str_avoiding_backslashes (node .value , quote_types = _MULTI_QUOTES )
@@ -1558,7 +1577,7 @@ def visit_Slice(self, node):
1558
1577
self .traverse (node .step )
1559
1578
1560
1579
def visit_Match (self , node ):
1561
- self .fill ("match " )
1580
+ self .fill ("match " , allow_semicolon = False )
1562
1581
self .traverse (node .subject )
1563
1582
with self .block ():
1564
1583
for case in node .cases :
@@ -1652,7 +1671,7 @@ def visit_withitem(self, node):
1652
1671
self .traverse (node .optional_vars )
1653
1672
1654
1673
def visit_match_case (self , node ):
1655
- self .fill ("case " )
1674
+ self .fill ("case " , allow_semicolon = False )
1656
1675
self .traverse (node .pattern )
1657
1676
if node .guard :
1658
1677
self .write (" if " )
0 commit comments