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/importlib | |
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/importlib')
-rw-r--r-- | Lib/importlib/_bootstrap.py | 78 |
1 files changed, 51 insertions, 27 deletions
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(): |