12
12
from __future__ import annotations
13
13
14
14
import os
15
+ from concurrent .futures import ProcessPoolExecutor
15
16
import sys
16
17
import logging
17
18
import subprocess as sp
59
60
SCRIPT_NAME = os .path .basename (sys .argv [0 ])
60
61
61
62
logger = logging .getLogger ()
62
- logging .basicConfig (level = logging .INFO , format = "%(levelname)s %(message)s" )
63
63
64
64
65
65
def main () -> int :
66
66
opt = parse_cmdline ()
67
67
if opt .container :
68
68
return run_in_container (opt .container )
69
69
70
+ logging .basicConfig (level = opt .log_level , format = "%(levelname)s %(message)s" )
71
+
70
72
current_ver = "." .join (map (str , sys .version_info [:2 ]))
71
73
if current_ver != PYVER :
72
74
logger .warning (
@@ -83,27 +85,50 @@ def main() -> int:
83
85
PYVER ,
84
86
)
85
87
86
- outputs = []
87
- for fpin in opt .inputs :
88
- fpout = fpin .parent / fpin .name .replace ("_async" , "" )
89
- outputs .append (str (fpout ))
90
- logger .info ("converting %s" , fpin )
91
- with fpin .open () as f :
92
- source = f .read ()
88
+ if not opt .convert_all :
89
+ inputs , outputs = [], []
90
+ for fpin in opt .inputs :
91
+ fpout = fpin .parent / fpin .name .replace ("_async" , "" )
92
+ if fpout .stat ().st_mtime >= fpin .stat ().st_mtime :
93
+ logger .debug ("not converting %s as %s is up to date" , fpin , fpout )
94
+ continue
95
+ inputs .append (fpin )
96
+ outputs .append (fpout )
97
+ if not outputs :
98
+ logger .warning ("all output files are up to date, nothing to do" )
99
+ return 0
100
+
101
+ else :
102
+ inputs = opt .inputs
103
+ outputs = [fpin .parent / fpin .name .replace ("_async" , "" ) for fpin in inputs ]
104
+
105
+ if opt .jobs == 1 :
106
+ logger .debug ("multi-processing disabled" )
107
+ for fpin , fpout in zip (inputs , outputs ):
108
+ convert (fpin , fpout )
109
+ else :
110
+ with ProcessPoolExecutor (max_workers = opt .jobs ) as executor :
111
+ executor .map (convert , inputs , outputs )
93
112
94
- tree = ast .parse (source , filename = str (fpin ))
95
- tree = async_to_sync (tree , filepath = fpin )
96
- output = tree_to_str (tree , fpin )
113
+ if opt .check :
114
+ return check ([str (o ) for o in outputs ])
97
115
98
- with fpout .open ("w" ) as f :
99
- print (output , file = f )
116
+ return 0
100
117
101
- sp .check_call (["black" , "-q" , str (fpout )])
102
118
103
- if opt .check :
104
- return check (outputs )
119
+ def convert (fpin : Path , fpout : Path ) -> None :
120
+ logger .info ("converting %s" , fpin )
121
+ with fpin .open () as f :
122
+ source = f .read ()
105
123
106
- return 0
124
+ tree = ast .parse (source , filename = str (fpin ))
125
+ tree = async_to_sync (tree , filepath = fpin )
126
+ output = tree_to_str (tree , fpin )
127
+
128
+ with fpout .open ("w" ) as f :
129
+ print (output , file = f )
130
+
131
+ sp .check_call (["black" , "-q" , str (fpout )])
107
132
108
133
109
134
def check (outputs : list [str ]) -> int :
@@ -567,6 +592,29 @@ def parse_cmdline() -> Namespace:
567
592
parser .add_argument (
568
593
"--all" , action = "store_true" , help = "process all the files of the project"
569
594
)
595
+ parser .add_argument (
596
+ "-B" ,
597
+ "--convert-all" ,
598
+ action = "store_true" ,
599
+ help = "process specified files without checking last modification times" ,
600
+ )
601
+ parser .add_argument (
602
+ "-j" ,
603
+ "--jobs" ,
604
+ type = int ,
605
+ metavar = "N" ,
606
+ help = (
607
+ "process files concurrently using at most N workers; "
608
+ "if unspecified, the number of processors on the machine will be used"
609
+ ),
610
+ )
611
+ parser .add_argument (
612
+ "-L" ,
613
+ "--log-level" ,
614
+ choices = ["DEBUG" , "INFO" , "WARNING" , "ERROR" , "CRITICAL" ],
615
+ default = "INFO" ,
616
+ help = "Logger level." ,
617
+ )
570
618
container = parser .add_mutually_exclusive_group ()
571
619
container .add_argument (
572
620
"--docker" ,
0 commit comments