Skip to content

Commit 07be72d

Browse files
CPython Developersyouknowone
CPython Developers
authored andcommitted
Update py_compile from CPython 3.10.6
1 parent adbed02 commit 07be72d

File tree

3 files changed

+120
-45
lines changed

3 files changed

+120
-45
lines changed

Lib/py_compile.py

+43-43
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def _get_default_invalidation_mode():
7777

7878

7979
def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,
80-
invalidation_mode=None):
80+
invalidation_mode=None, quiet=0):
8181
"""Byte-compile one Python source file to Python bytecode.
8282
8383
:param file: The source file name.
@@ -95,6 +95,8 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,
9595
are -1, 0, 1 and 2. A value of -1 means to use the optimization
9696
level of the current interpreter, as given by -O command line options.
9797
:param invalidation_mode:
98+
:param quiet: Return full output with False or 0, errors only with 1,
99+
and no output with 2.
98100
99101
:return: Path to the resulting byte compiled file.
100102
@@ -143,11 +145,12 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,
143145
_optimize=optimize)
144146
except Exception as err:
145147
py_exc = PyCompileError(err.__class__, err, dfile or file)
146-
if doraise:
147-
raise py_exc
148-
else:
149-
sys.stderr.write(py_exc.msg + '\n')
150-
return
148+
if quiet < 2:
149+
if doraise:
150+
raise py_exc
151+
else:
152+
sys.stderr.write(py_exc.msg + '\n')
153+
return
151154
try:
152155
dirname = os.path.dirname(cfile)
153156
if dirname:
@@ -170,43 +173,40 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,
170173
return cfile
171174

172175

173-
def main(args=None):
174-
"""Compile several source files.
175-
176-
The files named in 'args' (or on the command line, if 'args' is
177-
not specified) are compiled and the resulting bytecode is cached
178-
in the normal manner. This function does not search a directory
179-
structure to locate source files; it only compiles files named
180-
explicitly. If '-' is the only parameter in args, the list of
181-
files is taken from standard input.
182-
183-
"""
184-
if args is None:
185-
args = sys.argv[1:]
186-
rv = 0
187-
if args == ['-']:
188-
while True:
189-
filename = sys.stdin.readline()
190-
if not filename:
191-
break
192-
filename = filename.rstrip('\n')
193-
try:
194-
compile(filename, doraise=True)
195-
except PyCompileError as error:
196-
rv = 1
197-
sys.stderr.write("%s\n" % error.msg)
198-
except OSError as error:
199-
rv = 1
200-
sys.stderr.write("%s\n" % error)
176+
def main():
177+
import argparse
178+
179+
description = 'A simple command-line interface for py_compile module.'
180+
parser = argparse.ArgumentParser(description=description)
181+
parser.add_argument(
182+
'-q', '--quiet',
183+
action='store_true',
184+
help='Suppress error output',
185+
)
186+
parser.add_argument(
187+
'filenames',
188+
nargs='+',
189+
help='Files to compile',
190+
)
191+
args = parser.parse_args()
192+
if args.filenames == ['-']:
193+
filenames = [filename.rstrip('\n') for filename in sys.stdin.readlines()]
201194
else:
202-
for filename in args:
203-
try:
204-
compile(filename, doraise=True)
205-
except PyCompileError as error:
206-
# return value to indicate at least one failure
207-
rv = 1
208-
sys.stderr.write("%s\n" % error.msg)
209-
return rv
195+
filenames = args.filenames
196+
for filename in filenames:
197+
try:
198+
compile(filename, doraise=True)
199+
except PyCompileError as error:
200+
if args.quiet:
201+
parser.exit(1)
202+
else:
203+
parser.exit(1, error.msg)
204+
except OSError as error:
205+
if args.quiet:
206+
parser.exit(1)
207+
else:
208+
parser.exit(1, str(error))
209+
210210

211211
if __name__ == "__main__":
212-
sys.exit(main())
212+
main()

Lib/test/badsyntax_3131.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# -*- coding: utf-8 -*-
2+
= 2

Lib/test/test_py_compile.py

+75-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
import py_compile
55
import shutil
66
import stat
7+
import subprocess
78
import sys
89
import tempfile
910
import unittest
1011

1112
from test import support
12-
from test.support import os_helper
13+
from test.support import os_helper, script_helper
1314

1415

1516
def without_source_date_epoch(fxn):
@@ -52,7 +53,7 @@ def __new__(mcls, name, bases, dct, *, source_date_epoch):
5253
class PyCompileTestsBase:
5354

5455
def setUp(self):
55-
self.directory = tempfile.mkdtemp()
56+
self.directory = tempfile.mkdtemp(dir=os.getcwd())
5657
self.source_path = os.path.join(self.directory, '_test.py')
5758
self.pyc_path = self.source_path + 'c'
5859
self.cache_path = importlib.util.cache_from_source(self.source_path)
@@ -255,5 +256,77 @@ class PyCompileTestsWithoutSourceEpoch(PyCompileTestsBase,
255256
pass
256257

257258

259+
class PyCompileCLITestCase(unittest.TestCase):
260+
261+
def setUp(self):
262+
self.directory = tempfile.mkdtemp()
263+
self.source_path = os.path.join(self.directory, '_test.py')
264+
self.cache_path = importlib.util.cache_from_source(self.source_path)
265+
with open(self.source_path, 'w') as file:
266+
file.write('x = 123\n')
267+
268+
def tearDown(self):
269+
os_helper.rmtree(self.directory)
270+
271+
def pycompilecmd(self, *args, **kwargs):
272+
# assert_python_* helpers don't return proc object. We'll just use
273+
# subprocess.run() instead of spawn_python() and its friends to test
274+
# stdin support of the CLI.
275+
if args and args[0] == '-' and 'input' in kwargs:
276+
return subprocess.run([sys.executable, '-m', 'py_compile', '-'],
277+
input=kwargs['input'].encode(),
278+
capture_output=True)
279+
return script_helper.assert_python_ok('-m', 'py_compile', *args, **kwargs)
280+
281+
def pycompilecmd_failure(self, *args):
282+
return script_helper.assert_python_failure('-m', 'py_compile', *args)
283+
284+
def test_stdin(self):
285+
result = self.pycompilecmd('-', input=self.source_path)
286+
self.assertEqual(result.returncode, 0)
287+
self.assertEqual(result.stdout, b'')
288+
self.assertEqual(result.stderr, b'')
289+
self.assertTrue(os.path.exists(self.cache_path))
290+
291+
def test_with_files(self):
292+
rc, stdout, stderr = self.pycompilecmd(self.source_path, self.source_path)
293+
self.assertEqual(rc, 0)
294+
self.assertEqual(stdout, b'')
295+
self.assertEqual(stderr, b'')
296+
self.assertTrue(os.path.exists(self.cache_path))
297+
298+
def test_bad_syntax(self):
299+
bad_syntax = os.path.join(os.path.dirname(__file__), 'badsyntax_3131.py')
300+
rc, stdout, stderr = self.pycompilecmd_failure(bad_syntax)
301+
self.assertEqual(rc, 1)
302+
self.assertEqual(stdout, b'')
303+
self.assertIn(b'SyntaxError', stderr)
304+
305+
def test_bad_syntax_with_quiet(self):
306+
bad_syntax = os.path.join(os.path.dirname(__file__), 'badsyntax_3131.py')
307+
rc, stdout, stderr = self.pycompilecmd_failure('-q', bad_syntax)
308+
self.assertEqual(rc, 1)
309+
self.assertEqual(stdout, b'')
310+
self.assertEqual(stderr, b'')
311+
312+
def test_file_not_exists(self):
313+
should_not_exists = os.path.join(os.path.dirname(__file__), 'should_not_exists.py')
314+
rc, stdout, stderr = self.pycompilecmd_failure(self.source_path, should_not_exists)
315+
self.assertEqual(rc, 1)
316+
self.assertEqual(stdout, b'')
317+
self.assertIn(b'no such file or directory', stderr.lower())
318+
319+
# TODO: RUSTPYTHON
320+
if sys.platform == "win32":
321+
test_file_not_exists = unittest.expectedFailure(test_file_not_exists)
322+
323+
def test_file_not_exists_with_quiet(self):
324+
should_not_exists = os.path.join(os.path.dirname(__file__), 'should_not_exists.py')
325+
rc, stdout, stderr = self.pycompilecmd_failure('-q', self.source_path, should_not_exists)
326+
self.assertEqual(rc, 1)
327+
self.assertEqual(stdout, b'')
328+
self.assertEqual(stderr, b'')
329+
330+
258331
if __name__ == "__main__":
259332
unittest.main()

0 commit comments

Comments
 (0)