Issue #25768: Make compileall functions return booleans and document
the return values as well as test them. Thanks to Nicholas Chammas for the bug report and initial patch.
This commit is contained in:
parent
4a4ca7c13f
commit
1e3c3e906c
|
@ -103,7 +103,8 @@ Public functions
|
|||
.. function:: compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, workers=1)
|
||||
|
||||
Recursively descend the directory tree named by *dir*, compiling all :file:`.py`
|
||||
files along the way.
|
||||
files along the way. Return a true value if all the files compiled successfully,
|
||||
and a false value otherwise.
|
||||
|
||||
The *maxlevels* parameter is used to limit the depth of the recursion; it
|
||||
defaults to ``10``.
|
||||
|
@ -155,7 +156,8 @@ Public functions
|
|||
|
||||
.. function:: compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1)
|
||||
|
||||
Compile the file with path *fullname*.
|
||||
Compile the file with path *fullname*. Return a true value if the file
|
||||
compiled successfully, and a false value otherwise.
|
||||
|
||||
If *ddir* is given, it is prepended to the path to the file being compiled
|
||||
for use in compilation time tracebacks, and is also compiled in to the
|
||||
|
@ -191,8 +193,10 @@ Public functions
|
|||
|
||||
.. function:: compile_path(skip_curdir=True, maxlevels=0, force=False, quiet=0, legacy=False, optimize=-1)
|
||||
|
||||
Byte-compile all the :file:`.py` files found along ``sys.path``. If
|
||||
*skip_curdir* is true (the default), the current directory is not included
|
||||
Byte-compile all the :file:`.py` files found along ``sys.path``. Return a
|
||||
true value if all the files compiled successfully, and a false value otherwise.
|
||||
|
||||
If *skip_curdir* is true (the default), the current directory is not included
|
||||
in the search. All other parameters are passed to the :func:`compile_dir`
|
||||
function. Note that unlike the other compile functions, ``maxlevels``
|
||||
defaults to ``0``.
|
||||
|
|
|
@ -230,6 +230,11 @@ that may require changes to your code.
|
|||
Changes in the Python API
|
||||
-------------------------
|
||||
|
||||
* The functions in the :mod:`compileall` module now return booleans instead
|
||||
of ``1`` or ``0`` to represent success or failure, respectively. Thanks to
|
||||
booleans being a subclass of integers, this should only be an issue if you
|
||||
were doing identity checks for ``1`` or ``0``. See :issue:`25768`.
|
||||
|
||||
* Reading the :attr:`~urllib.parse.SplitResult.port` attribute of
|
||||
:func:`urllib.parse.urlsplit` and :func:`~urllib.parse.urlparse` results
|
||||
now raises :exc:`ValueError` for out-of-range values, rather than
|
||||
|
|
|
@ -68,7 +68,7 @@ def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
|
|||
"""
|
||||
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels,
|
||||
ddir=ddir)
|
||||
success = 1
|
||||
success = True
|
||||
if workers is not None and workers != 1 and ProcessPoolExecutor is not None:
|
||||
if workers < 0:
|
||||
raise ValueError('workers must be greater or equal to 0')
|
||||
|
@ -81,12 +81,12 @@ def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
|
|||
legacy=legacy,
|
||||
optimize=optimize),
|
||||
files)
|
||||
success = min(results, default=1)
|
||||
success = min(results, default=True)
|
||||
else:
|
||||
for file in files:
|
||||
if not compile_file(file, ddir, force, rx, quiet,
|
||||
legacy, optimize):
|
||||
success = 0
|
||||
success = False
|
||||
return success
|
||||
|
||||
def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
||||
|
@ -104,7 +104,7 @@ def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
|||
legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
|
||||
optimize: optimization level or -1 for level of the interpreter
|
||||
"""
|
||||
success = 1
|
||||
success = True
|
||||
name = os.path.basename(fullname)
|
||||
if ddir is not None:
|
||||
dfile = os.path.join(ddir, name)
|
||||
|
@ -144,7 +144,7 @@ def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
|||
ok = py_compile.compile(fullname, cfile, dfile, True,
|
||||
optimize=optimize)
|
||||
except py_compile.PyCompileError as err:
|
||||
success = 0
|
||||
success = False
|
||||
if quiet >= 2:
|
||||
return success
|
||||
elif quiet:
|
||||
|
@ -157,7 +157,7 @@ def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
|||
msg = msg.decode(sys.stdout.encoding)
|
||||
print(msg)
|
||||
except (SyntaxError, UnicodeError, OSError) as e:
|
||||
success = 0
|
||||
success = False
|
||||
if quiet >= 2:
|
||||
return success
|
||||
elif quiet:
|
||||
|
@ -167,7 +167,7 @@ def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
|||
print(e.__class__.__name__ + ':', e)
|
||||
else:
|
||||
if ok == 0:
|
||||
success = 0
|
||||
success = False
|
||||
return success
|
||||
|
||||
def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=0,
|
||||
|
@ -183,7 +183,7 @@ def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=0,
|
|||
legacy: as for compile_dir() (default False)
|
||||
optimize: as for compile_dir() (default -1)
|
||||
"""
|
||||
success = 1
|
||||
success = True
|
||||
for dir in sys.path:
|
||||
if (not dir or dir == os.curdir) and skip_curdir:
|
||||
if quiet < 2:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import sys
|
||||
import compileall
|
||||
import importlib.util
|
||||
import test.test_importlib.util
|
||||
import os
|
||||
import pathlib
|
||||
import py_compile
|
||||
|
@ -40,6 +41,11 @@ class CompileallTests(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
shutil.rmtree(self.directory)
|
||||
|
||||
def add_bad_source_file(self):
|
||||
self.bad_source_path = os.path.join(self.directory, '_test_bad.py')
|
||||
with open(self.bad_source_path, 'w') as file:
|
||||
file.write('x (\n')
|
||||
|
||||
def data(self):
|
||||
with open(self.bc_path, 'rb') as file:
|
||||
data = file.read(8)
|
||||
|
@ -78,15 +84,31 @@ class CompileallTests(unittest.TestCase):
|
|||
os.unlink(fn)
|
||||
except:
|
||||
pass
|
||||
compileall.compile_file(self.source_path, force=False, quiet=True)
|
||||
self.assertTrue(compileall.compile_file(self.source_path,
|
||||
force=False, quiet=True))
|
||||
self.assertTrue(os.path.isfile(self.bc_path) and
|
||||
not os.path.isfile(self.bc_path2))
|
||||
os.unlink(self.bc_path)
|
||||
compileall.compile_dir(self.directory, force=False, quiet=True)
|
||||
self.assertTrue(compileall.compile_dir(self.directory, force=False,
|
||||
quiet=True))
|
||||
self.assertTrue(os.path.isfile(self.bc_path) and
|
||||
os.path.isfile(self.bc_path2))
|
||||
os.unlink(self.bc_path)
|
||||
os.unlink(self.bc_path2)
|
||||
# Test against bad files
|
||||
self.add_bad_source_file()
|
||||
self.assertFalse(compileall.compile_file(self.bad_source_path,
|
||||
force=False, quiet=2))
|
||||
self.assertFalse(compileall.compile_dir(self.directory,
|
||||
force=False, quiet=2))
|
||||
|
||||
def test_compile_path(self):
|
||||
self.assertTrue(compileall.compile_path(quiet=2))
|
||||
|
||||
with test.test_importlib.util.import_state(path=[self.directory]):
|
||||
self.add_bad_source_file()
|
||||
self.assertFalse(compileall.compile_path(skip_curdir=False,
|
||||
force=True, quiet=2))
|
||||
|
||||
def test_no_pycache_in_non_package(self):
|
||||
# Bug 8563 reported that __pycache__ directories got created by
|
||||
|
|
|
@ -235,6 +235,7 @@ Octavian Cerna
|
|||
Michael Cetrulo
|
||||
Dave Chambers
|
||||
Pascal Chambon
|
||||
Nicholas Chammas
|
||||
John Chandler
|
||||
Hye-Shik Chang
|
||||
Jeffrey Chang
|
||||
|
|
|
@ -123,6 +123,9 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #25768: Have the functions in compileall return booleans instead of
|
||||
ints and add proper documentation and tests for the return values.
|
||||
|
||||
- Issue #24103: Fixed possible use after free in ElementTree.XMLPullParser.
|
||||
|
||||
- Issue #25860: os.fwalk() no longer skips remaining directories when error
|
||||
|
|
Loading…
Reference in New Issue