Issue #17907: touch up the code for imp.new_module().

This commit is contained in:
Brett Cannon 2013-06-14 22:26:30 -04:00
parent 15e489f7c5
commit a3c96154d2
8 changed files with 3700 additions and 3558 deletions

View File

@ -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()

View File

@ -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.

View File

@ -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**

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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()

File diff suppressed because it is too large Load Diff