Skip to content

Commit a74b041

Browse files
committed
Add distutils module and update os module, among others
CPython 3.6.0
1 parent 3dfb04e commit a74b041

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+30630
-39
lines changed

Lib/compileall.py

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
"""Module/script to byte-compile all .py files to .pyc files.
2+
3+
When called as a script with arguments, this compiles the directories
4+
given as arguments recursively; the -l option prevents it from
5+
recursing into directories.
6+
7+
Without arguments, if compiles all modules on sys.path, without
8+
recursing into subdirectories. (Even though it should do so for
9+
packages -- for now, you'll have to deal with packages separately.)
10+
11+
See module py_compile for details of the actual byte-compilation.
12+
"""
13+
import os
14+
import sys
15+
import importlib.util
16+
import py_compile
17+
import struct
18+
19+
try:
20+
from concurrent.futures import ProcessPoolExecutor
21+
except ImportError:
22+
ProcessPoolExecutor = None
23+
from functools import partial
24+
25+
__all__ = ["compile_dir","compile_file","compile_path"]
26+
27+
def _walk_dir(dir, ddir=None, maxlevels=10, quiet=0):
28+
if quiet < 2 and isinstance(dir, os.PathLike):
29+
dir = os.fspath(dir)
30+
if not quiet:
31+
print('Listing {!r}...'.format(dir))
32+
try:
33+
names = os.listdir(dir)
34+
except OSError:
35+
if quiet < 2:
36+
print("Can't list {!r}".format(dir))
37+
names = []
38+
names.sort()
39+
for name in names:
40+
if name == '__pycache__':
41+
continue
42+
fullname = os.path.join(dir, name)
43+
if ddir is not None:
44+
dfile = os.path.join(ddir, name)
45+
else:
46+
dfile = None
47+
if not os.path.isdir(fullname):
48+
yield fullname
49+
elif (maxlevels > 0 and name != os.curdir and name != os.pardir and
50+
os.path.isdir(fullname) and not os.path.islink(fullname)):
51+
yield from _walk_dir(fullname, ddir=dfile,
52+
maxlevels=maxlevels - 1, quiet=quiet)
53+
54+
def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
55+
quiet=0, legacy=False, optimize=-1, workers=1):
56+
"""Byte-compile all modules in the given directory tree.
57+
58+
Arguments (only dir is required):
59+
60+
dir: the directory to byte-compile
61+
maxlevels: maximum recursion level (default 10)
62+
ddir: the directory that will be prepended to the path to the
63+
file as it is compiled into each byte-code file.
64+
force: if True, force compilation, even if timestamps are up-to-date
65+
quiet: full output with False or 0, errors only with 1,
66+
no output with 2
67+
legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
68+
optimize: optimization level or -1 for level of the interpreter
69+
workers: maximum number of parallel workers
70+
"""
71+
if workers is not None and workers < 0:
72+
raise ValueError('workers must be greater or equal to 0')
73+
74+
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels,
75+
ddir=ddir)
76+
success = True
77+
if workers is not None and workers != 1 and ProcessPoolExecutor is not None:
78+
workers = workers or None
79+
with ProcessPoolExecutor(max_workers=workers) as executor:
80+
results = executor.map(partial(compile_file,
81+
ddir=ddir, force=force,
82+
rx=rx, quiet=quiet,
83+
legacy=legacy,
84+
optimize=optimize),
85+
files)
86+
success = min(results, default=True)
87+
else:
88+
for file in files:
89+
if not compile_file(file, ddir, force, rx, quiet,
90+
legacy, optimize):
91+
success = False
92+
return success
93+
94+
def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
95+
legacy=False, optimize=-1):
96+
"""Byte-compile one file.
97+
98+
Arguments (only fullname is required):
99+
100+
fullname: the file to byte-compile
101+
ddir: if given, the directory name compiled in to the
102+
byte-code file.
103+
force: if True, force compilation, even if timestamps are up-to-date
104+
quiet: full output with False or 0, errors only with 1,
105+
no output with 2
106+
legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
107+
optimize: optimization level or -1 for level of the interpreter
108+
"""
109+
success = True
110+
if quiet < 2 and isinstance(fullname, os.PathLike):
111+
fullname = os.fspath(fullname)
112+
name = os.path.basename(fullname)
113+
if ddir is not None:
114+
dfile = os.path.join(ddir, name)
115+
else:
116+
dfile = None
117+
if rx is not None:
118+
mo = rx.search(fullname)
119+
if mo:
120+
return success
121+
if os.path.isfile(fullname):
122+
if legacy:
123+
cfile = fullname + 'c'
124+
else:
125+
if optimize >= 0:
126+
opt = optimize if optimize >= 1 else ''
127+
cfile = importlib.util.cache_from_source(
128+
fullname, optimization=opt)
129+
else:
130+
cfile = importlib.util.cache_from_source(fullname)
131+
cache_dir = os.path.dirname(cfile)
132+
head, tail = name[:-3], name[-3:]
133+
if tail == '.py':
134+
if not force:
135+
try:
136+
mtime = int(os.stat(fullname).st_mtime)
137+
expect = struct.pack('<4sl', importlib.util.MAGIC_NUMBER,
138+
mtime)
139+
with open(cfile, 'rb') as chandle:
140+
actual = chandle.read(8)
141+
if expect == actual:
142+
return success
143+
except OSError:
144+
pass
145+
if not quiet:
146+
print('Compiling {!r}...'.format(fullname))
147+
try:
148+
ok = py_compile.compile(fullname, cfile, dfile, True,
149+
optimize=optimize)
150+
except py_compile.PyCompileError as err:
151+
success = False
152+
if quiet >= 2:
153+
return success
154+
elif quiet:
155+
print('*** Error compiling {!r}...'.format(fullname))
156+
else:
157+
print('*** ', end='')
158+
# escape non-printable characters in msg
159+
msg = err.msg.encode(sys.stdout.encoding,
160+
errors='backslashreplace')
161+
msg = msg.decode(sys.stdout.encoding)
162+
print(msg)
163+
except (SyntaxError, UnicodeError, OSError) as e:
164+
success = False
165+
if quiet >= 2:
166+
return success
167+
elif quiet:
168+
print('*** Error compiling {!r}...'.format(fullname))
169+
else:
170+
print('*** ', end='')
171+
print(e.__class__.__name__ + ':', e)
172+
else:
173+
if ok == 0:
174+
success = False
175+
return success
176+
177+
def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=0,
178+
legacy=False, optimize=-1):
179+
"""Byte-compile all module on sys.path.
180+
181+
Arguments (all optional):
182+
183+
skip_curdir: if true, skip current directory (default True)
184+
maxlevels: max recursion level (default 0)
185+
force: as for compile_dir() (default False)
186+
quiet: as for compile_dir() (default 0)
187+
legacy: as for compile_dir() (default False)
188+
optimize: as for compile_dir() (default -1)
189+
"""
190+
success = True
191+
for dir in sys.path:
192+
if (not dir or dir == os.curdir) and skip_curdir:
193+
if quiet < 2:
194+
print('Skipping current directory')
195+
else:
196+
success = success and compile_dir(dir, maxlevels, None,
197+
force, quiet=quiet,
198+
legacy=legacy, optimize=optimize)
199+
return success
200+
201+
202+
def main():
203+
"""Script main program."""
204+
import argparse
205+
206+
parser = argparse.ArgumentParser(
207+
description='Utilities to support installing Python libraries.')
208+
parser.add_argument('-l', action='store_const', const=0,
209+
default=10, dest='maxlevels',
210+
help="don't recurse into subdirectories")
211+
parser.add_argument('-r', type=int, dest='recursion',
212+
help=('control the maximum recursion level. '
213+
'if `-l` and `-r` options are specified, '
214+
'then `-r` takes precedence.'))
215+
parser.add_argument('-f', action='store_true', dest='force',
216+
help='force rebuild even if timestamps are up to date')
217+
parser.add_argument('-q', action='count', dest='quiet', default=0,
218+
help='output only error messages; -qq will suppress '
219+
'the error messages as well.')
220+
parser.add_argument('-b', action='store_true', dest='legacy',
221+
help='use legacy (pre-PEP3147) compiled file locations')
222+
parser.add_argument('-d', metavar='DESTDIR', dest='ddir', default=None,
223+
help=('directory to prepend to file paths for use in '
224+
'compile-time tracebacks and in runtime '
225+
'tracebacks in cases where the source file is '
226+
'unavailable'))
227+
parser.add_argument('-x', metavar='REGEXP', dest='rx', default=None,
228+
help=('skip files matching the regular expression; '
229+
'the regexp is searched for in the full path '
230+
'of each file considered for compilation'))
231+
parser.add_argument('-i', metavar='FILE', dest='flist',
232+
help=('add all the files and directories listed in '
233+
'FILE to the list considered for compilation; '
234+
'if "-", names are read from stdin'))
235+
parser.add_argument('compile_dest', metavar='FILE|DIR', nargs='*',
236+
help=('zero or more file and directory names '
237+
'to compile; if no arguments given, defaults '
238+
'to the equivalent of -l sys.path'))
239+
parser.add_argument('-j', '--workers', default=1,
240+
type=int, help='Run compileall concurrently')
241+
242+
args = parser.parse_args()
243+
compile_dests = args.compile_dest
244+
245+
if args.rx:
246+
import re
247+
args.rx = re.compile(args.rx)
248+
249+
250+
if args.recursion is not None:
251+
maxlevels = args.recursion
252+
else:
253+
maxlevels = args.maxlevels
254+
255+
# if flist is provided then load it
256+
if args.flist:
257+
try:
258+
with (sys.stdin if args.flist=='-' else open(args.flist)) as f:
259+
for line in f:
260+
compile_dests.append(line.strip())
261+
except OSError:
262+
if args.quiet < 2:
263+
print("Error reading file list {}".format(args.flist))
264+
return False
265+
266+
if args.workers is not None:
267+
args.workers = args.workers or None
268+
269+
success = True
270+
try:
271+
if compile_dests:
272+
for dest in compile_dests:
273+
if os.path.isfile(dest):
274+
if not compile_file(dest, args.ddir, args.force, args.rx,
275+
args.quiet, args.legacy):
276+
success = False
277+
else:
278+
if not compile_dir(dest, maxlevels, args.ddir,
279+
args.force, args.rx, args.quiet,
280+
args.legacy, workers=args.workers):
281+
success = False
282+
return success
283+
else:
284+
return compile_path(legacy=args.legacy, force=args.force,
285+
quiet=args.quiet)
286+
except KeyboardInterrupt:
287+
if args.quiet < 2:
288+
print("\n[interrupted]")
289+
return False
290+
return True
291+
292+
293+
if __name__ == '__main__':
294+
exit_status = int(not main())
295+
sys.exit(exit_status)

0 commit comments

Comments
 (0)