mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
Issue #15056: imp.cache_from_source() and source_from_cache() raise
NotimplementedError when sys.implementation.cache_tag is None. Thanks to Pranav Ravichandran for taking an initial stab at the patch.
This commit is contained in:
parent
bf7eab077f
commit
19a2f5961c
6 changed files with 3875 additions and 3802 deletions
|
@ -180,14 +180,19 @@ file paths.
|
||||||
source *path*. For example, if *path* is ``/foo/bar/baz.py`` the return
|
source *path*. For example, if *path* is ``/foo/bar/baz.py`` the return
|
||||||
value would be ``/foo/bar/__pycache__/baz.cpython-32.pyc`` for Python 3.2.
|
value would be ``/foo/bar/__pycache__/baz.cpython-32.pyc`` for Python 3.2.
|
||||||
The ``cpython-32`` string comes from the current magic tag (see
|
The ``cpython-32`` string comes from the current magic tag (see
|
||||||
:func:`get_tag`). The returned path will end in ``.pyc`` when
|
:func:`get_tag`; if :attr:`sys.implementation.cache_tag` is not defined then
|
||||||
``__debug__`` is True or ``.pyo`` for an optimized Python
|
:exc:`NotImplementedError` will be raised). The returned path will end in
|
||||||
|
``.pyc`` when ``__debug__`` is True or ``.pyo`` for an optimized Python
|
||||||
(i.e. ``__debug__`` is False). By passing in True or False for
|
(i.e. ``__debug__`` is False). By passing in True or False for
|
||||||
*debug_override* you can override the system's value for ``__debug__`` for
|
*debug_override* you can override the system's value for ``__debug__`` for
|
||||||
extension selection.
|
extension selection.
|
||||||
|
|
||||||
*path* need not exist.
|
*path* need not exist.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.3
|
||||||
|
If :attr:`sys.implementation.cache_tag` is ``None``, then
|
||||||
|
:exc:`NotImplementedError` is raised.
|
||||||
|
|
||||||
|
|
||||||
.. function:: source_from_cache(path)
|
.. function:: source_from_cache(path)
|
||||||
|
|
||||||
|
@ -195,7 +200,13 @@ file paths.
|
||||||
file path. For example, if *path* is
|
file path. For example, if *path* is
|
||||||
``/foo/bar/__pycache__/baz.cpython-32.pyc`` the returned path would be
|
``/foo/bar/__pycache__/baz.cpython-32.pyc`` the returned path would be
|
||||||
``/foo/bar/baz.py``. *path* need not exist, however if it does not conform
|
``/foo/bar/baz.py``. *path* need not exist, however if it does not conform
|
||||||
to :pep:`3147` format, a ``ValueError`` is raised.
|
to :pep:`3147` format, a ``ValueError`` is raised. If
|
||||||
|
:attr:`sys.implementation.cache_tag` is not defined,
|
||||||
|
:exc:`NotImplementedError` is raised.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.3
|
||||||
|
Raise :exc:`NotImplementedError` when
|
||||||
|
:attr:`sys.implementation.cache_tag` is not defined.
|
||||||
|
|
||||||
|
|
||||||
.. function:: get_tag()
|
.. function:: get_tag()
|
||||||
|
@ -203,6 +214,10 @@ file paths.
|
||||||
Return the :pep:`3147` magic tag string matching this version of Python's
|
Return the :pep:`3147` magic tag string matching this version of Python's
|
||||||
magic number, as returned by :func:`get_magic`.
|
magic number, as returned by :func:`get_magic`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
You may use :attr:`sys.implementation.cache_tag` directly starting
|
||||||
|
in Python 3.3.
|
||||||
|
|
||||||
|
|
||||||
The following functions help interact with the import system's internal
|
The following functions help interact with the import system's internal
|
||||||
locking mechanism. Locking semantics of imports are an implementation
|
locking mechanism. Locking semantics of imports are an implementation
|
||||||
|
|
|
@ -58,9 +58,12 @@ def source_from_cache(path):
|
||||||
|
|
||||||
The .pyc/.pyo file does not need to exist; this simply returns the path to
|
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 .py file calculated to correspond to the .pyc/.pyo file. If path does
|
||||||
not conform to PEP 3147 format, ValueError will be raised.
|
not conform to PEP 3147 format, ValueError will be raised. If
|
||||||
|
sys.implementation.cache_tag is None then NotImplementedError is raised.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if sys.implementation.cache_tag is None:
|
||||||
|
raise NotImplementedError('sys.implementation.cache_tag is None')
|
||||||
head, pycache_filename = os.path.split(path)
|
head, pycache_filename = os.path.split(path)
|
||||||
head, pycache = os.path.split(head)
|
head, pycache = os.path.split(head)
|
||||||
if pycache != _bootstrap._PYCACHE:
|
if pycache != _bootstrap._PYCACHE:
|
||||||
|
|
|
@ -321,6 +321,8 @@ def cache_from_source(path, debug_override=None):
|
||||||
If debug_override is not None, then it must be a boolean and is taken as
|
If debug_override is not None, then it must be a boolean and is taken as
|
||||||
the value of __debug__ instead.
|
the value of __debug__ instead.
|
||||||
|
|
||||||
|
If sys.implementation.cache_tag is None then NotImplementedError is raised.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
debug = __debug__ if debug_override is None else debug_override
|
debug = __debug__ if debug_override is None else debug_override
|
||||||
if debug:
|
if debug:
|
||||||
|
@ -329,7 +331,10 @@ def cache_from_source(path, debug_override=None):
|
||||||
suffixes = OPTIMIZED_BYTECODE_SUFFIXES
|
suffixes = OPTIMIZED_BYTECODE_SUFFIXES
|
||||||
head, tail = _path_split(path)
|
head, tail = _path_split(path)
|
||||||
base_filename, sep, _ = tail.partition('.')
|
base_filename, sep, _ = tail.partition('.')
|
||||||
filename = ''.join([base_filename, sep, _TAG, suffixes[0]])
|
tag = sys.implementation.cache_tag
|
||||||
|
if tag is None:
|
||||||
|
raise NotImplementedError('sys.implementation.cache_tag is None')
|
||||||
|
filename = ''.join([base_filename, sep, tag, suffixes[0]])
|
||||||
return _path_join(head, _PYCACHE, filename)
|
return _path_join(head, _PYCACHE, filename)
|
||||||
|
|
||||||
|
|
||||||
|
@ -649,7 +654,10 @@ class _LoaderBasics:
|
||||||
code_object = self.get_code(name)
|
code_object = self.get_code(name)
|
||||||
module.__file__ = self.get_filename(name)
|
module.__file__ = self.get_filename(name)
|
||||||
if not sourceless:
|
if not sourceless:
|
||||||
|
try:
|
||||||
module.__cached__ = cache_from_source(module.__file__)
|
module.__cached__ = cache_from_source(module.__file__)
|
||||||
|
except NotImplementedError:
|
||||||
|
module.__cached__ = module.__file__
|
||||||
else:
|
else:
|
||||||
module.__cached__ = module.__file__
|
module.__cached__ = module.__file__
|
||||||
module.__package__ = name
|
module.__package__ = name
|
||||||
|
@ -718,9 +726,12 @@ class SourceLoader(_LoaderBasics):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
source_path = self.get_filename(fullname)
|
source_path = self.get_filename(fullname)
|
||||||
bytecode_path = cache_from_source(source_path)
|
|
||||||
source_mtime = None
|
source_mtime = None
|
||||||
if bytecode_path is not None:
|
try:
|
||||||
|
bytecode_path = cache_from_source(source_path)
|
||||||
|
except NotImplementedError:
|
||||||
|
bytecode_path = None
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
st = self.path_stats(source_path)
|
st = self.path_stats(source_path)
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
|
@ -1417,7 +1428,6 @@ def __import__(name, globals={}, locals={}, fromlist=[], level=0):
|
||||||
|
|
||||||
|
|
||||||
_MAGIC_NUMBER = None # Set in _setup()
|
_MAGIC_NUMBER = None # Set in _setup()
|
||||||
_TAG = None # Set in _setup()
|
|
||||||
|
|
||||||
|
|
||||||
def _setup(sys_module, _imp_module):
|
def _setup(sys_module, _imp_module):
|
||||||
|
@ -1479,7 +1489,6 @@ def _setup(sys_module, _imp_module):
|
||||||
# Constants
|
# Constants
|
||||||
setattr(self_module, '_relax_case', _make_relax_case())
|
setattr(self_module, '_relax_case', _make_relax_case())
|
||||||
setattr(self_module, '_MAGIC_NUMBER', _imp_module.get_magic())
|
setattr(self_module, '_MAGIC_NUMBER', _imp_module.get_magic())
|
||||||
setattr(self_module, '_TAG', sys.implementation.cache_tag)
|
|
||||||
if builtin_os == 'nt':
|
if builtin_os == 'nt':
|
||||||
SOURCE_SUFFIXES.append('.pyw')
|
SOURCE_SUFFIXES.append('.pyw')
|
||||||
|
|
||||||
|
|
|
@ -231,6 +231,8 @@ class PEP3147Tests(unittest.TestCase):
|
||||||
|
|
||||||
tag = imp.get_tag()
|
tag = imp.get_tag()
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.implementation.cache_tag is not None,
|
||||||
|
'requires sys.implementation.cache_tag not be None')
|
||||||
def test_cache_from_source(self):
|
def test_cache_from_source(self):
|
||||||
# Given the path to a .py file, return the path to its PEP 3147
|
# Given the path to a .py file, return the path to its PEP 3147
|
||||||
# defined .pyc file (i.e. under __pycache__).
|
# defined .pyc file (i.e. under __pycache__).
|
||||||
|
@ -239,6 +241,12 @@ class PEP3147Tests(unittest.TestCase):
|
||||||
'qux.{}.pyc'.format(self.tag))
|
'qux.{}.pyc'.format(self.tag))
|
||||||
self.assertEqual(imp.cache_from_source(path, True), expect)
|
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):
|
def test_cache_from_source_no_dot(self):
|
||||||
# Directory with a dot, filename without dot.
|
# Directory with a dot, filename without dot.
|
||||||
path = os.path.join('foo.bar', 'file')
|
path = os.path.join('foo.bar', 'file')
|
||||||
|
@ -283,6 +291,9 @@ class PEP3147Tests(unittest.TestCase):
|
||||||
imp.cache_from_source('\\foo\\bar\\baz/qux.py', True),
|
imp.cache_from_source('\\foo\\bar\\baz/qux.py', True),
|
||||||
'\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag))
|
'\\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')
|
||||||
def test_source_from_cache(self):
|
def test_source_from_cache(self):
|
||||||
# Given the path to a PEP 3147 defined .pyc file, return the path to
|
# Given the path to a PEP 3147 defined .pyc file, return the path to
|
||||||
# its source. This tests the good path.
|
# its source. This tests the good path.
|
||||||
|
@ -291,6 +302,13 @@ class PEP3147Tests(unittest.TestCase):
|
||||||
expect = os.path.join('foo', 'bar', 'baz', 'qux.py')
|
expect = os.path.join('foo', 'bar', 'baz', 'qux.py')
|
||||||
self.assertEqual(imp.source_from_cache(path), expect)
|
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):
|
def test_source_from_cache_bad_path(self):
|
||||||
# When the path to a pyc file is not in PEP 3147 format, a ValueError
|
# When the path to a pyc file is not in PEP 3147 format, a ValueError
|
||||||
# is raised.
|
# is raised.
|
||||||
|
|
|
@ -31,6 +31,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #15056: imp.cache_from_source() and source_from_cache() raise
|
||||||
|
NotImplementedError when sys.implementation.cache_tag is set to None.
|
||||||
|
|
||||||
- Issue #15256: Grammatical mistake in exception raised by imp.find_module().
|
- Issue #15256: Grammatical mistake in exception raised by imp.find_module().
|
||||||
|
|
||||||
- Issue #5931: wsgiref environ variable SERVER_SOFTWARE will specify an
|
- Issue #5931: wsgiref environ variable SERVER_SOFTWARE will specify an
|
||||||
|
|
7609
Python/importlib.h
7609
Python/importlib.h
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue