Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
241a633
bpo-38731: add missing quiet variable in py_compile.main
Nov 12, 2019
5c4b7dd
📜🤖 Added by blurb_it.
blurb-it[bot] Nov 13, 2019
94ee0c7
bpo-38731: remove undefined `quiet` variable from `py_compile.main`
Nov 13, 2019
6a7c446
bpo-38731: fix NEWS entry
Nov 14, 2019
4466105
Update Misc/NEWS.d/next/Library/2019-11-13-07-37-11.bpo-38731.9qmcSx.rst
gvsheva Nov 16, 2019
4e14f87
bpo-38731: fix traceback on file not exists
Nov 21, 2019
86b1107
bpo-38731: add test cases
Nov 21, 2019
538aa30
add missed '-q/--quiet' flag in `py_compile.main`
Nov 22, 2019
2e2c204
bpo-38731: fix docs
Nov 26, 2019
f88e6e8
bpo-38731: fix docs
Dec 3, 2019
f895b86
bpo-38731: use print in py_compile.main
Dec 3, 2019
799c35f
improve news
merwok Dec 3, 2019
2ac7651
small doc polish
merwok Dec 3, 2019
05dcd91
bpo-38731: yet a few fixes
Dec 3, 2019
885edae
Merge branch 'master' into fix-issue-38731
merwok Dec 19, 2019
6eccb1f
damned github editor
merwok Dec 19, 2019
69e141c
sync with upstream
gvsheva Jan 2, 2020
edf619c
bpo-38731: yet a few fixes
Jan 2, 2020
90ca99d
Merge branch 'master' into fix-issue-38731
Jul 15, 2020
afeaf1f
bpo-38731: drop description
Jul 15, 2020
51f05df
Tweaks before merge
berkerpeksag Jul 25, 2020
6df8c07
debug stdin test on windows
berkerpeksag Jul 25, 2020
ae5752e
avoid BytesWarning
berkerpeksag Jul 25, 2020
8235543
rework cli tests a bit
berkerpeksag Jul 25, 2020
400a4e2
Merge remote-tracking branch 'upstream/master' into pr/17134
berkerpeksag Jul 25, 2020
024f402
revert debug output and add more tweaks
berkerpeksag Jul 25, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions Doc/library/py_compile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,21 +125,33 @@ byte-code cache files in the directory containing the source code.
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
line, if *args* is ``None``) are compiled and the resulting byte-code is
cached in the normal manner. This function does not search a directory
structure to locate source files; it only compiles files named explicitly.
If ``'-'`` is the only parameter in args, the list of files is taken from
standard input.
Comment thread
gvsheva marked this conversation as resolved.
This module can be invoked as a script to compile several source
files. The files named in *filenames* are compiled and the resulting
bytecode is cached in the normal manner. This program does not search
a directory structure to locate source files; it only compiles files
named explicitly. The exit status is nonzero if one of the files could
not be compiled.

.. versionchanged:: 3.2
Added support for ``'-'``.
Comment thread
gvsheva marked this conversation as resolved.
.. 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
Added support for ``-``.

When this module is run as a script, the :func:`main` is used to compile all the
files named on the command line. The exit status is nonzero if one of the files
could not be compiled.
.. versionchanged:: 3.10
Added support for :option:`-q`.


.. seealso::
Expand Down
6 changes: 6 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
(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
---

Expand Down
74 changes: 34 additions & 40 deletions Lib/py_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,46 +173,40 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,
return cfile


def main(args=None):
"""Compile several source files.

The files named in 'args' (or on the command line, if 'args' is
not specified) are compiled and the resulting bytecode is cached
in the normal manner. This function does not search a directory
structure to locate source files; it only compiles files named
explicitly. If '-' is the only parameter in args, the list of
files is taken from standard input.

"""
if args is None:
args = sys.argv[1:]
rv = 0
if args == ['-']:
while True:
filename = sys.stdin.readline()
if not filename:
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)
def main():
import argparse

description = 'A simple command-line interface for py_compile module.'
parser = argparse.ArgumentParser(description=description)
parser.add_argument(
'-q', '--quiet',
action='store_true',
help='Suppress error output',
)
parser.add_argument(
'filenames',
nargs='+',
help='Files to compile',
)
args = parser.parse_args()
if args.filenames == ['-']:
filenames = sys.stdin.readlines()
else:
for filename in args:
try:
compile(filename, doraise=True)
except PyCompileError as error:
# return value to indicate at least one failure
rv = 1
if quiet < 2:
sys.stderr.write("%s\n" % error.msg)
return rv
filenames = args.filenames
for filename in filenames:
try:
compile(filename, doraise=True)
except PyCompileError as error:
if args.quiet:
parser.exit(1)
else:
parser.exit(1, error.msg)
except OSError as error:
if args.quiet:
parser.exit(1)
else:
parser.exit(1, str(error))


if __name__ == "__main__":
sys.exit(main())
main()
71 changes: 70 additions & 1 deletion Lib/test/test_py_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
import py_compile
import shutil
import stat
import subprocess
import sys
import tempfile
import unittest

from test import support
from test.support import os_helper
from test.support import os_helper, script_helper


def without_source_date_epoch(fxn):
Expand Down Expand Up @@ -217,5 +218,73 @@ class PyCompileTestsWithoutSourceEpoch(PyCompileTestsBase,
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__":
unittest.main()
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1565,6 +1565,7 @@ Justin Sheehy
Akash Shende
Charlie Shepherd
Bruce Sherwood
Gregory Shevchenko
Alexander Shigin
Pete Shinners
Michael Shiplett
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add ``--quiet`` option to command-line interface of :mod:`py_compile`.
Patch by Gregory Schevchenko.