diff options
author | Brett Cannon <brett@python.org> | 2015-04-13 18:21:02 (GMT) |
---|---|---|
committer | Brett Cannon <brett@python.org> | 2015-04-13 18:21:02 (GMT) |
commit | f299abdafa0f2b6eb7abae274861b19b361c96bc (patch) | |
tree | afc3a2bf560e30c7725510eda3b57d71ceddba00 /Lib | |
parent | a63cc212348e276c8ede32773313c60ff7fda651 (diff) | |
download | cpython-f299abdafa0f2b6eb7abae274861b19b361c96bc.zip cpython-f299abdafa0f2b6eb7abae274861b19b361c96bc.tar.gz cpython-f299abdafa0f2b6eb7abae274861b19b361c96bc.tar.bz2 |
Issue #23731: Implement PEP 488.
The concept of .pyo files no longer exists. Now .pyc files have an
optional `opt-` tag which specifies if any extra optimizations beyond
the peepholer were applied.
Diffstat (limited to 'Lib')
32 files changed, 288 insertions, 297 deletions
diff --git a/Lib/compileall.py b/Lib/compileall.py index 4f46920..aeaaf8e 100644 --- a/Lib/compileall.py +++ b/Lib/compileall.py @@ -1,4 +1,4 @@ -"""Module/script to byte-compile all .py files to .pyc (or .pyo) files. +"""Module/script to byte-compile all .py files to .pyc files. When called as a script with arguments, this compiles the directories given as arguments recursively; the -l option prevents it from @@ -118,11 +118,12 @@ def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, return success if os.path.isfile(fullname): if legacy: - cfile = fullname + ('c' if __debug__ else 'o') + cfile = fullname + 'c' else: if optimize >= 0: + opt = optimize if optimize >= 1 else '' cfile = importlib.util.cache_from_source( - fullname, debug_override=not optimize) + fullname, optimization=opt) else: cfile = importlib.util.cache_from_source(fullname) cache_dir = os.path.dirname(cfile) diff --git a/Lib/distutils/command/build_py.py b/Lib/distutils/command/build_py.py index 9100b96..cf0ca57 100644 --- a/Lib/distutils/command/build_py.py +++ b/Lib/distutils/command/build_py.py @@ -314,10 +314,10 @@ class build_py (Command): if include_bytecode: if self.compile: outputs.append(importlib.util.cache_from_source( - filename, debug_override=True)) + filename, optimization='')) if self.optimize > 0: outputs.append(importlib.util.cache_from_source( - filename, debug_override=False)) + filename, optimization=self.optimize)) outputs += [ os.path.join(build_dir, filename) diff --git a/Lib/distutils/command/install_lib.py b/Lib/distutils/command/install_lib.py index 215813b..6154cf0 100644 --- a/Lib/distutils/command/install_lib.py +++ b/Lib/distutils/command/install_lib.py @@ -22,15 +22,15 @@ class install_lib(Command): # possible scenarios: # 1) no compilation at all (--no-compile --no-optimize) # 2) compile .pyc only (--compile --no-optimize; default) - # 3) compile .pyc and "level 1" .pyo (--compile --optimize) - # 4) compile "level 1" .pyo only (--no-compile --optimize) - # 5) compile .pyc and "level 2" .pyo (--compile --optimize-more) - # 6) compile "level 2" .pyo only (--no-compile --optimize-more) + # 3) compile .pyc and "opt-1" .pyc (--compile --optimize) + # 4) compile "opt-1" .pyc only (--no-compile --optimize) + # 5) compile .pyc and "opt-2" .pyc (--compile --optimize-more) + # 6) compile "opt-2" .pyc only (--no-compile --optimize-more) # - # The UI for this is two option, 'compile' and 'optimize'. + # The UI for this is two options, 'compile' and 'optimize'. # 'compile' is strictly boolean, and only decides whether to # generate .pyc files. 'optimize' is three-way (0, 1, or 2), and - # decides both whether to generate .pyo files and what level of + # decides both whether to generate .pyc files and what level of # optimization to use. user_options = [ @@ -166,10 +166,10 @@ class install_lib(Command): continue if self.compile: bytecode_files.append(importlib.util.cache_from_source( - py_file, debug_override=True)) + py_file, optimization='')) if self.optimize > 0: bytecode_files.append(importlib.util.cache_from_source( - py_file, debug_override=False)) + py_file, optimization=self.optimize)) return bytecode_files diff --git a/Lib/distutils/tests/test_build_py.py b/Lib/distutils/tests/test_build_py.py index c8f6b89..18283dc 100644 --- a/Lib/distutils/tests/test_build_py.py +++ b/Lib/distutils/tests/test_build_py.py @@ -120,8 +120,8 @@ class BuildPyTestCase(support.TempdirManager, found = os.listdir(cmd.build_lib) self.assertEqual(sorted(found), ['__pycache__', 'boiledeggs.py']) found = os.listdir(os.path.join(cmd.build_lib, '__pycache__')) - self.assertEqual(sorted(found), - ['boiledeggs.%s.pyo' % sys.implementation.cache_tag]) + expect = 'boiledeggs.{}.opt-1.pyc'.format(sys.implementation.cache_tag) + self.assertEqual(sorted(found), [expect]) def test_dir_in_package_data(self): """ diff --git a/Lib/distutils/tests/test_install_lib.py b/Lib/distutils/tests/test_install_lib.py index 40dd1a9..5378aa8 100644 --- a/Lib/distutils/tests/test_install_lib.py +++ b/Lib/distutils/tests/test_install_lib.py @@ -44,12 +44,11 @@ class InstallLibTestCase(support.TempdirManager, f = os.path.join(project_dir, 'foo.py') self.write_file(f, '# python file') cmd.byte_compile([f]) - pyc_file = importlib.util.cache_from_source('foo.py', - debug_override=True) - pyo_file = importlib.util.cache_from_source('foo.py', - debug_override=False) + pyc_file = importlib.util.cache_from_source('foo.py', optimization='') + pyc_opt_file = importlib.util.cache_from_source('foo.py', + optimization=cmd.optimize) self.assertTrue(os.path.exists(pyc_file)) - self.assertTrue(os.path.exists(pyo_file)) + self.assertTrue(os.path.exists(pyc_opt_file)) def test_get_outputs(self): project_dir, dist = self.create_dist() @@ -66,8 +65,8 @@ class InstallLibTestCase(support.TempdirManager, cmd.distribution.packages = ['spam'] cmd.distribution.script_name = 'setup.py' - # get_outputs should return 4 elements: spam/__init__.py, .pyc and - # .pyo, foo.import-tag-abiflags.so / foo.pyd + # get_outputs should return 4 elements: spam/__init__.py and .pyc, + # foo.import-tag-abiflags.so / foo.pyd outputs = cmd.get_outputs() self.assertEqual(len(outputs), 4, outputs) diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index 5adcac5..e423325 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -322,11 +322,11 @@ def byte_compile (py_files, prefix=None, base_dir=None, verbose=1, dry_run=0, direct=None): - """Byte-compile a collection of Python source files to either .pyc - or .pyo files in a __pycache__ subdirectory. 'py_files' is a list + """Byte-compile a collection of Python source files to .pyc + files in a __pycache__ subdirectory. 'py_files' is a list of files to compile; any files that don't end in ".py" are silently skipped. 'optimize' must be one of the following: - 0 - don't optimize (generate .pyc) + 0 - don't optimize 1 - normal optimization (like "python -O") 2 - extra optimization (like "python -OO") If 'force' is true, all files are recompiled regardless of @@ -438,8 +438,9 @@ byte_compile(files, optimize=%r, force=%r, # cfile - byte-compiled file # dfile - purported source filename (same as 'file' by default) if optimize >= 0: + opt = '' if optimize == 0 else optimize cfile = importlib.util.cache_from_source( - file, debug_override=not optimize) + file, optimization=opt) else: cfile = importlib.util.cache_from_source(file) dfile = file diff --git a/Lib/doctest.py b/Lib/doctest.py index 7d5bcf4..96ab0c4 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -1051,7 +1051,7 @@ class DocTestFinder: filename = None else: filename = getattr(module, '__file__', module.__name__) - if filename[-4:] in (".pyc", ".pyo"): + if filename[-4:] == ".pyc": filename = filename[:-1] return self._parser.get_doctest(docstring, globs, name, filename, lineno) @@ -2378,7 +2378,7 @@ def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, continue if not test.filename: filename = module.__file__ - if filename[-4:] in (".pyc", ".pyo"): + if filename[-4:] == ".pyc": filename = filename[:-1] test.filename = filename suite.addTest(DocTestCase(test, **options)) @@ -58,24 +58,23 @@ def new_module(name): def get_magic(): """**DEPRECATED** - Return the magic number for .pyc or .pyo files. + Return the magic number for .pyc files. """ return util.MAGIC_NUMBER def get_tag(): - """Return the magic tag for .pyc or .pyo files.""" + """Return the magic tag for .pyc files.""" return sys.implementation.cache_tag def cache_from_source(path, debug_override=None): """**DEPRECATED** - Given the path to a .py file, return the path to its .pyc/.pyo file. + Given the path to a .py file, return the path to its .pyc file. The .py file does not need to exist; this simply returns the path to the - .pyc/.pyo file calculated as if the .py file were imported. The extension - will be .pyc unless sys.flags.optimize is non-zero, then it will be .pyo. + .pyc file calculated as if the .py file were imported. If debug_override is not None, then it must be a boolean and is used in place of sys.flags.optimize. @@ -83,16 +82,18 @@ def cache_from_source(path, debug_override=None): If sys.implementation.cache_tag is None then NotImplementedError is raised. """ - return util.cache_from_source(path, debug_override) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + return util.cache_from_source(path, debug_override) def source_from_cache(path): """**DEPRECATED** - Given the path to a .pyc./.pyo file, return the path to its .py file. + Given the path to a .pyc. file, return the path to its .py file. - The .pyc/.pyo file does not need to exist; this simply returns the path to - the .py file calculated to correspond to the .pyc/.pyo file. If path does + The .pyc file does not need to exist; this simply returns the path to + the .py file calculated to correspond to the .pyc file. If path does not conform to PEP 3147 format, ValueError will be raised. If sys.implementation.cache_tag is None then NotImplementedError is raised. diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 0ed7cc6..c6019ad 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -429,45 +429,64 @@ MAGIC_NUMBER = (3320).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' +_OPT = 'opt-' SOURCE_SUFFIXES = ['.py'] # _setup() adds .pyw as needed. -DEBUG_BYTECODE_SUFFIXES = ['.pyc'] -OPTIMIZED_BYTECODE_SUFFIXES = ['.pyo'] +BYTECODE_SUFFIXES = ['.pyc'] +# Deprecated. +DEBUG_BYTECODE_SUFFIXES = OPTIMIZED_BYTECODE_SUFFIXES = BYTECODE_SUFFIXES -def cache_from_source(path, debug_override=None): - """Given the path to a .py file, return the path to its .pyc/.pyo file. +def cache_from_source(path, debug_override=None, *, optimization=None): + """Given the path to a .py file, return the path to its .pyc file. The .py file does not need to exist; this simply returns the path to the - .pyc/.pyo file calculated as if the .py file were imported. The extension - will be .pyc unless sys.flags.optimize is non-zero, then it will be .pyo. + .pyc file calculated as if the .py file were imported. - If debug_override is not None, then it must be a boolean and is used in - place of sys.flags.optimize. + The 'optimization' parameter controls the presumed optimization level of + the bytecode file. If 'optimization' is not None, the string representation + of the argument is taken and verified to be alphanumeric (else ValueError + is raised). + + The debug_override parameter is deprecated. If debug_override is not None, + a True value is the same as setting 'optimization' to the empty string + while a False value is equivalent to setting 'optimization' to '1'. If sys.implementation.cache_tag is None then NotImplementedError is raised. """ - debug = not sys.flags.optimize if debug_override is None else debug_override - if debug: - suffixes = DEBUG_BYTECODE_SUFFIXES - else: - suffixes = OPTIMIZED_BYTECODE_SUFFIXES + if debug_override is not None: + _warnings.warn('the debug_override parameter is deprecated; use ' + "'optimization' instead", DeprecationWarning) + if optimization is not None: + message = 'debug_override or optimization must be set to None' + raise TypeError(message) + optimization = '' if debug_override else 1 head, tail = _path_split(path) base, sep, rest = tail.rpartition('.') tag = sys.implementation.cache_tag if tag is None: raise NotImplementedError('sys.implementation.cache_tag is None') - filename = ''.join([(base if base else rest), sep, tag, suffixes[0]]) - return _path_join(head, _PYCACHE, filename) + almost_filename = ''.join([(base if base else rest), sep, tag]) + if optimization is None: + if sys.flags.optimize == 0: + optimization = '' + else: + optimization = sys.flags.optimize + optimization = str(optimization) + if optimization != '': + if not optimization.isalnum(): + raise ValueError('{!r} is not alphanumeric'.format(optimization)) + almost_filename = '{}.{}{}'.format(almost_filename, _OPT, optimization) + return _path_join(head, _PYCACHE, almost_filename + BYTECODE_SUFFIXES[0]) def source_from_cache(path): - """Given the path to a .pyc./.pyo file, return the path to its .py file. + """Given the path to a .pyc. file, return the path to its .py file. - The .pyc/.pyo file does not need to exist; this simply returns the path to - the .py file calculated to correspond to the .pyc/.pyo file. If path does - not conform to PEP 3147 format, ValueError will be raised. If + The .pyc file does not need to exist; this simply returns the path to + the .py file calculated to correspond to the .pyc file. If path does + not conform to PEP 3147/488 format, ValueError will be raised. If sys.implementation.cache_tag is None then NotImplementedError is raised. """ @@ -478,9 +497,19 @@ def source_from_cache(path): if pycache != _PYCACHE: raise ValueError('{} not bottom-level directory in ' '{!r}'.format(_PYCACHE, path)) - if pycache_filename.count('.') != 2: - raise ValueError('expected only 2 dots in ' + dot_count = pycache_filename.count('.') + if dot_count not in {2, 3}: + raise ValueError('expected only 2 or 3 dots in ' '{!r}'.format(pycache_filename)) + elif dot_count == 3: + optimization = pycache_filename.rsplit('.', 2)[-2] + if not optimization.startswith(_OPT): + raise ValueError("optimization portion of filename does not start " + "with {!r}".format(_OPT)) + opt_level = optimization[len(_OPT):] + if not opt_level.isalnum(): + raise ValueError("optimization level {!r} is not an alphanumeric " + "value".format(optimization)) base_filename = pycache_filename.partition('.')[0] return _path_join(head, base_filename + SOURCE_SUFFIXES[0]) @@ -2337,15 +2366,10 @@ def _setup(sys_module, _imp_module): modules, those two modules must be explicitly passed in. """ - global _imp, sys, BYTECODE_SUFFIXES + global _imp, sys _imp = _imp_module sys = sys_module - if sys.flags.optimize: - BYTECODE_SUFFIXES = OPTIMIZED_BYTECODE_SUFFIXES - else: - BYTECODE_SUFFIXES = DEBUG_BYTECODE_SUFFIXES - # Set up the spec for existing builtin/frozen modules. module_type = type(sys) for name, module in sys.modules.items(): diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py index b778e60..5d2c06d 100644 --- a/Lib/modulefinder.py +++ b/Lib/modulefinder.py @@ -223,7 +223,7 @@ class ModuleFinder: if not m.__path__: return modules = {} - # 'suffixes' used to be a list hardcoded to [".py", ".pyc", ".pyo"]. + # 'suffixes' used to be a list hardcoded to [".py", ".pyc"]. # But we must also collect Python extension modules - although # we cannot separate normal dlls from Python extensions. suffixes = [] diff --git a/Lib/msilib/__init__.py b/Lib/msilib/__init__.py index d29a593..873560d 100644 --- a/Lib/msilib/__init__.py +++ b/Lib/msilib/__init__.py @@ -361,7 +361,7 @@ class Directory: # [(logical, 0, filehash.IntegerData(1), # filehash.IntegerData(2), filehash.IntegerData(3), # filehash.IntegerData(4))]) - # Automatically remove .pyc/.pyo files on uninstall (2) + # Automatically remove .pyc files on uninstall (2) # XXX: adding so many RemoveFile entries makes installer unbelievably # slow. So instead, we have to use wildcard remove entries if file.endswith(".py"): @@ -382,10 +382,9 @@ class Directory: return files def remove_pyc(self): - "Remove .pyc/.pyo files on uninstall" + "Remove .pyc files on uninstall" add_data(self.db, "RemoveFile", - [(self.component+"c", self.component, "*.pyc", self.logical, 2), - (self.component+"o", self.component, "*.pyo", self.logical, 2)]) + [(self.component+"c", self.component, "*.pyc", self.logical, 2)]) class Binary: def __init__(self, fname): diff --git a/Lib/py_compile.py b/Lib/py_compile.py index 1277b93..166c488 100644 --- a/Lib/py_compile.py +++ b/Lib/py_compile.py @@ -1,4 +1,4 @@ -"""Routine to "compile" a .py file to a .pyc (or .pyo) file. +"""Routine to "compile" a .py file to a .pyc file. This module has intimate knowledge of the format of .pyc files. """ @@ -67,7 +67,7 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1): :param file: The source file name. :param cfile: The target byte compiled file name. When not given, this - defaults to the PEP 3147 location. + defaults to the PEP 3147/PEP 488 location. :param dfile: Purported file name, i.e. the file name that shows up in error messages. Defaults to the source file name. :param doraise: Flag indicating whether or not an exception should be @@ -85,12 +85,12 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1): Note that it isn't necessary to byte-compile Python modules for execution efficiency -- Python itself byte-compiles a module when it is loaded, and if it can, writes out the bytecode to the - corresponding .pyc (or .pyo) file. + corresponding .pyc file. However, if a Python installation is shared between users, it is a good idea to byte-compile all modules upon installation, since other users may not be able to write in the source directories, - and thus they won't be able to write the .pyc/.pyo file, and then + and thus they won't be able to write the .pyc file, and then they would be byte-compiling every module each time it is loaded. This can slow down program start-up considerably. @@ -105,8 +105,9 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1): """ if cfile is None: if optimize >= 0: + optimization = optimize if optimize >= 1 else '' cfile = importlib.util.cache_from_source(file, - debug_override=not optimize) + optimization=optimization) else: cfile = importlib.util.cache_from_source(file) if os.path.islink(cfile): diff --git a/Lib/pydoc.py b/Lib/pydoc.py index d77ed00..264e407 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -213,7 +213,7 @@ def classify_class_attrs(object): def ispackage(path): """Guess whether a path refers to a package directory.""" if os.path.isdir(path): - for ext in ('.py', '.pyc', '.pyo'): + for ext in ('.py', '.pyc'): if os.path.isfile(os.path.join(path, '__init__' + ext)): return True return False diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 0495121..1d0f11f 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -376,36 +376,32 @@ def rmtree(path): pass def make_legacy_pyc(source): - """Move a PEP 3147 pyc/pyo file to its legacy pyc/pyo location. - - The choice of .pyc or .pyo extension is done based on the __debug__ flag - value. + """Move a PEP 3147/488 pyc file to its legacy pyc location. :param source: The file system path to the source file. The source file - does not need to exist, however the PEP 3147 pyc file must exist. + does not need to exist, however the PEP 3147/488 pyc file must exist. :return: The file system path to the legacy pyc file. """ pyc_file = importlib.util.cache_from_source(source) up_one = os.path.dirname(os.path.abspath(source)) - legacy_pyc = os.path.join(up_one, source + ('c' if __debug__ else 'o')) + legacy_pyc = os.path.join(up_one, source + 'c') os.rename(pyc_file, legacy_pyc) return legacy_pyc def forget(modname): """'Forget' a module was ever imported. - This removes the module from sys.modules and deletes any PEP 3147 or - legacy .pyc and .pyo files. + This removes the module from sys.modules and deletes any PEP 3147/488 or + legacy .pyc files. """ unload(modname) for dirname in sys.path: source = os.path.join(dirname, modname + '.py') # It doesn't matter if they exist or not, unlink all possible - # combinations of PEP 3147 and legacy pyc and pyo files. + # combinations of PEP 3147/488 and legacy pyc files. unlink(source + 'c') - unlink(source + 'o') - unlink(importlib.util.cache_from_source(source, debug_override=True)) - unlink(importlib.util.cache_from_source(source, debug_override=False)) + for opt in ('', 1, 2): + unlink(importlib.util.cache_from_source(source, optimization=opt)) # Check whether a gui is actually available def _is_gui_available(): diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 6116676..3d33bb5 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -425,7 +425,7 @@ if 1: def test_compile_ast(self): fname = __file__ - if fname.lower().endswith(('pyc', 'pyo')): + if fname.lower().endswith('pyc'): fname = fname[:-1] with open(fname, 'r') as f: fcontents = f.read() diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py index 7506c70..07756f6 100644 --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -101,16 +101,16 @@ class CompileallTests(unittest.TestCase): def test_optimize(self): # make sure compiling with different optimization settings than the # interpreter's creates the correct file names - optimize = 1 if __debug__ else 0 + optimize, opt = (1, 1) if __debug__ else (0, '') compileall.compile_dir(self.directory, quiet=True, optimize=optimize) cached = importlib.util.cache_from_source(self.source_path, - debug_override=not optimize) + optimization=opt) self.assertTrue(os.path.isfile(cached)) cached2 = importlib.util.cache_from_source(self.source_path2, - debug_override=not optimize) + optimization=opt) self.assertTrue(os.path.isfile(cached2)) cached3 = importlib.util.cache_from_source(self.source_path3, - debug_override=not optimize) + optimization=opt) self.assertTrue(os.path.isfile(cached3)) @mock.patch('compileall.ProcessPoolExecutor') @@ -237,11 +237,11 @@ class CommandLineTests(unittest.TestCase): self.assertNotIn(b'Listing ', quiet) # Ensure that the default behavior of compileall's CLI is to create - # PEP 3147 pyc/pyo files. + # PEP 3147/PEP 488 pyc files. for name, ext, switch in [ ('normal', 'pyc', []), - ('optimize', 'pyo', ['-O']), - ('doubleoptimize', 'pyo', ['-OO']), + ('optimize', 'opt-1.pyc', ['-O']), + ('doubleoptimize', 'opt-2.pyc', ['-OO']), ]: def f(self, ext=ext, switch=switch): script_helper.assert_python_ok(*(switch + @@ -258,13 +258,12 @@ class CommandLineTests(unittest.TestCase): def test_legacy_paths(self): # Ensure that with the proper switch, compileall leaves legacy - # pyc/pyo files, and no __pycache__ directory. + # pyc files, and no __pycache__ directory. self.assertRunOK('-b', '-q', self.pkgdir) # Verify the __pycache__ directory contents. self.assertFalse(os.path.exists(self.pkgdir_cachedir)) - opt = 'c' if __debug__ else 'o' - expected = sorted(['__init__.py', '__init__.py' + opt, 'bar.py', - 'bar.py' + opt]) + expected = sorted(['__init__.py', '__init__.pyc', 'bar.py', + 'bar.pyc']) self.assertEqual(sorted(os.listdir(self.pkgdir)), expected) def test_multiple_runs(self): diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py index 80b9ec3..47bf1de 100644 --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -111,7 +111,6 @@ class ImportTests(unittest.TestCase): del sys.path[0] support.unlink(temp_mod_name + '.py') support.unlink(temp_mod_name + '.pyc') - support.unlink(temp_mod_name + '.pyo') def test_issue5604(self): # Test cannot cover imp.load_compiled function. @@ -194,7 +193,7 @@ class ImportTests(unittest.TestCase): self.assertEqual(package.b, 2) finally: del sys.path[0] - for ext in ('.py', '.pyc', '.pyo'): + for ext in ('.py', '.pyc'): support.unlink(temp_mod_name + ext) support.unlink(init_file_name + ext) support.rmtree(test_package_name) @@ -346,56 +345,6 @@ class PEP3147Tests(unittest.TestCase): 'qux.{}.pyc'.format(self.tag)) self.assertEqual(imp.cache_from_source(path, True), expect) - def test_cache_from_source_no_cache_tag(self): - # Non cache tag means NotImplementedError. - with support.swap_attr(sys.implementation, 'cache_tag', None): - with self.assertRaises(NotImplementedError): - imp.cache_from_source('whatever.py') - - def test_cache_from_source_no_dot(self): - # Directory with a dot, filename without dot. - path = os.path.join('foo.bar', 'file') - expect = os.path.join('foo.bar', '__pycache__', - 'file{}.pyc'.format(self.tag)) - self.assertEqual(imp.cache_from_source(path, True), expect) - - def test_cache_from_source_optimized(self): - # Given the path to a .py file, return the path to its PEP 3147 - # defined .pyo file (i.e. under __pycache__). - path = os.path.join('foo', 'bar', 'baz', 'qux.py') - expect = os.path.join('foo', 'bar', 'baz', '__pycache__', - 'qux.{}.pyo'.format(self.tag)) - self.assertEqual(imp.cache_from_source(path, False), expect) - - def test_cache_from_source_cwd(self): - path = 'foo.py' - expect = os.path.join('__pycache__', 'foo.{}.pyc'.format(self.tag)) - self.assertEqual(imp.cache_from_source(path, True), expect) - - def test_cache_from_source_override(self): - # When debug_override is not None, it can be any true-ish or false-ish - # value. - path = os.path.join('foo', 'bar', 'baz.py') - partial_expect = os.path.join('foo', 'bar', '__pycache__', - 'baz.{}.py'.format(self.tag)) - self.assertEqual(imp.cache_from_source(path, []), partial_expect + 'o') - self.assertEqual(imp.cache_from_source(path, [17]), - partial_expect + 'c') - # However if the bool-ishness can't be determined, the exception - # propagates. - class Bearish: - def __bool__(self): raise RuntimeError - with self.assertRaises(RuntimeError): - imp.cache_from_source('/foo/bar/baz.py', Bearish()) - - @unittest.skipUnless(os.sep == '\\' and os.altsep == '/', - 'test meaningful only where os.altsep is defined') - def test_sep_altsep_and_sep_cache_from_source(self): - # Windows path and PEP 3147 where sep is right of altsep. - self.assertEqual( - imp.cache_from_source('\\foo\\bar\\baz/qux.py', True), - '\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag)) - @unittest.skipUnless(sys.implementation.cache_tag is not None, 'requires sys.implementation.cache_tag to not be ' 'None') @@ -407,68 +356,6 @@ class PEP3147Tests(unittest.TestCase): expect = os.path.join('foo', 'bar', 'baz', 'qux.py') self.assertEqual(imp.source_from_cache(path), expect) - def test_source_from_cache_no_cache_tag(self): - # If sys.implementation.cache_tag is None, raise NotImplementedError. - path = os.path.join('blah', '__pycache__', 'whatever.pyc') - with support.swap_attr(sys.implementation, 'cache_tag', None): - with self.assertRaises(NotImplementedError): - imp.source_from_cache(path) - - def test_source_from_cache_bad_path(self): - # When the path to a pyc file is not in PEP 3147 format, a ValueError - # is raised. - self.assertRaises( - ValueError, imp.source_from_cache, '/foo/bar/bazqux.pyc') - - def test_source_from_cache_no_slash(self): - # No slashes at all in path -> ValueError - self.assertRaises( - ValueError, imp.source_from_cache, 'foo.cpython-32.pyc') - - def test_source_from_cache_too_few_dots(self): - # Too few dots in final path component -> ValueError - self.assertRaises( - ValueError, imp.source_from_cache, '__pycache__/foo.pyc') - - def test_source_from_cache_too_many_dots(self): - # Too many dots in final path component -> ValueError - self.assertRaises( - ValueError, imp.source_from_cache, - '__pycache__/foo.cpython-32.foo.pyc') - - def test_source_from_cache_no__pycache__(self): - # Another problem with the path -> ValueError - self.assertRaises( - ValueError, imp.source_from_cache, - '/foo/bar/foo.cpython-32.foo.pyc') - - def test_package___file__(self): - try: - m = __import__('pep3147') - except ImportError: - pass - else: - self.fail("pep3147 module already exists: %r" % (m,)) - # Test that a package's __file__ points to the right source directory. - os.mkdir('pep3147') - sys.path.insert(0, os.curdir) - def cleanup(): - if sys.path[0] == os.curdir: - del sys.path[0] - shutil.rmtree('pep3147') - self.addCleanup(cleanup) - # Touch the __init__.py file. - support.create_empty_file('pep3147/__init__.py') - importlib.invalidate_caches() - expected___file__ = os.sep.join(('.', 'pep3147', '__init__.py')) - m = __import__('pep3147') - self.assertEqual(m.__file__, expected___file__, (m.__file__, m.__path__, sys.path, sys.path_importer_cache)) - # Ensure we load the pyc file. - support.unload('pep3147') - m = __import__('pep3147') - support.unload('pep3147') - self.assertEqual(m.__file__, expected___file__, (m.__file__, m.__path__, sys.path, sys.path_importer_cache)) - class NullImporterTests(unittest.TestCase): @unittest.skipIf(support.TESTFN_UNENCODABLE is None, diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index fd21fa2..5f87d89 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -32,7 +32,6 @@ skip_if_dont_write_bytecode = unittest.skipIf( def remove_files(name): for f in (name + ".py", name + ".pyc", - name + ".pyo", name + ".pyw", name + "$py.class"): unlink(f) @@ -84,7 +83,6 @@ class ImportTests(unittest.TestCase): def test_with_extension(ext): # The extension is normally ".py", perhaps ".pyw". source = TESTFN + ext - pyo = TESTFN + ".pyo" if is_jython: pyc = TESTFN + "$py.class" else: @@ -115,7 +113,6 @@ class ImportTests(unittest.TestCase): forget(TESTFN) unlink(source) unlink(pyc) - unlink(pyo) sys.path.insert(0, os.curdir) try: @@ -138,7 +135,7 @@ class ImportTests(unittest.TestCase): f.write(']') try: - # Compile & remove .py file; we only need .pyc (or .pyo). + # Compile & remove .py file; we only need .pyc. # Bytecode must be relocated from the PEP 3147 bytecode-only location. py_compile.compile(filename) finally: @@ -252,7 +249,7 @@ class ImportTests(unittest.TestCase): importlib.invalidate_caches() mod = __import__(TESTFN) base, ext = os.path.splitext(mod.__file__) - self.assertIn(ext, ('.pyc', '.pyo')) + self.assertEqual(ext, '.pyc') finally: del sys.path[0] remove_files(TESTFN) @@ -328,7 +325,7 @@ class ImportTests(unittest.TestCase): @skip_if_dont_write_bytecode class FilePermissionTests(unittest.TestCase): - # tests for file mode on cached .pyc/.pyo files + # tests for file mode on cached .pyc files @unittest.skipUnless(os.name == 'posix', "test meaningful only on posix systems") @@ -339,7 +336,7 @@ class FilePermissionTests(unittest.TestCase): module = __import__(name) if not os.path.exists(cached_path): self.fail("__import__ did not result in creation of " - "either a .pyc or .pyo file") + "a .pyc file") stat_info = os.stat(cached_path) # Check that the umask is respected, and the executable bits @@ -358,7 +355,7 @@ class FilePermissionTests(unittest.TestCase): __import__(name) if not os.path.exists(cached_path): self.fail("__import__ did not result in creation of " - "either a .pyc or .pyo file") + "a .pyc file") stat_info = os.stat(cached_path) self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)), oct(mode)) @@ -373,7 +370,7 @@ class FilePermissionTests(unittest.TestCase): __import__(name) if not os.path.exists(cached_path): self.fail("__import__ did not result in creation of " - "either a .pyc or .pyo file") + "a .pyc file") stat_info = os.stat(cached_path) expected = mode | 0o200 # Account for fix for issue #6074 @@ -404,10 +401,7 @@ class FilePermissionTests(unittest.TestCase): unlink(path) unload(name) importlib.invalidate_caches() - if __debug__: - bytecode_only = path + "c" - else: - bytecode_only = path + "o" + bytecode_only = path + "c" os.rename(importlib.util.cache_from_source(path), bytecode_only) m = __import__(name) self.assertEqual(m.x, 'rewritten') @@ -631,9 +625,7 @@ class OverridingImportBuiltinTests(unittest.TestCase): class PycacheTests(unittest.TestCase): - # Test the various PEP 3147 related behaviors. - - tag = sys.implementation.cache_tag + # Test the various PEP 3147/488-related behaviors. def _clean(self): forget(TESTFN) @@ -658,9 +650,10 @@ class PycacheTests(unittest.TestCase): self.assertFalse(os.path.exists('__pycache__')) __import__(TESTFN) self.assertTrue(os.path.exists('__pycache__')) - self.assertTrue(os.path.exists(os.path.join( - '__pycache__', '{}.{}.py{}'.format( - TESTFN, self.tag, 'c' if __debug__ else 'o')))) + pyc_path = importlib.util.cache_from_source(self.source) + self.assertTrue(os.path.exists(pyc_path), + 'bytecode file {!r} for {!r} does not ' + 'exist'.format(pyc_path, TESTFN)) @unittest.skipUnless(os.name == 'posix', "test meaningful only on posix systems") @@ -673,8 +666,10 @@ class PycacheTests(unittest.TestCase): with temp_umask(0o222): __import__(TESTFN) self.assertTrue(os.path.exists('__pycache__')) - self.assertFalse(os.path.exists(os.path.join( - '__pycache__', '{}.{}.pyc'.format(TESTFN, self.tag)))) + pyc_path = importlib.util.cache_from_source(self.source) + self.assertFalse(os.path.exists(pyc_path), + 'bytecode file {!r} for {!r} ' + 'exists'.format(pyc_path, TESTFN)) @skip_if_dont_write_bytecode def test_missing_source(self): diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index 5d35d14..69466b2 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -5,6 +5,7 @@ machinery = util.import_importlib('importlib.machinery') importlib_util = util.import_importlib('importlib.util') import os +import string import sys from test import support import types @@ -562,7 +563,8 @@ class PEP3147Tests: path = os.path.join('foo', 'bar', 'baz', 'qux.py') expect = os.path.join('foo', 'bar', 'baz', '__pycache__', 'qux.{}.pyc'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, True), expect) + self.assertEqual(self.util.cache_from_source(path, optimization=''), + expect) def test_cache_from_source_no_cache_tag(self): # No cache tag means NotImplementedError. @@ -575,43 +577,103 @@ class PEP3147Tests: path = os.path.join('foo.bar', 'file') expect = os.path.join('foo.bar', '__pycache__', 'file{}.pyc'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, True), expect) + self.assertEqual(self.util.cache_from_source(path, optimization=''), + expect) - def test_cache_from_source_optimized(self): - # Given the path to a .py file, return the path to its PEP 3147 - # defined .pyo file (i.e. under __pycache__). + def test_cache_from_source_debug_override(self): + # Given the path to a .py file, return the path to its PEP 3147/PEP 488 + # defined .pyc file (i.e. under __pycache__). path = os.path.join('foo', 'bar', 'baz', 'qux.py') - expect = os.path.join('foo', 'bar', 'baz', '__pycache__', - 'qux.{}.pyo'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, False), expect) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + self.assertEqual(self.util.cache_from_source(path, False), + self.util.cache_from_source(path, optimization=1)) + self.assertEqual(self.util.cache_from_source(path, True), + self.util.cache_from_source(path, optimization='')) + with warnings.catch_warnings(): + warnings.simplefilter('error') + with self.assertRaises(DeprecationWarning): + self.util.cache_from_source(path, False) + with self.assertRaises(DeprecationWarning): + self.util.cache_from_source(path, True) def test_cache_from_source_cwd(self): path = 'foo.py' expect = os.path.join('__pycache__', 'foo.{}.pyc'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, True), expect) + self.assertEqual(self.util.cache_from_source(path, optimization=''), + expect) def test_cache_from_source_override(self): # When debug_override is not None, it can be any true-ish or false-ish # value. path = os.path.join('foo', 'bar', 'baz.py') - partial_expect = os.path.join('foo', 'bar', '__pycache__', - 'baz.{}.py'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, []), partial_expect + 'o') - self.assertEqual(self.util.cache_from_source(path, [17]), - partial_expect + 'c') # However if the bool-ishness can't be determined, the exception # propagates. class Bearish: def __bool__(self): raise RuntimeError - with self.assertRaises(RuntimeError): - self.util.cache_from_source('/foo/bar/baz.py', Bearish()) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + self.assertEqual(self.util.cache_from_source(path, []), + self.util.cache_from_source(path, optimization=1)) + self.assertEqual(self.util.cache_from_source(path, [17]), + self.util.cache_from_source(path, optimization='')) + with self.assertRaises(RuntimeError): + self.util.cache_from_source('/foo/bar/baz.py', Bearish()) + + + def test_cache_from_source_optimization_empty_string(self): + # Setting 'optimization' to '' leads to no optimization tag (PEP 488). + path = 'foo.py' + expect = os.path.join('__pycache__', 'foo.{}.pyc'.format(self.tag)) + self.assertEqual(self.util.cache_from_source(path, optimization=''), + expect) + + def test_cache_from_source_optimization_None(self): + # Setting 'optimization' to None uses the interpreter's optimization. + # (PEP 488) + path = 'foo.py' + optimization_level = sys.flags.optimize + almost_expect = os.path.join('__pycache__', 'foo.{}'.format(self.tag)) + if optimization_level == 0: + expect = almost_expect + '.pyc' + elif optimization_level <= 2: + expect = almost_expect + '.opt-{}.pyc'.format(optimization_level) + else: + msg = '{!r} is a non-standard optimization level'.format(optimization_level) + self.skipTest(msg) + self.assertEqual(self.util.cache_from_source(path, optimization=None), + expect) + + def test_cache_from_source_optimization_set(self): + # The 'optimization' parameter accepts anything that has a string repr + # that passes str.alnum(). + path = 'foo.py' + valid_characters = string.ascii_letters + string.digits + almost_expect = os.path.join('__pycache__', 'foo.{}'.format(self.tag)) + got = self.util.cache_from_source(path, optimization=valid_characters) + # Test all valid characters are accepted. + self.assertEqual(got, + almost_expect + '.opt-{}.pyc'.format(valid_characters)) + # str() should be called on argument. + self.assertEqual(self.util.cache_from_source(path, optimization=42), + almost_expect + '.opt-42.pyc') + # Invalid characters raise ValueError. + with self.assertRaises(ValueError): + self.util.cache_from_source(path, optimization='path/is/bad') + + def test_cache_from_source_debug_override_optimization_both_set(self): + # Can only set one of the optimization-related parameters. + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + with self.assertRaises(TypeError): + self.util.cache_from_source('foo.py', False, optimization='') @unittest.skipUnless(os.sep == '\\' and os.altsep == '/', 'test meaningful only where os.altsep is defined') def test_sep_altsep_and_sep_cache_from_source(self): # Windows path and PEP 3147 where sep is right of altsep. self.assertEqual( - self.util.cache_from_source('\\foo\\bar\\baz/qux.py', True), + self.util.cache_from_source('\\foo\\bar\\baz/qux.py', optimization=''), '\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag)) @unittest.skipUnless(sys.implementation.cache_tag is not None, @@ -649,7 +711,12 @@ class PEP3147Tests: ValueError, self.util.source_from_cache, '__pycache__/foo.pyc') def test_source_from_cache_too_many_dots(self): - # Too many dots in final path component -> ValueError + with self.assertRaises(ValueError): + self.util.source_from_cache( + '__pycache__/foo.cpython-32.opt-1.foo.pyc') + + def test_source_from_cache_not_opt(self): + # Non-`opt-` path component -> ValueError self.assertRaises( ValueError, self.util.source_from_cache, '__pycache__/foo.cpython-32.foo.pyc') @@ -660,6 +727,17 @@ class PEP3147Tests: ValueError, self.util.source_from_cache, '/foo/bar/foo.cpython-32.foo.pyc') + def test_source_from_cache_optimized_bytecode(self): + # Optimized bytecode is not an issue. + path = os.path.join('__pycache__', 'foo.{}.opt-1.pyc'.format(self.tag)) + self.assertEqual(self.util.source_from_cache(path), 'foo.py') + + def test_source_from_cache_missing_optimization(self): + # An empty optimization level is a no-no. + path = os.path.join('__pycache__', 'foo.{}.opt-.pyc'.format(self.tag)) + with self.assertRaises(ValueError): + self.util.source_from_cache(path) + (Frozen_PEP3147Tests, Source_PEP3147Tests diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py index 1abea27..bff35db 100644 --- a/Lib/test/test_py_compile.py +++ b/Lib/test/test_py_compile.py @@ -119,6 +119,10 @@ class PyCompileTests(unittest.TestCase): self.assertTrue(os.path.exists(cache_path)) self.assertFalse(os.path.exists(pyc_path)) + def test_optimization_path(self): + # Specifying optimized bytecode should lead to a path reflecting that. + self.assertIn('opt-2', py_compile.compile(self.source_path, optimize=2)) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index 786b813..3884734 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -269,7 +269,7 @@ class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin): if verbose > 1: print(ex) # Persist with cleaning up def _fix_ns_for_legacy_pyc(self, ns, alter_sys): - char_to_add = "c" if __debug__ else "o" + char_to_add = "c" ns["__file__"] += char_to_add ns["__cached__"] = ns["__file__"] spec = ns["__spec__"] diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index 05bf274..2f2c584 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -13,8 +13,8 @@ from test.tracedmodules import testmod #------------------------------- Utilities -----------------------------------# def fix_ext_py(filename): - """Given a .pyc/.pyo filename converts it to the appropriate .py""" - if filename.endswith(('.pyc', '.pyo')): + """Given a .pyc filename converts it to the appropriate .py""" + if filename.endswith('.pyc'): filename = filename[:-1] return filename diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py index 19d3fd8..9382c48 100644 --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -660,11 +660,9 @@ class TestFilters(unittest.TestCase): self.assertFalse(fnmatch('abcdd', 'a*c*e')) self.assertFalse(fnmatch('abcbdefef', 'a*bd*eg')) - # replace .pyc and .pyo suffix with .py + # replace .pyc suffix with .py self.assertTrue(fnmatch('a.pyc', 'a.py')) - self.assertTrue(fnmatch('a.pyo', 'a.py')) self.assertTrue(fnmatch('a.py', 'a.pyc')) - self.assertTrue(fnmatch('a.py', 'a.pyo')) if os.name == 'nt': # case insensitive @@ -674,7 +672,6 @@ class TestFilters(unittest.TestCase): self.assertTrue(fnmatch('a.pyc', 'a.PY')) self.assertTrue(fnmatch('a.PYO', 'a.py')) self.assertTrue(fnmatch('a.py', 'a.PYC')) - self.assertTrue(fnmatch('a.PY', 'a.pyo')) else: # case sensitive self.assertFalse(fnmatch('aBC', 'ABc')) @@ -683,7 +680,6 @@ class TestFilters(unittest.TestCase): self.assertFalse(fnmatch('a.pyc', 'a.PY')) self.assertFalse(fnmatch('a.PYO', 'a.py')) self.assertFalse(fnmatch('a.py', 'a.PYC')) - self.assertFalse(fnmatch('a.PY', 'a.pyo')) if os.name == 'nt': # normalize alternate separator "/" to the standard separator "\" diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 1b2dc85..aa8c463 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -689,7 +689,7 @@ class PyZipFileTests(unittest.TestCase): self.requiresWriteAccess(os.path.dirname(__file__)) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: fn = __file__ - if fn.endswith('.pyc') or fn.endswith('.pyo'): + if fn.endswith('.pyc'): path_split = fn.split(os.sep) if os.altsep is not None: path_split.extend(fn.split(os.altsep)) @@ -706,7 +706,7 @@ class PyZipFileTests(unittest.TestCase): with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: fn = __file__ - if fn.endswith(('.pyc', '.pyo')): + if fn.endswith('.pyc'): fn = fn[:-1] zipfp.writepy(fn, "testpackage") @@ -762,10 +762,8 @@ class PyZipFileTests(unittest.TestCase): import email packagedir = os.path.dirname(email.__file__) self.requiresWriteAccess(packagedir) - # use .pyc if running test in optimization mode, - # use .pyo if running test in debug mode optlevel = 1 if __debug__ else 0 - ext = '.pyo' if optlevel == 1 else '.pyc' + ext = '.pyc' with TemporaryFile() as t, \ zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp: @@ -839,11 +837,10 @@ class PyZipFileTests(unittest.TestCase): self.assertIn("SyntaxError", s.getvalue()) # as it will not have compiled the python file, it will - # include the .py file not .pyc or .pyo + # include the .py file not .pyc names = zipfp.namelist() self.assertIn('mod1.py', names) self.assertNotIn('mod1.pyc', names) - self.assertNotIn('mod1.pyo', names) finally: rmtree(TESTFN2) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py index 0a83841..a97a778 100644 --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -51,7 +51,7 @@ TESTPACK2 = "ziptestpackage2" TEMP_ZIP = os.path.abspath("junk95142.zip") pyc_file = importlib.util.cache_from_source(TESTMOD + '.py') -pyc_ext = ('.pyc' if __debug__ else '.pyo') +pyc_ext = '.pyc' class ImportHooksBaseTestCase(unittest.TestCase): diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index c8d8061..109e399 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1852,7 +1852,7 @@ class Tk(Misc, Wm): import os baseName = os.path.basename(sys.argv[0]) baseName, ext = os.path.splitext(baseName) - if ext not in ('.py', '.pyc', '.pyo'): + if ext not in ('.py', '.pyc'): baseName = baseName + ext interactive = 0 self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use) diff --git a/Lib/tkinter/test/runtktests.py b/Lib/tkinter/test/runtktests.py index ccb3755..dbe5e88 100644 --- a/Lib/tkinter/test/runtktests.py +++ b/Lib/tkinter/test/runtktests.py @@ -16,7 +16,7 @@ this_dir_path = os.path.abspath(os.path.dirname(__file__)) def is_package(path): for name in os.listdir(path): - if name in ('__init__.py', '__init__.pyc', '__init.pyo'): + if name in ('__init__.py', '__init__.pyc'): return True return False diff --git a/Lib/trace.py b/Lib/trace.py index 41eff26..f108266 100755 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -305,7 +305,7 @@ class CoverageResults: if self.is_ignored_filename(filename): continue - if filename.endswith((".pyc", ".pyo")): + if filename.endswith(".pyc"): filename = filename[:-1] if coverdir is None: diff --git a/Lib/tracemalloc.py b/Lib/tracemalloc.py index adedfc5..6288da8 100644 --- a/Lib/tracemalloc.py +++ b/Lib/tracemalloc.py @@ -297,7 +297,7 @@ class _Traces(Sequence): def _normalize_filename(filename): filename = os.path.normcase(filename) - if filename.endswith(('.pyc', '.pyo')): + if filename.endswith('.pyc'): filename = filename[:-1] return filename diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py index 8a1a2a7..c776f16 100644 --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -14,9 +14,9 @@ from . import case, suite, util __unittest = True -# what about .pyc or .pyo (etc) +# what about .pyc (etc) # we would need to avoid loading the same tests multiple times -# from '.py', '.pyc' *and* '.pyo' +# from '.py', *and* '.pyc' VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE) diff --git a/Lib/warnings.py b/Lib/warnings.py index 5ca4b9c..16246b4 100644 --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -188,7 +188,7 @@ def warn(message, category=None, stacklevel=1): filename = globals.get('__file__') if filename: fnl = filename.lower() - if fnl.endswith((".pyc", ".pyo")): + if fnl.endswith(".pyc"): filename = filename[:-1] else: if module == "__main__": diff --git a/Lib/zipfile.py b/Lib/zipfile.py index d545c55..85bdaa9 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1731,7 +1731,7 @@ class PyZipFile(ZipFile): the modules into the archive. If pathname is a plain directory, listdir *.py and enter all modules. Else, pathname must be a Python *.py file and the module will be put into the - archive. Added modules are always module.pyo or module.pyc. + archive. Added modules are always module.pyc. This method will compile the module.py into module.pyc if necessary. If filterfunc(pathname) is given, it is called with every argument. @@ -1824,46 +1824,59 @@ class PyZipFile(ZipFile): file_py = pathname + ".py" file_pyc = pathname + ".pyc" - file_pyo = pathname + ".pyo" - pycache_pyc = importlib.util.cache_from_source(file_py, True) - pycache_pyo = importlib.util.cache_from_source(file_py, False) + pycache_opt0 = importlib.util.cache_from_source(file_py, optimization='') + pycache_opt1 = importlib.util.cache_from_source(file_py, optimization=1) + pycache_opt2 = importlib.util.cache_from_source(file_py, optimization=2) if self._optimize == -1: # legacy mode: use whatever file is present - if (os.path.isfile(file_pyo) and - os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime): - # Use .pyo file. - arcname = fname = file_pyo - elif (os.path.isfile(file_pyc) and + if (os.path.isfile(file_pyc) and os.stat(file_pyc).st_mtime >= os.stat(file_py).st_mtime): # Use .pyc file. arcname = fname = file_pyc - elif (os.path.isfile(pycache_pyc) and - os.stat(pycache_pyc).st_mtime >= os.stat(file_py).st_mtime): + elif (os.path.isfile(pycache_opt0) and + os.stat(pycache_opt0).st_mtime >= os.stat(file_py).st_mtime): # Use the __pycache__/*.pyc file, but write it to the legacy pyc # file name in the archive. - fname = pycache_pyc + fname = pycache_opt0 arcname = file_pyc - elif (os.path.isfile(pycache_pyo) and - os.stat(pycache_pyo).st_mtime >= os.stat(file_py).st_mtime): - # Use the __pycache__/*.pyo file, but write it to the legacy pyo + elif (os.path.isfile(pycache_opt1) and + os.stat(pycache_opt1).st_mtime >= os.stat(file_py).st_mtime): + # Use the __pycache__/*.pyc file, but write it to the legacy pyc + # file name in the archive. + fname = pycache_opt1 + arcname = file_pyc + elif (os.path.isfile(pycache_opt2) and + os.stat(pycache_opt2).st_mtime >= os.stat(file_py).st_mtime): + # Use the __pycache__/*.pyc file, but write it to the legacy pyc # file name in the archive. - fname = pycache_pyo - arcname = file_pyo + fname = pycache_opt2 + arcname = file_pyc else: # Compile py into PEP 3147 pyc file. if _compile(file_py): - fname = (pycache_pyc if __debug__ else pycache_pyo) - arcname = (file_pyc if __debug__ else file_pyo) + if sys.flags.optimize == 0: + fname = pycache_opt0 + elif sys.flags.optimize == 1: + fname = pycache_opt1 + else: + fname = pycache_opt2 + arcname = file_pyc else: fname = arcname = file_py else: # new mode: use given optimization level if self._optimize == 0: - fname = pycache_pyc + fname = pycache_opt0 arcname = file_pyc else: - fname = pycache_pyo - arcname = file_pyo + arcname = file_pyc + if self._optimize == 1: + fname = pycache_opt1 + elif self._optimize == 2: + fname = pycache_opt2 + else: + msg = "invalid value for 'optimize': {!r}".format(self._optimize) + raise ValueError(msg) if not (os.path.isfile(fname) and os.stat(fname).st_mtime >= os.stat(file_py).st_mtime): if not _compile(file_py, optimize=self._optimize): |