bpo-38731: Add --quiet option to py_compile CLI (GH-17134)
This commit is contained in:
parent
af08db7bac
commit
daff39070e
|
@ -125,21 +125,33 @@ byte-code cache files in the directory containing the source code.
|
||||||
system external to Python like a build system.
|
system external to Python like a build system.
|
||||||
|
|
||||||
|
|
||||||
.. function:: main(args=None)
|
Command-Line Interface
|
||||||
|
----------------------
|
||||||
|
|
||||||
Compile several source files. The files named in *args* (or on the command
|
This module can be invoked as a script to compile several source
|
||||||
line, if *args* is ``None``) are compiled and the resulting byte-code is
|
files. The files named in *filenames* are compiled and the resulting
|
||||||
cached in the normal manner. This function does not search a directory
|
bytecode is cached in the normal manner. This program does not search
|
||||||
structure to locate source files; it only compiles files named explicitly.
|
a directory structure to locate source files; it only compiles files
|
||||||
If ``'-'`` is the only parameter in args, the list of files is taken from
|
named explicitly. The exit status is nonzero if one of the files could
|
||||||
standard input.
|
not be compiled.
|
||||||
|
|
||||||
|
.. program:: python -m py_compile
|
||||||
|
|
||||||
|
.. cmdoption:: <file> ... <fileN>
|
||||||
|
-
|
||||||
|
|
||||||
|
Positional arguments are files to compile. If ``-`` is the only
|
||||||
|
parameter, the list of files is taken from standard input.
|
||||||
|
|
||||||
|
.. cmdoption:: -q, --quiet
|
||||||
|
|
||||||
|
Suppress errors output.
|
||||||
|
|
||||||
.. versionchanged:: 3.2
|
.. versionchanged:: 3.2
|
||||||
Added support for ``'-'``.
|
Added support for ``-``.
|
||||||
|
|
||||||
When this module is run as a script, the :func:`main` is used to compile all the
|
.. versionchanged:: 3.10
|
||||||
files named on the command line. The exit status is nonzero if one of the files
|
Added support for :option:`-q`.
|
||||||
could not be compiled.
|
|
||||||
|
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
|
@ -110,6 +110,12 @@ Added the *root_dir* and *dir_fd* parameters in :func:`~glob.glob` and
|
||||||
:func:`~glob.iglob` which allow to specify the root directory for searching.
|
:func:`~glob.iglob` which allow to specify the root directory for searching.
|
||||||
(Contributed by Serhiy Storchaka in :issue:`38144`.)
|
(Contributed by Serhiy Storchaka in :issue:`38144`.)
|
||||||
|
|
||||||
|
py_compile
|
||||||
|
----------
|
||||||
|
|
||||||
|
Added ``--quiet`` option to command-line interface of :mod:`py_compile`.
|
||||||
|
(Contributed by Gregory Schevchenko in :issue:`38731`.)
|
||||||
|
|
||||||
sys
|
sys
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -173,46 +173,40 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,
|
||||||
return cfile
|
return cfile
|
||||||
|
|
||||||
|
|
||||||
def main(args=None):
|
def main():
|
||||||
"""Compile several source files.
|
import argparse
|
||||||
|
|
||||||
The files named in 'args' (or on the command line, if 'args' is
|
description = 'A simple command-line interface for py_compile module.'
|
||||||
not specified) are compiled and the resulting bytecode is cached
|
parser = argparse.ArgumentParser(description=description)
|
||||||
in the normal manner. This function does not search a directory
|
parser.add_argument(
|
||||||
structure to locate source files; it only compiles files named
|
'-q', '--quiet',
|
||||||
explicitly. If '-' is the only parameter in args, the list of
|
action='store_true',
|
||||||
files is taken from standard input.
|
help='Suppress error output',
|
||||||
|
)
|
||||||
"""
|
parser.add_argument(
|
||||||
if args is None:
|
'filenames',
|
||||||
args = sys.argv[1:]
|
nargs='+',
|
||||||
rv = 0
|
help='Files to compile',
|
||||||
if args == ['-']:
|
)
|
||||||
while True:
|
args = parser.parse_args()
|
||||||
filename = sys.stdin.readline()
|
if args.filenames == ['-']:
|
||||||
if not filename:
|
filenames = sys.stdin.readlines()
|
||||||
break
|
|
||||||
filename = filename.rstrip('\n')
|
|
||||||
try:
|
|
||||||
compile(filename, doraise=True)
|
|
||||||
except PyCompileError as error:
|
|
||||||
rv = 1
|
|
||||||
if quiet < 2:
|
|
||||||
sys.stderr.write("%s\n" % error.msg)
|
|
||||||
except OSError as error:
|
|
||||||
rv = 1
|
|
||||||
if quiet < 2:
|
|
||||||
sys.stderr.write("%s\n" % error)
|
|
||||||
else:
|
else:
|
||||||
for filename in args:
|
filenames = args.filenames
|
||||||
|
for filename in filenames:
|
||||||
try:
|
try:
|
||||||
compile(filename, doraise=True)
|
compile(filename, doraise=True)
|
||||||
except PyCompileError as error:
|
except PyCompileError as error:
|
||||||
# return value to indicate at least one failure
|
if args.quiet:
|
||||||
rv = 1
|
parser.exit(1)
|
||||||
if quiet < 2:
|
else:
|
||||||
sys.stderr.write("%s\n" % error.msg)
|
parser.exit(1, error.msg)
|
||||||
return rv
|
except OSError as error:
|
||||||
|
if args.quiet:
|
||||||
|
parser.exit(1)
|
||||||
|
else:
|
||||||
|
parser.exit(1, str(error))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(main())
|
main()
|
||||||
|
|
|
@ -4,12 +4,13 @@ import os
|
||||||
import py_compile
|
import py_compile
|
||||||
import shutil
|
import shutil
|
||||||
import stat
|
import stat
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import os_helper
|
from test.support import os_helper, script_helper
|
||||||
|
|
||||||
|
|
||||||
def without_source_date_epoch(fxn):
|
def without_source_date_epoch(fxn):
|
||||||
|
@ -217,5 +218,73 @@ class PyCompileTestsWithoutSourceEpoch(PyCompileTestsBase,
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PyCompileCLITestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.directory = tempfile.mkdtemp()
|
||||||
|
self.source_path = os.path.join(self.directory, '_test.py')
|
||||||
|
self.cache_path = importlib.util.cache_from_source(self.source_path)
|
||||||
|
with open(self.source_path, 'w') as file:
|
||||||
|
file.write('x = 123\n')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
support.rmtree(self.directory)
|
||||||
|
|
||||||
|
def pycompilecmd(self, *args, **kwargs):
|
||||||
|
# assert_python_* helpers don't return proc object. We'll just use
|
||||||
|
# subprocess.run() instead of spawn_python() and its friends to test
|
||||||
|
# stdin support of the CLI.
|
||||||
|
if args and args[0] == '-' and 'input' in kwargs:
|
||||||
|
return subprocess.run([sys.executable, '-m', 'py_compile', '-'],
|
||||||
|
input=kwargs['input'].encode(),
|
||||||
|
capture_output=True)
|
||||||
|
return script_helper.assert_python_ok('-m', 'py_compile', *args, **kwargs)
|
||||||
|
|
||||||
|
def pycompilecmd_failure(self, *args):
|
||||||
|
return script_helper.assert_python_failure('-m', 'py_compile', *args)
|
||||||
|
|
||||||
|
def test_stdin(self):
|
||||||
|
result = self.pycompilecmd('-', input=self.source_path)
|
||||||
|
self.assertEqual(result.returncode, 0)
|
||||||
|
self.assertEqual(result.stdout, b'')
|
||||||
|
self.assertEqual(result.stderr, b'')
|
||||||
|
self.assertTrue(os.path.exists(self.cache_path))
|
||||||
|
|
||||||
|
def test_with_files(self):
|
||||||
|
rc, stdout, stderr = self.pycompilecmd(self.source_path, self.source_path)
|
||||||
|
self.assertEqual(rc, 0)
|
||||||
|
self.assertEqual(stdout, b'')
|
||||||
|
self.assertEqual(stderr, b'')
|
||||||
|
self.assertTrue(os.path.exists(self.cache_path))
|
||||||
|
|
||||||
|
def test_bad_syntax(self):
|
||||||
|
bad_syntax = os.path.join(os.path.dirname(__file__), 'badsyntax_3131.py')
|
||||||
|
rc, stdout, stderr = self.pycompilecmd_failure(bad_syntax)
|
||||||
|
self.assertEqual(rc, 1)
|
||||||
|
self.assertEqual(stdout, b'')
|
||||||
|
self.assertIn(b'SyntaxError', stderr)
|
||||||
|
|
||||||
|
def test_bad_syntax_with_quiet(self):
|
||||||
|
bad_syntax = os.path.join(os.path.dirname(__file__), 'badsyntax_3131.py')
|
||||||
|
rc, stdout, stderr = self.pycompilecmd_failure('-q', bad_syntax)
|
||||||
|
self.assertEqual(rc, 1)
|
||||||
|
self.assertEqual(stdout, b'')
|
||||||
|
self.assertEqual(stderr, b'')
|
||||||
|
|
||||||
|
def test_file_not_exists(self):
|
||||||
|
should_not_exists = os.path.join(os.path.dirname(__file__), 'should_not_exists.py')
|
||||||
|
rc, stdout, stderr = self.pycompilecmd_failure(self.source_path, should_not_exists)
|
||||||
|
self.assertEqual(rc, 1)
|
||||||
|
self.assertEqual(stdout, b'')
|
||||||
|
self.assertIn(b'No such file or directory', stderr)
|
||||||
|
|
||||||
|
def test_file_not_exists_with_quiet(self):
|
||||||
|
should_not_exists = os.path.join(os.path.dirname(__file__), 'should_not_exists.py')
|
||||||
|
rc, stdout, stderr = self.pycompilecmd_failure('-q', self.source_path, should_not_exists)
|
||||||
|
self.assertEqual(rc, 1)
|
||||||
|
self.assertEqual(stdout, b'')
|
||||||
|
self.assertEqual(stderr, b'')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -1565,6 +1565,7 @@ Justin Sheehy
|
||||||
Akash Shende
|
Akash Shende
|
||||||
Charlie Shepherd
|
Charlie Shepherd
|
||||||
Bruce Sherwood
|
Bruce Sherwood
|
||||||
|
Gregory Shevchenko
|
||||||
Alexander Shigin
|
Alexander Shigin
|
||||||
Pete Shinners
|
Pete Shinners
|
||||||
Michael Shiplett
|
Michael Shiplett
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Add ``--quiet`` option to command-line interface of :mod:`py_compile`.
|
||||||
|
Patch by Gregory Schevchenko.
|
Loading…
Reference in New Issue