| --- a/Lib/packaging/tests/support.py |
| +++ b/Lib/packaging/tests/support.py |
| @@ -38,7 +38,9 @@ import shutil |
| import logging |
| import weakref |
| import tempfile |
| +import textwrap |
| import sysconfig |
| +from subprocess import Popen, PIPE |
| from packaging.dist import Distribution |
| from packaging.util import resolve_name |
| @@ -56,6 +58,8 @@ __all__ = [ |
| # misc. functions and decorators |
| 'fake_dec', 'create_distribution', 'use_command', |
| 'copy_xxmodule_c', 'fixup_build_ext', |
| + # functions used in byte-compilation tests |
| + 'create_py_module', 'check_pyc_file', 'check_pyo_file', |
| # imported from this module for backport purposes |
| 'unittest', 'requires_zlib', 'skip_2to3_optimize', 'skip_unless_symlink', |
| ] |
| @@ -381,6 +385,88 @@ def fixup_build_ext(cmd): |
| cmd.library_dirs = value.split(os.pathsep) |
| +def create_py_module(filename): |
| + """Create a Python module suitable for some tests. |
| + |
| + *filename* is a string containing the filename to write to. |
| + This function should be used with check_pyc_file and check_pyo_file, |
| + see test_command_build_py.py for an example. |
| + """ |
| + # The documentation of -O mode is quite brief; experimentation + source |
| + # code reading (Py_OptimizeFlag then c_optimize in Python/compile.c) |
| + # find these optimizations: -O sets __debug__ to False and disables |
| + # asserts, -OO also sets __doc__ attributes to None. The following code |
| + # exercises all of these things. |
| + with open(filename, 'w') as fp: |
| + fp.write(textwrap.dedent('''\ |
| + """Module docstring.""" |
| + |
| + print('debug:', __debug__) |
| + |
| + try: |
| + assert False |
| + except AssertionError: |
| + print('assertion: failed as expected') |
| + else: |
| + print('assertion: disabled') |
| + |
| + print('docstring:', __doc__) |
| + ''')) |
| + |
| + |
| +def check_pyc_file(testcase, modname, basedir): |
| + """Make sure that a pyc file is compiled with optimization off. |
| + |
| + *testcase* should be a unittest.TestCase instance. *modname* is the |
| + name of a module for which there exists a .pyc file created by |
| + byte-compiling a module written by create_py_module. *basedir* is |
| + the parent directory of the .py file. |
| + """ |
| + # using a subprocess to avoid module caching issues and to be independent |
| + # of the calling Python's -O option -> we can call check_pyc_file and |
| + # check_pyo_file in a row, from a Python started with or without -O |
| + with Popen([sys.executable, '-E', '-m', modname], cwd=basedir, |
| + stdout=PIPE, stderr=PIPE) as process: |
| + output = process.stdout.read() |
| + |
| + output = output.decode('ascii').splitlines() |
| + testcase.assertEqual(process.returncode, 0) |
| + testcase.assertEqual(output, ['debug: True', |
| + 'assertion: failed as expected', |
| + 'docstring: Module docstring.']) |
| + |
| + |
| +def check_pyo_file(testcase, modname, basedir, level): |
| + """Make sure that a pyo file is compiled with the right optimizations. |
| + |
| + *level* should be 1 or 2 (matching python -O or -OO). See |
| + check_pyc_file for the other arguments. |
| + """ |
| + if level == 1: |
| + flag = '-O' |
| + docstring = 'docstring: Module docstring.' |
| + elif level == 2: |
| + flag = '-OO' |
| + docstring = 'docstring: None' |
| + else: |
| + raise ValueError('level must be 1 or 2, not %r' % level) |
| + |
| + # an existing .pyc file is not considered for import, but if there is a |
| + # .pyo file created with -O, a call with -OO will not recreate it, so |
| + # pay attention to byte-compilation when writing tests (i.e. use different |
| + # methods or module names to test code with different optimization levels) |
| + |
| + with Popen([sys.executable, '-E', flag, '-m', modname], cwd=basedir, |
| + stdout=PIPE, stderr=PIPE) as process: |
| + output = process.stdout.read() |
| + |
| + output = output.decode('ascii').splitlines() |
| + testcase.assertEqual(process.returncode, 0) |
| + testcase.assertEqual(output, ['debug: False', |
| + 'assertion: disabled', |
| + docstring]) |
| + |
| + |
| try: |
| from test.support import skip_unless_symlink |
| except ImportError: |