1616import py_compile
1717import struct
1818
19- __all__ = ["compile_dir" ,"compile_file" ,"compile_path" ]
19+ try :
20+ from concurrent .futures import ProcessPoolExecutor
21+ except ImportError :
22+ ProcessPoolExecutor = None
23+ from functools import partial
2024
21- def compile_dir (dir , maxlevels = 10 , ddir = None , force = False , rx = None ,
22- quiet = False , legacy = False , optimize = - 1 ):
23- """Byte-compile all modules in the given directory tree.
24-
25- Arguments (only dir is required):
25+ __all__ = ["compile_dir" ,"compile_file" ,"compile_path" ]
2626
27- dir: the directory to byte-compile
28- maxlevels: maximum recursion level (default 10)
29- ddir: the directory that will be prepended to the path to the
30- file as it is compiled into each byte-code file.
31- force: if True, force compilation, even if timestamps are up-to-date
32- quiet: if True, be quiet during compilation
33- legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
34- optimize: optimization level or -1 for level of the interpreter
35- """
27+ def _walk_dir (dir , ddir = None , maxlevels = 10 , quiet = False ):
3628 if not quiet :
3729 print ('Listing {!r}...' .format (dir ))
3830 try :
@@ -41,7 +33,6 @@ def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
4133 print ("Can't list {!r}" .format (dir ))
4234 names = []
4335 names .sort ()
44- success = 1
4536 for name in names :
4637 if name == '__pycache__' :
4738 continue
@@ -51,13 +42,50 @@ def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
5142 else :
5243 dfile = None
5344 if not os .path .isdir (fullname ):
54- if not compile_file (fullname , ddir , force , rx , quiet ,
55- legacy , optimize ):
56- success = 0
45+ yield fullname
5746 elif (maxlevels > 0 and name != os .curdir and name != os .pardir and
5847 os .path .isdir (fullname ) and not os .path .islink (fullname )):
59- if not compile_dir (fullname , maxlevels - 1 , dfile , force , rx ,
60- quiet , legacy , optimize ):
48+ yield from _walk_dir (fullname , ddir = dfile ,
49+ maxlevels = maxlevels - 1 , quiet = quiet )
50+
51+ def compile_dir (dir , maxlevels = 10 , ddir = None , force = False , rx = None ,
52+ quiet = False , legacy = False , optimize = - 1 , workers = 1 ):
53+ """Byte-compile all modules in the given directory tree.
54+
55+ Arguments (only dir is required):
56+
57+ dir: the directory to byte-compile
58+ maxlevels: maximum recursion level (default 10)
59+ ddir: the directory that will be prepended to the path to the
60+ file as it is compiled into each byte-code file.
61+ force: if True, force compilation, even if timestamps are up-to-date
62+ quiet: if True, be quiet during compilation
63+ legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
64+ optimize: optimization level or -1 for level of the interpreter
65+ workers: maximum number of parallel workers
66+ """
67+ files = _walk_dir (dir , quiet = quiet , maxlevels = maxlevels ,
68+ ddir = ddir )
69+ success = 1
70+ if workers is not None and workers != 1 :
71+ if workers < 0 :
72+ raise ValueError ('workers must be greater or equal to 0' )
73+ if ProcessPoolExecutor is None :
74+ raise NotImplementedError ('multiprocessing support not available' )
75+
76+ workers = workers or None
77+ with ProcessPoolExecutor (max_workers = workers ) as executor :
78+ results = executor .map (partial (compile_file ,
79+ ddir = ddir , force = force ,
80+ rx = rx , quiet = quiet ,
81+ legacy = legacy ,
82+ optimize = optimize ),
83+ files )
84+ success = min (results , default = 1 )
85+ else :
86+ for file in files :
87+ if not compile_file (file , ddir , force , rx , quiet ,
88+ legacy , optimize ):
6189 success = 0
6290 return success
6391
@@ -196,8 +224,10 @@ def main():
196224 help = ('zero or more file and directory names '
197225 'to compile; if no arguments given, defaults '
198226 'to the equivalent of -l sys.path' ))
199- args = parser .parse_args ()
227+ parser .add_argument ('-j' , '--workers' , default = 1 ,
228+ type = int , help = 'Run compileall concurrently' )
200229
230+ args = parser .parse_args ()
201231 compile_dests = args .compile_dest
202232
203233 if (args .ddir and (len (compile_dests ) != 1
@@ -223,6 +253,9 @@ def main():
223253 print ("Error reading file list {}" .format (args .flist ))
224254 return False
225255
256+ if args .workers is not None :
257+ args .workers = args .workers or None
258+
226259 success = True
227260 try :
228261 if compile_dests :
@@ -234,7 +267,7 @@ def main():
234267 else :
235268 if not compile_dir (dest , maxlevels , args .ddir ,
236269 args .force , args .rx , args .quiet ,
237- args .legacy ):
270+ args .legacy , workers = args . workers ):
238271 success = False
239272 return success
240273 else :
0 commit comments