bpo-38731: Add --quiet option to py_compile CLI (GH-17134)

This commit is contained in:
Gregory Schevchenko 2020-07-25 22:58:45 +03:00 committed by GitHub
parent af08db7bac
commit daff39070e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 136 additions and 52 deletions

View File

@ -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.
.. versionchanged:: 3.2 .. program:: python -m py_compile
Added support for ``'-'``.
When this module is run as a script, the :func:`main` is used to compile all the .. cmdoption:: <file> ... <fileN>
files named on the command line. The exit status is nonzero if one of the files -
could not be compiled.
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
Added support for ``-``.
.. versionchanged:: 3.10
Added support for :option:`-q`.
.. seealso:: .. seealso::

View File

@ -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
--- ---

View File

@ -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
try: for filename in filenames:
compile(filename, doraise=True) try:
except PyCompileError as error: compile(filename, doraise=True)
# return value to indicate at least one failure except PyCompileError as error:
rv = 1 if args.quiet:
if quiet < 2: parser.exit(1)
sys.stderr.write("%s\n" % error.msg) else:
return rv parser.exit(1, error.msg)
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()

View File

@ -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()

View File

@ -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

View File

@ -0,0 +1,2 @@
Add ``--quiet`` option to command-line interface of :mod:`py_compile`.
Patch by Gregory Schevchenko.