mirror of
https://github.com/python/cpython.git
synced 2025-12-09 02:35:14 +00:00
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
6 changed files with 49 additions and 14 deletions
|
|
@ -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)
|
.. 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`
|
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
|
The *maxlevels* parameter is used to limit the depth of the recursion; it
|
||||||
defaults to ``10``.
|
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)
|
.. 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
|
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
|
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)
|
.. 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
|
Byte-compile all the :file:`.py` files found along ``sys.path``. Return a
|
||||||
*skip_curdir* is true (the default), the current directory is not included
|
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`
|
in the search. All other parameters are passed to the :func:`compile_dir`
|
||||||
function. Note that unlike the other compile functions, ``maxlevels``
|
function. Note that unlike the other compile functions, ``maxlevels``
|
||||||
defaults to ``0``.
|
defaults to ``0``.
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,11 @@ that may require changes to your code.
|
||||||
Changes in the Python API
|
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
|
* Reading the :attr:`~urllib.parse.SplitResult.port` attribute of
|
||||||
:func:`urllib.parse.urlsplit` and :func:`~urllib.parse.urlparse` results
|
:func:`urllib.parse.urlsplit` and :func:`~urllib.parse.urlparse` results
|
||||||
now raises :exc:`ValueError` for out-of-range values, rather than
|
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,
|
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels,
|
||||||
ddir=ddir)
|
ddir=ddir)
|
||||||
success = 1
|
success = True
|
||||||
if workers is not None and workers != 1 and ProcessPoolExecutor is not None:
|
if workers is not None and workers != 1 and ProcessPoolExecutor is not None:
|
||||||
if workers < 0:
|
if workers < 0:
|
||||||
raise ValueError('workers must be greater or equal to 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,
|
legacy=legacy,
|
||||||
optimize=optimize),
|
optimize=optimize),
|
||||||
files)
|
files)
|
||||||
success = min(results, default=1)
|
success = min(results, default=True)
|
||||||
else:
|
else:
|
||||||
for file in files:
|
for file in files:
|
||||||
if not compile_file(file, ddir, force, rx, quiet,
|
if not compile_file(file, ddir, force, rx, quiet,
|
||||||
legacy, optimize):
|
legacy, optimize):
|
||||||
success = 0
|
success = False
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
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
|
legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
|
||||||
optimize: optimization level or -1 for level of the interpreter
|
optimize: optimization level or -1 for level of the interpreter
|
||||||
"""
|
"""
|
||||||
success = 1
|
success = True
|
||||||
name = os.path.basename(fullname)
|
name = os.path.basename(fullname)
|
||||||
if ddir is not None:
|
if ddir is not None:
|
||||||
dfile = os.path.join(ddir, name)
|
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,
|
ok = py_compile.compile(fullname, cfile, dfile, True,
|
||||||
optimize=optimize)
|
optimize=optimize)
|
||||||
except py_compile.PyCompileError as err:
|
except py_compile.PyCompileError as err:
|
||||||
success = 0
|
success = False
|
||||||
if quiet >= 2:
|
if quiet >= 2:
|
||||||
return success
|
return success
|
||||||
elif quiet:
|
elif quiet:
|
||||||
|
|
@ -157,7 +157,7 @@ def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
||||||
msg = msg.decode(sys.stdout.encoding)
|
msg = msg.decode(sys.stdout.encoding)
|
||||||
print(msg)
|
print(msg)
|
||||||
except (SyntaxError, UnicodeError, OSError) as e:
|
except (SyntaxError, UnicodeError, OSError) as e:
|
||||||
success = 0
|
success = False
|
||||||
if quiet >= 2:
|
if quiet >= 2:
|
||||||
return success
|
return success
|
||||||
elif quiet:
|
elif quiet:
|
||||||
|
|
@ -167,7 +167,7 @@ def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
||||||
print(e.__class__.__name__ + ':', e)
|
print(e.__class__.__name__ + ':', e)
|
||||||
else:
|
else:
|
||||||
if ok == 0:
|
if ok == 0:
|
||||||
success = 0
|
success = False
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=0,
|
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)
|
legacy: as for compile_dir() (default False)
|
||||||
optimize: as for compile_dir() (default -1)
|
optimize: as for compile_dir() (default -1)
|
||||||
"""
|
"""
|
||||||
success = 1
|
success = True
|
||||||
for dir in sys.path:
|
for dir in sys.path:
|
||||||
if (not dir or dir == os.curdir) and skip_curdir:
|
if (not dir or dir == os.curdir) and skip_curdir:
|
||||||
if quiet < 2:
|
if quiet < 2:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
import compileall
|
import compileall
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
import test.test_importlib.util
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import py_compile
|
import py_compile
|
||||||
|
|
@ -40,6 +41,11 @@ class CompileallTests(unittest.TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
shutil.rmtree(self.directory)
|
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):
|
def data(self):
|
||||||
with open(self.bc_path, 'rb') as file:
|
with open(self.bc_path, 'rb') as file:
|
||||||
data = file.read(8)
|
data = file.read(8)
|
||||||
|
|
@ -78,15 +84,31 @@ class CompileallTests(unittest.TestCase):
|
||||||
os.unlink(fn)
|
os.unlink(fn)
|
||||||
except:
|
except:
|
||||||
pass
|
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
|
self.assertTrue(os.path.isfile(self.bc_path) and
|
||||||
not os.path.isfile(self.bc_path2))
|
not os.path.isfile(self.bc_path2))
|
||||||
os.unlink(self.bc_path)
|
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
|
self.assertTrue(os.path.isfile(self.bc_path) and
|
||||||
os.path.isfile(self.bc_path2))
|
os.path.isfile(self.bc_path2))
|
||||||
os.unlink(self.bc_path)
|
os.unlink(self.bc_path)
|
||||||
os.unlink(self.bc_path2)
|
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):
|
def test_no_pycache_in_non_package(self):
|
||||||
# Bug 8563 reported that __pycache__ directories got created by
|
# Bug 8563 reported that __pycache__ directories got created by
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,7 @@ Octavian Cerna
|
||||||
Michael Cetrulo
|
Michael Cetrulo
|
||||||
Dave Chambers
|
Dave Chambers
|
||||||
Pascal Chambon
|
Pascal Chambon
|
||||||
|
Nicholas Chammas
|
||||||
John Chandler
|
John Chandler
|
||||||
Hye-Shik Chang
|
Hye-Shik Chang
|
||||||
Jeffrey Chang
|
Jeffrey Chang
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,9 @@ Core and Builtins
|
||||||
Library
|
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 #24103: Fixed possible use after free in ElementTree.XMLPullParser.
|
||||||
|
|
||||||
- Issue #25860: os.fwalk() no longer skips remaining directories when error
|
- Issue #25860: os.fwalk() no longer skips remaining directories when error
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue