[Python-checkins] cpython: Issue #17907: touch up the code for imp.new_module().

brett.cannon python-checkins at python.org
Sat Jun 15 04:26:39 CEST 2013


http://hg.python.org/cpython/rev/9cacdb9d0c59
changeset:   84134:9cacdb9d0c59
user:        Brett Cannon <brett at python.org>
date:        Fri Jun 14 22:26:30 2013 -0400
summary:
  Issue #17907: touch up the code for imp.new_module().

files:
  Doc/library/imp.rst                  |     6 +
  Doc/library/importlib.rst            |    30 +
  Lib/imp.py                           |    13 +-
  Lib/importlib/_bootstrap.py          |    11 +-
  Lib/importlib/util.py                |     2 +
  Lib/test/test_import.py              |     1 -
  Lib/test/test_importlib/test_util.py |   116 +
  Python/importlib.h                   |  7077 ++++++-------
  8 files changed, 3699 insertions(+), 3557 deletions(-)


diff --git a/Doc/library/imp.rst b/Doc/library/imp.rst
--- a/Doc/library/imp.rst
+++ b/Doc/library/imp.rst
@@ -205,6 +205,9 @@
       If :attr:`sys.implementation.cache_tag` is ``None``, then
       :exc:`NotImplementedError` is raised.
 
+   .. deprecated:: 3.4
+      Use :func:`importlib.util.cache_from_source` instead.
+
 
 .. function:: source_from_cache(path)
 
@@ -220,6 +223,9 @@
       Raise :exc:`NotImplementedError` when
       :attr:`sys.implementation.cache_tag` is not defined.
 
+   .. deprecated:: 3.4
+      Use :func:`importlib.util.source_from_cache` instead.
+
 
 .. function:: get_tag()
 
diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst
--- a/Doc/library/importlib.rst
+++ b/Doc/library/importlib.rst
@@ -886,6 +886,36 @@
 
    .. 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)
 
    Resolve a relative module name to an absolute one.
diff --git a/Lib/imp.py b/Lib/imp.py
--- a/Lib/imp.py
+++ b/Lib/imp.py
@@ -17,7 +17,6 @@
     load_dynamic = None
 
 # Directly exposed by this module
-from importlib._bootstrap import new_module
 from importlib._bootstrap import cache_from_source, source_from_cache
 
 
@@ -28,6 +27,7 @@
 import os
 import sys
 import tokenize
+import types
 import warnings
 
 
@@ -44,6 +44,17 @@
 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():
     """**DEPRECATED**
 
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -121,15 +121,6 @@
 _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 ########################################################
 
 # A dict mapping module names to weakrefs of _ModuleLock instances
@@ -509,7 +500,7 @@
             # This must be done before open() is called as the 'io' module
             # implicitly imports 'locale' and would otherwise trigger an
             # 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
             # (otherwise an optimization shortcut in import.c becomes wrong)
             self._module.__initializing__ = True
diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py
--- a/Lib/importlib/util.py
+++ b/Lib/importlib/util.py
@@ -1,9 +1,11 @@
 """Utility code for constructing importers, etc."""
 
 from ._bootstrap import MAGIC_NUMBER
+from ._bootstrap import cache_from_source
 from ._bootstrap import module_to_load
 from ._bootstrap import set_loader
 from ._bootstrap import set_package
+from ._bootstrap import source_from_cache
 from ._bootstrap import _resolve_name
 
 import functools
diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py
--- a/Lib/test/test_import.py
+++ b/Lib/test/test_import.py
@@ -859,7 +859,6 @@
         from importlib import machinery
         mod = sys.modules['_frozen_importlib']
         self.assertIs(machinery.FileFinder, mod.FileFinder)
-        self.assertIs(imp.new_module, mod.new_module)
 
 
 class ImportTracebackTests(unittest.TestCase):
diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py
--- a/Lib/test/test_importlib/test_util.py
+++ b/Lib/test/test_importlib/test_util.py
@@ -1,6 +1,7 @@
 from importlib import util
 from . import util as test_util
 import imp
+import os
 import sys
 from test import support
 import types
@@ -324,5 +325,120 @@
         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__':
     unittest.main()
diff --git a/Python/importlib.h b/Python/importlib.h
--- a/Python/importlib.h
+++ b/Python/importlib.h
[stripped]

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list