112
112
sections .append (section .strip ())
113
113
114
114
115
+ def f (s ):
116
+ """
117
+ Basic support for 3.6's f-strings, in 3.5!
118
+
119
+ Formats "s" using appropriate globals and locals
120
+ dictionaries. This f-string:
121
+ f"hello a is {a}"
122
+ simply becomes
123
+ f("hello a is {a}")
124
+ In other words, just throw parentheses around the
125
+ string, and you're done!
126
+
127
+ Implemented internally using str.format_map().
128
+ This means it doesn't support expressions:
129
+ f("two minus three is {2-3}")
130
+ And it doesn't support function calls:
131
+ f("how many elements? {len(my_list)}")
132
+ But most other f-string features work.
133
+ """
134
+ frame = sys ._getframe (1 )
135
+ d = dict (builtins .__dict__ )
136
+ d .update (frame .f_globals )
137
+ d .update (frame .f_locals )
138
+ return s .format_map (d )
139
+
140
+
115
141
def sanitize_section (section ):
116
142
"""
117
143
Cleans up a section string, making it viable as a directory name.
@@ -224,10 +250,10 @@ def sortable_datetime():
224
250
225
251
226
252
def prompt (prompt ):
227
- return input ("[{}> " . format ( prompt ))
253
+ return input (f ( "[{prompt }> " ))
228
254
229
255
def require_ok (prompt ):
230
- prompt = "[{}> " . format ( prompt )
256
+ prompt = f ( "[{prompt }> " )
231
257
while True :
232
258
s = input (prompt ).strip ()
233
259
if s == 'ok' :
@@ -457,7 +483,7 @@ def parse(self, text, *, metadata=None, filename="input"):
457
483
line_number = None
458
484
459
485
def throw (s ):
460
- raise BlurbError ("Error in {}:{}:\n {}" . format ( filename , line_number , s ))
486
+ raise BlurbError (f ( "Error in {filename }:{line_number }:\n {s}" ))
461
487
462
488
def finish_entry ():
463
489
nonlocal body
@@ -522,8 +548,8 @@ def load(self, filename, *, metadata=None):
522
548
523
549
Broadly equivalent to blurb.parse(open(filename).read()).
524
550
"""
525
- with open (filename , "rt" , encoding = "utf-8" ) as f :
526
- text = f .read ()
551
+ with open (filename , "rt" , encoding = "utf-8" ) as file :
552
+ text = file .read ()
527
553
self .parse (text , metadata = metadata , filename = filename )
528
554
529
555
def __str__ (self ):
@@ -537,7 +563,7 @@ def __str__(self):
537
563
add_separator = True
538
564
if metadata :
539
565
for name , value in sorted (metadata .items ()):
540
- add (".. {}: {}\n " . format ( name , value ))
566
+ add (f ( ".. {name }: {value }\n " ))
541
567
add ("\n " )
542
568
add (textwrap_body (body ))
543
569
return "" .join (output )
@@ -547,8 +573,8 @@ def save(self, path):
547
573
safe_mkdir (dirname )
548
574
549
575
text = str (self )
550
- with open (path , "wt" , encoding = "utf-8" ) as f :
551
- f .write (text )
576
+ with open (path , "wt" , encoding = "utf-8" ) as file :
577
+ file .write (text )
552
578
553
579
@staticmethod
554
580
def _parse_next_filename (filename ):
@@ -559,10 +585,10 @@ def _parse_next_filename(filename):
559
585
components = filename .split (os .sep )
560
586
section , filename = components [- 2 :]
561
587
section = unsanitize_section (section )
562
- assert section in sections , "Unknown section {}" . format ( section )
588
+ assert section in sections , f ( "Unknown section {section}" )
563
589
564
590
fields = [x .strip () for x in filename .split ("." )]
565
- assert len (fields ) >= 4 , "Can't parse 'next' filename! filename {!r} fields {}" . format ( filename , fields )
591
+ assert len (fields ) >= 4 , f ( "Can't parse 'next' filename! filename {filename !r} fields {fields}" )
566
592
assert fields [- 1 ] == "rst"
567
593
568
594
metadata = {"date" : fields [0 ], "nonce" : fields [- 2 ], "section" : section }
@@ -656,8 +682,8 @@ def filename_test(self, filename):
656
682
b .load (filename )
657
683
self .assertTrue (b )
658
684
if os .path .exists (filename + '.res' ):
659
- with open (filename + '.res' , encoding = 'utf-8' ) as f :
660
- expected = f .read ()
685
+ with open (filename + '.res' , encoding = 'utf-8' ) as file :
686
+ expected = file .read ()
661
687
self .assertEqual (str (b ), expected )
662
688
663
689
def test_files (self ):
@@ -712,8 +738,8 @@ def chdir_to_repo_root():
712
738
def test_first_line (filename , test ):
713
739
if not os .path .exists (filename ):
714
740
return False
715
- with open (filename , "rt" ) as f :
716
- lines = f .read ().split ('\n ' )
741
+ with open (filename , "rt" ) as file :
742
+ lines = file .read ().split ('\n ' )
717
743
if not (lines and test (lines [0 ])):
718
744
return False
719
745
return True
@@ -751,7 +777,7 @@ def subcommand(fn):
751
777
def get_subcommand (subcommand ):
752
778
fn = subcommands .get (subcommand )
753
779
if not fn :
754
- error ("Unknown subcommand: {}\n Run 'blurb help' for help." . format ( subcommand ))
780
+ error (f ( "Unknown subcommand: {subcommand }\n Run 'blurb help' for help." ))
755
781
return fn
756
782
757
783
@@ -813,19 +839,19 @@ def help(subcommand=None):
813
839
for name , p in inspect .signature (fn ).parameters .items ():
814
840
if p .kind == inspect .Parameter .KEYWORD_ONLY :
815
841
short_option = name [0 ]
816
- options .append (" [-{}|--{}]" . format ( short_option , name ))
842
+ options .append (f ( " [-{short_option }|--{name }]" ))
817
843
elif p .kind == inspect .Parameter .POSITIONAL_OR_KEYWORD :
818
844
positionals .append (" " )
819
845
has_default = (p .default != inspect ._empty )
820
846
if has_default :
821
847
positionals .append ("[" )
822
848
nesting += 1
823
- positionals .append ("<{}>" . format ( name ))
849
+ positionals .append (f ( "<{name }>" ))
824
850
positionals .append ("]" * nesting )
825
851
826
852
827
853
parameters = "" .join (options + positionals )
828
- print ("blurb {}{}" . format ( subcommand , parameters ))
854
+ print (f ( "blurb {subcommand}{parameters}" ))
829
855
print ()
830
856
print (doc )
831
857
sys .exit (0 )
@@ -888,7 +914,7 @@ def add():
888
914
atexit .register (lambda : os .unlink (tmp_path ))
889
915
890
916
def init_tmp_with_template ():
891
- with open (tmp_path , "wt" , encoding = "utf-8" ) as f :
917
+ with open (tmp_path , "wt" , encoding = "utf-8" ) as file :
892
918
# hack:
893
919
# my editor likes to strip trailing whitespace from lines.
894
920
# normally this is a good idea. but in the case of the template
@@ -902,7 +928,7 @@ def init_tmp_with_template():
902
928
if without_space not in text :
903
929
sys .exit ("Can't find BPO line to ensure there's a space on the end!" )
904
930
text = text .replace (without_space , with_space )
905
- f .write (text )
931
+ file .write (text )
906
932
907
933
init_tmp_with_template ()
908
934
@@ -916,7 +942,7 @@ def init_tmp_with_template():
916
942
else :
917
943
args = list (shlex .split (editor ))
918
944
if not shutil .which (args [0 ]):
919
- sys .exit ("Invalid GIT_EDITOR / EDITOR value: {}" . format ( editor ))
945
+ sys .exit (f ( "Invalid GIT_EDITOR / EDITOR value: {editor}" ))
920
946
args .append (tmp_path )
921
947
922
948
while True :
@@ -936,7 +962,7 @@ def init_tmp_with_template():
936
962
937
963
if failure :
938
964
print ()
939
- print ("Error: {}" . format ( failure ))
965
+ print (f ( "Error: {failure}" ))
940
966
print ()
941
967
try :
942
968
prompt ("Hit return to retry (or Ctrl-C to abort)" )
@@ -970,20 +996,20 @@ def release(version):
970
996
if existing_filenames :
971
997
error ("Sorry, can't handle appending 'next' files to an existing version (yet)." )
972
998
973
- output = "Misc/NEWS.d/{}.rst" . format ( version )
999
+ output = f ( "Misc/NEWS.d/{version }.rst" )
974
1000
filenames = glob_blurbs ("next" )
975
1001
blurbs = Blurbs ()
976
1002
date = current_date ()
977
1003
978
1004
if not filenames :
979
- print ("No blurbs found. Setting {} as having no changes." . format ( version ))
980
- body = "There were no new changes in version {}.\n " . format ( version )
1005
+ print (f ( "No blurbs found. Setting {version } as having no changes." ))
1006
+ body = f ( "There were no new changes in version {version }.\n " )
981
1007
metadata = {"no changes" : "True" , "bpo" : "0" , "section" : "Library" , "date" : date , "nonce" : nonceify (body )}
982
1008
blurbs .append ((metadata , body ))
983
1009
else :
984
1010
no_changes = None
985
1011
count = len (filenames )
986
- print ('Merging {} blurbs to "{}".' . format ( count , output ))
1012
+ print (f ( 'Merging {count } blurbs to "{output }".' ))
987
1013
988
1014
for filename in filenames :
989
1015
if not filename .endswith (".rst" ):
@@ -999,14 +1025,15 @@ def release(version):
999
1025
git_add_files .append (output )
1000
1026
flush_git_add_files ()
1001
1027
1002
- print ("Removing {} 'next' files from git." .format (len (filenames )))
1028
+ how_many = len (filenames )
1029
+ print (f ("Removing {how_many} 'next' files from git." ))
1003
1030
git_rm_files .extend (filenames )
1004
1031
flush_git_rm_files ()
1005
1032
1006
1033
# sanity check: ensuring that saving/reloading the merged blurb file works.
1007
1034
blurbs2 = Blurbs ()
1008
1035
blurbs2 .load (output )
1009
- assert blurbs2 == blurbs , "Reloading {} isn't reproducible?!" . format ( output )
1036
+ assert blurbs2 == blurbs , f ( "Reloading {output } isn't reproducible?!" )
1010
1037
1011
1038
print ()
1012
1039
print ("Ready for commit." )
@@ -1077,7 +1104,7 @@ def print(*a, sep=" "):
1077
1104
metadata , body = blurbs [0 ]
1078
1105
release_date = metadata ["release date" ]
1079
1106
1080
- print ("*Release date: {}*" . format ( release_date ))
1107
+ print (f ( "*Release date: {release_date }*" ))
1081
1108
print ()
1082
1109
1083
1110
if "no changes" in metadata :
@@ -1145,11 +1172,11 @@ def populate():
1145
1172
1146
1173
for section in sections :
1147
1174
dir_name = sanitize_section (section )
1148
- dir_path = "NEWS.d/next/{}" . format ( dir_name )
1175
+ dir_path = f ( "NEWS.d/next/{dir_name}" )
1149
1176
safe_mkdir (dir_path )
1150
- readme_path = "NEWS.d/next/{}/README.rst" . format ( dir_name )
1151
- with open (readme_path , "wt" , encoding = "utf-8" ) as f :
1152
- f .write ("Put news entry ``blurb`` files for the *{}* section in this directory.\n " . format ( section ))
1177
+ readme_path = f ( "NEWS.d/next/{dir_name }/README.rst" )
1178
+ with open (readme_path , "wt" , encoding = "utf-8" ) as readme :
1179
+ readme .write (f ( "Put news entry ``blurb`` files for the *{section }* section in this directory.\n " ))
1153
1180
git_add_files .append (dir_path )
1154
1181
git_add_files .append (readme_path )
1155
1182
flush_git_add_files ()
@@ -1170,7 +1197,7 @@ def export():
1170
1197
# """
1171
1198
# Test function for blurb command-line processing.
1172
1199
# """
1173
- # print("arg: boolean {} option {}".format(boolean, option ))
1200
+ # print(f( "arg: boolean {boolean } option {option}" ))
1174
1201
1175
1202
1176
1203
@subcommand
@@ -1255,7 +1282,7 @@ def flush_blurb():
1255
1282
fields .append (field )
1256
1283
see_also = ", " .join (fields )
1257
1284
# print("see_also: ", repr(see_also))
1258
- accumulator .append ("(See also: {})" . format ( see_also ))
1285
+ accumulator .append (f ( "(See also: {see_also })" ))
1259
1286
see_also = None
1260
1287
if not accumulator :
1261
1288
return
@@ -1301,8 +1328,8 @@ def flush_version():
1301
1328
if version is None :
1302
1329
assert not blurbs , "version should only be None initially, we shouldn't have blurbs yet"
1303
1330
return
1304
- assert blurbs , "No blurbs defined when flushing version {}!" . format ( version )
1305
- output = "NEWS.d/{}.rst" . format ( version )
1331
+ assert blurbs , f ( "No blurbs defined when flushing version {version }!" )
1332
+ output = f ( "NEWS.d/{version }.rst" )
1306
1333
1307
1334
if released :
1308
1335
# saving merged blurb file for version, e.g. Misc/NEWS.d/3.7.0a1.rst
@@ -1318,8 +1345,8 @@ def flush_version():
1318
1345
blurbs .clear ()
1319
1346
version_count += 1
1320
1347
1321
- with open ("NEWS" , "rt" , encoding = "utf-8" ) as f :
1322
- for line_number , line in enumerate (f ):
1348
+ with open ("NEWS" , "rt" , encoding = "utf-8" ) as file :
1349
+ for line_number , line in enumerate (file ):
1323
1350
line = line .rstrip ()
1324
1351
1325
1352
if line .startswith ("\ufeff " ):
@@ -1420,11 +1447,11 @@ def flush_version():
1420
1447
elif line .startswith ("- Issue #9516: Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET" ):
1421
1448
line = "- Issue #9516 and Issue #9516: avoid errors in sysconfig when MACOSX_DEPLOYMENT_TARGET"
1422
1449
elif line .title ().startswith (("- Request #" , "- Bug #" , "- Patch #" , "- Patches #" )):
1423
- # print("FIXING LINE {}: {!r}".format(line_number), line )
1450
+ # print(f( "FIXING LINE {line_number }: {line !r}") )
1424
1451
line = "- Issue #" + line .partition ('#' )[2 ]
1425
- # print("FIXED LINE {!r}".format(line ))
1452
+ # print(f( "FIXED LINE {line_number}: {line !r}"))
1426
1453
# else:
1427
- # print("NOT FIXING LINE {}: {!r}".format(line_number, line ))
1454
+ # print(f( "NOT FIXING LINE {line_number }: {line !r}"))
1428
1455
1429
1456
1430
1457
# 4. determine the actual content of the line
@@ -1489,7 +1516,7 @@ def flush_version():
1489
1516
line = line [4 :]
1490
1517
parse_bpo = True
1491
1518
else :
1492
- # print("[[{:8} no bpo]] {}".format(line_number, line ))
1519
+ # print(f( "[[{line_number :8} no bpo]] {line}" ))
1493
1520
parse_bpo = False
1494
1521
if parse_bpo :
1495
1522
# GAAAH
@@ -1529,9 +1556,9 @@ def flush_version():
1529
1556
try :
1530
1557
int (bpo ) # this will throw if it's not a legal int
1531
1558
except ValueError :
1532
- sys .exit ("Couldn't convert bpo number to int on line {}! " . format ( line_number ) + repr ( bpo ))
1559
+ sys .exit (f ( "Couldn't convert bpo number to int on line {line_number }! { bpo!r}" ))
1533
1560
if see_also == "partially" :
1534
- sys .exit ("What the hell on line {}! " . format ( line_number ) + repr ( bpo ))
1561
+ sys .exit (f ( "What the hell on line {line_number }! { bpo!r}" ))
1535
1562
1536
1563
# 4.6.1 continuation of blurb
1537
1564
elif line .startswith (" " ):
@@ -1540,7 +1567,7 @@ def flush_version():
1540
1567
elif line .startswith (" * " ):
1541
1568
line = line [3 :]
1542
1569
elif line :
1543
- sys .exit ("Didn't recognize line {}! " . format ( line_number ) + repr ( line ))
1570
+ sys .exit (f ( "Didn't recognize line {line_number }! { line!r}" ))
1544
1571
# only add blank lines if we have an initial line in the accumulator
1545
1572
if line or accumulator :
1546
1573
accumulator .append (line )
@@ -1552,7 +1579,7 @@ def flush_version():
1552
1579
git_rm_files .append ("NEWS" )
1553
1580
flush_git_rm_files ()
1554
1581
1555
- print ("Wrote {} news items across {} versions." . format ( blurb_count , version_count ))
1582
+ print (f ( "Wrote {blurb_count } news items across {version_count } versions." ))
1556
1583
print ()
1557
1584
print ("Ready for commit." )
1558
1585
@@ -1601,10 +1628,10 @@ def main():
1601
1628
def handle_option (s , dict ):
1602
1629
name = dict .get (s , None )
1603
1630
if not name :
1604
- sys .exit ('blurb: Unknown option for {}: "{}"' . format ( subcommand , s ))
1631
+ sys .exit (f ( 'blurb: Unknown option for {subcommand }: "{s }"' ))
1605
1632
kwargs [name ] = not kwargs [name ]
1606
1633
1607
- # print("short_options {} long_options {}".format(short_options, long_options ))
1634
+ # print(f( "short_options {short_options } long_options {long_options}" ))
1608
1635
for a in args :
1609
1636
if done_with_options :
1610
1637
filtered_args .append (a )
@@ -1638,7 +1665,7 @@ def handle_option(s, dict):
1638
1665
# whoops, must be a real type error, reraise
1639
1666
raise e
1640
1667
1641
- how_many = "{ } argument". format ( specified )
1668
+ how_many = f ( "{specified } argument" )
1642
1669
if specified != 1 :
1643
1670
how_many += "s"
1644
1671
@@ -1649,12 +1676,12 @@ def handle_option(s, dict):
1649
1676
middle = "requires"
1650
1677
else :
1651
1678
plural = "" if required == 1 else "s"
1652
- middle = "requires at least {} argument{} and at most" . format ( required , plural )
1653
- middle += " {} argument" . format ( total )
1679
+ middle = f ( "requires at least {required } argument{plural } and at most" )
1680
+ middle += f ( " {total } argument" )
1654
1681
if total != 1 :
1655
1682
middle += "s"
1656
1683
1657
- print ('Error: Wrong number of arguments!\n \n blurb {} {},\n and you specified {}.' . format ( subcommand , middle , how_many ))
1684
+ print (f ( 'Error: Wrong number of arguments!\n \n blurb {subcommand } {middle },\n and you specified {how_many }.' ))
1658
1685
print ()
1659
1686
print ("usage: " , end = "" )
1660
1687
help (subcommand )
0 commit comments