Issue #17907: touch up the code for imp.new_module().
This commit is contained in:
parent
15e489f7c5
commit
a3c96154d2
|
@ -205,6 +205,9 @@ file paths.
|
||||||
If :attr:`sys.implementation.cache_tag` is ``None``, then
|
If :attr:`sys.implementation.cache_tag` is ``None``, then
|
||||||
:exc:`NotImplementedError` is raised.
|
:exc:`NotImplementedError` is raised.
|
||||||
|
|
||||||
|
.. deprecated:: 3.4
|
||||||
|
Use :func:`importlib.util.cache_from_source` instead.
|
||||||
|
|
||||||
|
|
||||||
.. function:: source_from_cache(path)
|
.. function:: source_from_cache(path)
|
||||||
|
|
||||||
|
@ -220,6 +223,9 @@ file paths.
|
||||||
Raise :exc:`NotImplementedError` when
|
Raise :exc:`NotImplementedError` when
|
||||||
:attr:`sys.implementation.cache_tag` is not defined.
|
:attr:`sys.implementation.cache_tag` is not defined.
|
||||||
|
|
||||||
|
.. deprecated:: 3.4
|
||||||
|
Use :func:`importlib.util.source_from_cache` instead.
|
||||||
|
|
||||||
|
|
||||||
.. function:: get_tag()
|
.. function:: get_tag()
|
||||||
|
|
||||||
|
|
|
@ -886,6 +886,36 @@ an :term:`importer`.
|
||||||
|
|
||||||
.. versionadded:: 3.4
|
.. versionadded:: 3.4
|
||||||
|
|
||||||
|
.. function:: cache_from_source(path, debug_override=None)
|
||||||
|
|
||||||
|
Return the :pep:`3147` path to the byte-compiled file associated with the
|
||||||
|
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.
|
||||||
|
The ``cpython-32`` string comes from the current magic tag (see
|
||||||
|
:func:`get_tag`; if :attr:`sys.implementation.cache_tag` is not defined then
|
||||||
|
: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
|
||||||
|
*debug_override* you can override the system's value for ``__debug__`` for
|
||||||
|
extension selection.
|
||||||
|
|
||||||
|
*path* need not exist.
|
||||||
|
|
||||||
|
.. versionadded:: 3.4
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: source_from_cache(path)
|
||||||
|
|
||||||
|
Given the *path* to a :pep:`3147` file name, return the associated source code
|
||||||
|
file path. For example, if *path* is
|
||||||
|
``/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
|
||||||
|
to :pep:`3147` format, a ``ValueError`` is raised. If
|
||||||
|
:attr:`sys.implementation.cache_tag` is not defined,
|
||||||
|
:exc:`NotImplementedError` is raised.
|
||||||
|
|
||||||
|
.. versionadded:: 3.4
|
||||||
|
|
||||||
.. function:: resolve_name(name, package)
|
.. function:: resolve_name(name, package)
|
||||||
|
|
||||||
Resolve a relative module name to an absolute one.
|
Resolve a relative module name to an absolute one.
|
||||||
|
|
13
Lib/imp.py
13
Lib/imp.py
|
@ -17,7 +17,6 @@ except ModuleNotFoundError:
|
||||||
load_dynamic = None
|
load_dynamic = None
|
||||||
|
|
||||||
# Directly exposed by this module
|
# Directly exposed by this module
|
||||||
from importlib._bootstrap import new_module
|
|
||||||
from importlib._bootstrap import cache_from_source, source_from_cache
|
from importlib._bootstrap import cache_from_source, source_from_cache
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,6 +27,7 @@ import importlib
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tokenize
|
import tokenize
|
||||||
|
import types
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,6 +44,17 @@ PY_CODERESOURCE = 8
|
||||||
IMP_HOOK = 9
|
IMP_HOOK = 9
|
||||||
|
|
||||||
|
|
||||||
|
def new_module(name):
|
||||||
|
"""**DEPRECATED**
|
||||||
|
|
||||||
|
Create a new module.
|
||||||
|
|
||||||
|
The module is not entered into sys.modules.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return types.ModuleType(name)
|
||||||
|
|
||||||
|
|
||||||
def get_magic():
|
def get_magic():
|
||||||
"""**DEPRECATED**
|
"""**DEPRECATED**
|
||||||
|
|
||||||
|
|
|
@ -121,15 +121,6 @@ def _wrap(new, old):
|
||||||
_code_type = type(_wrap.__code__)
|
_code_type = type(_wrap.__code__)
|
||||||
|
|
||||||
|
|
||||||
def new_module(name):
|
|
||||||
"""Create a new module.
|
|
||||||
|
|
||||||
The module is not entered into sys.modules.
|
|
||||||
|
|
||||||
"""
|
|
||||||
return type(_io)(name)
|
|
||||||
|
|
||||||
|
|
||||||
# Module-level locking ########################################################
|
# Module-level locking ########################################################
|
||||||
|
|
||||||
# A dict mapping module names to weakrefs of _ModuleLock instances
|
# A dict mapping module names to weakrefs of _ModuleLock instances
|
||||||
|
@ -509,7 +500,7 @@ class _ModuleManager:
|
||||||
# This must be done before open() is called as the 'io' module
|
# This must be done before open() is called as the 'io' module
|
||||||
# implicitly imports 'locale' and would otherwise trigger an
|
# implicitly imports 'locale' and would otherwise trigger an
|
||||||
# infinite loop.
|
# infinite loop.
|
||||||
self._module = new_module(self._name)
|
self._module = type(_io)(self._name)
|
||||||
# This must be done before putting the module in sys.modules
|
# This must be done before putting the module in sys.modules
|
||||||
# (otherwise an optimization shortcut in import.c becomes wrong)
|
# (otherwise an optimization shortcut in import.c becomes wrong)
|
||||||
self._module.__initializing__ = True
|
self._module.__initializing__ = True
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
"""Utility code for constructing importers, etc."""
|
"""Utility code for constructing importers, etc."""
|
||||||
|
|
||||||
from ._bootstrap import MAGIC_NUMBER
|
from ._bootstrap import MAGIC_NUMBER
|
||||||
|
from ._bootstrap import cache_from_source
|
||||||
from ._bootstrap import module_to_load
|
from ._bootstrap import module_to_load
|
||||||
from ._bootstrap import set_loader
|
from ._bootstrap import set_loader
|
||||||
from ._bootstrap import set_package
|
from ._bootstrap import set_package
|
||||||
|
from ._bootstrap import source_from_cache
|
||||||
from ._bootstrap import _resolve_name
|
from ._bootstrap import _resolve_name
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
|
|
@ -859,7 +859,6 @@ class ImportlibBootstrapTests(unittest.TestCase):
|
||||||
from importlib import machinery
|
from importlib import machinery
|
||||||
mod = sys.modules['_frozen_importlib']
|
mod = sys.modules['_frozen_importlib']
|
||||||
self.assertIs(machinery.FileFinder, mod.FileFinder)
|
self.assertIs(machinery.FileFinder, mod.FileFinder)
|
||||||
self.assertIs(imp.new_module, mod.new_module)
|
|
||||||
|
|
||||||
|
|
||||||
class ImportTracebackTests(unittest.TestCase):
|
class ImportTracebackTests(unittest.TestCase):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from importlib import util
|
from importlib import util
|
||||||
from . import util as test_util
|
from . import util as test_util
|
||||||
import imp
|
import imp
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
from test import support
|
from test import support
|
||||||
import types
|
import types
|
||||||
|
@ -324,5 +325,120 @@ class MagicNumberTests(unittest.TestCase):
|
||||||
self.assertTrue(util.MAGIC_NUMBER.endswith(b'\r\n'))
|
self.assertTrue(util.MAGIC_NUMBER.endswith(b'\r\n'))
|
||||||
|
|
||||||
|
|
||||||
|
class PEP3147Tests(unittest.TestCase):
|
||||||
|
"""Tests of PEP 3147-related functions:
|
||||||
|
cache_from_source and source_from_cache.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
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):
|
||||||
|
# Given the path to a .py file, return the path to its PEP 3147
|
||||||
|
# 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.{}.pyc'.format(self.tag))
|
||||||
|
self.assertEqual(util.cache_from_source(path, True), expect)
|
||||||
|
|
||||||
|
def test_cache_from_source_no_cache_tag(self):
|
||||||
|
# No cache tag means NotImplementedError.
|
||||||
|
with support.swap_attr(sys.implementation, 'cache_tag', None):
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
util.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(util.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(util.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(util.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(util.cache_from_source(path, []), partial_expect + 'o')
|
||||||
|
self.assertEqual(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):
|
||||||
|
util.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(
|
||||||
|
util.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')
|
||||||
|
def test_source_from_cache(self):
|
||||||
|
# Given the path to a PEP 3147 defined .pyc file, return the path to
|
||||||
|
# its source. This tests the good path.
|
||||||
|
path = os.path.join('foo', 'bar', 'baz', '__pycache__',
|
||||||
|
'qux.{}.pyc'.format(self.tag))
|
||||||
|
expect = os.path.join('foo', 'bar', 'baz', 'qux.py')
|
||||||
|
self.assertEqual(util.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):
|
||||||
|
util.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, util.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, util.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, util.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, util.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, util.source_from_cache,
|
||||||
|
'/foo/bar/foo.cpython-32.foo.pyc')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
7079
Python/importlib.h
7079
Python/importlib.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue