[Python-checkins] r71801 - in python/branches/py3k: Doc/library/test.rst Lib/test/support.py Lib/test/test_heapq.py Lib/test/test_warnings.py Misc/NEWS

nick.coghlan python-checkins at python.org
Wed Apr 22 18:13:37 CEST 2009


Author: nick.coghlan
Date: Wed Apr 22 18:13:36 2009
New Revision: 71801

Log:
Merged revisions 71799 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r71799 | nick.coghlan | 2009-04-23 01:26:04 +1000 (Thu, 23 Apr 2009) | 1 line
  
  Issue 5354: Change API for import_fresh_module() to better support test_warnings use case (also fixes some bugs in the original implementation)
........


Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Doc/library/test.rst
   python/branches/py3k/Lib/test/support.py
   python/branches/py3k/Lib/test/test_heapq.py
   python/branches/py3k/Lib/test/test_warnings.py
   python/branches/py3k/Misc/NEWS

Modified: python/branches/py3k/Doc/library/test.rst
==============================================================================
--- python/branches/py3k/Doc/library/test.rst	(original)
+++ python/branches/py3k/Doc/library/test.rst	Wed Apr 22 18:13:36 2009
@@ -8,8 +8,8 @@
 
 
 The :mod:`test` package contains all regression tests for Python as well as the
-modules :mod:`test.test_support` and :mod:`test.regrtest`.
-:mod:`test.test_support` is used to enhance your tests while
+modules :mod:`test.support` and :mod:`test.regrtest`.
+:mod:`test.support` is used to enhance your tests while
 :mod:`test.regrtest` drives the testing suite.
 
 Each module in the :mod:`test` package whose name starts with ``test_`` is a
@@ -47,7 +47,7 @@
 A basic boilerplate is often used::
 
    import unittest
-   from test import test_support
+   from test import support
 
    class MyTestCase1(unittest.TestCase):
 
@@ -75,7 +75,7 @@
    ... more test classes ...
 
    def test_main():
-       test_support.run_unittest(MyTestCase1,
+       support.run_unittest(MyTestCase1,
                                  MyTestCase2,
                                  ... list other tests ...
                                 )
@@ -273,7 +273,7 @@
    following :func:`test_main` function::
 
       def test_main():
-          test_support.run_unittest(__name__)
+          support.run_unittest(__name__)
 
    This will run all tests defined in the named module.
 
@@ -334,15 +334,39 @@
    .. versionadded:: 3.1
 
 
-.. function:: import_fresh_module(name, blocked_names=None, deprecated=False)
+.. function:: import_fresh_module(name, fresh=(), blocked=(), deprecated=False)
 
-   This function imports and returns a fresh copy of the named Python module. The
-   ``sys.modules`` cache is bypassed temporarily, and the ability to import the
-   modules named in *blocked_names* is suppressed for the duration of the import.
+   This function imports and returns a fresh copy of the named Python module
+   by removing the named module from ``sys.modules`` before doing the import.
+   Note that unlike :func:`reload`, the original module is not affected by
+   this operation.
+
+   *fresh* is an iterable of additional module names that are also removed
+   from the ``sys.modules`` cache before doing the import.
+
+   *blocked* is an iterable of module names that are replaced with :const:`0`
+   in the module cache during the import to ensure that attempts to import
+   them raise :exc:`ImportError`.
+
+   The named module and any modules named in the *fresh* and *blocked*
+   parameters are saved before starting the import and then reinserted into
+   ``sys.modules`` when the fresh import is complete.
 
    Module and package deprecation messages are suppressed during this import
    if *deprecated* is :const:`True`.
 
+   This function will raise :exc:`unittest.SkipTest` is the named module
+   cannot be imported.
+
+   Example use::
+
+      # Get copies of the warnings module for testing without
+      # affecting the version being used by the rest of the test suite
+      # One copy uses the C implementation, the other is forced to use
+      # the pure Python fallback implementation
+      py_warnings = import_fresh_module('warnings', blocked=['_warnings'])
+      c_warnings = import_fresh_module('warnings', fresh=['_warnings'])
+
    .. versionadded:: 3.1
 
 

Modified: python/branches/py3k/Lib/test/support.py
==============================================================================
--- python/branches/py3k/Lib/test/support.py	(original)
+++ python/branches/py3k/Lib/test/support.py	Wed Apr 22 18:13:36 2009
@@ -69,12 +69,43 @@
             raise unittest.SkipTest(str(msg))
 
 
-def import_fresh_module(name, blocked_names=None, deprecated=False):
+def _save_and_remove_module(name, orig_modules):
+    """Helper function to save and remove a module from sys.modules
+
+       Return value is True if the module was in sys.modules and
+       False otherwise."""
+    saved = True
+    try:
+        orig_modules[name] = sys.modules[name]
+    except KeyError:
+        saved = False
+    else:
+        del sys.modules[name]
+    return saved
+
+
+def _save_and_block_module(name, orig_modules):
+    """Helper function to save and block a module in sys.modules
+
+       Return value is True if the module was in sys.modules and
+       False otherwise."""
+    saved = True
+    try:
+        orig_modules[name] = sys.modules[name]
+    except KeyError:
+        saved = False
+    sys.modules[name] = 0
+    return saved
+
+
+def import_fresh_module(name, fresh=(), blocked=(), deprecated=False):
     """Imports and returns a module, deliberately bypassing the sys.modules cache
     and importing a fresh copy of the module. Once the import is complete,
     the sys.modules cache is restored to its original state.
 
-    Importing of modules named in blocked_names is prevented while the fresh import
+    Modules named in fresh are also imported anew if needed by the import.
+
+    Importing of modules named in blocked is prevented while the fresh import
     takes place.
 
     If deprecated is True, any module or package deprecation messages
@@ -82,21 +113,24 @@
     # NOTE: test_heapq and test_warnings include extra sanity checks to make
     # sure that this utility function is working as expected
     with _ignore_deprecated_imports(deprecated):
-        if blocked_names is None:
-            blocked_names = ()
+        # Keep track of modules saved for later restoration as well
+        # as those which just need a blocking entry removed
         orig_modules = {}
-        if name in sys.modules:
-            orig_modules[name] = sys.modules[name]
-            del sys.modules[name]
+        names_to_remove = []
+        _save_and_remove_module(name, orig_modules)
         try:
-            for blocked in blocked_names:
-                orig_modules[blocked] = sys.modules[blocked]
-                sys.modules[blocked] = 0
-            py_module = importlib.import_module(name)
+            for fresh_name in fresh:
+                _save_and_remove_module(fresh_name, orig_modules)
+            for blocked_name in blocked:
+                if not _save_and_block_module(blocked_name, orig_modules):
+                    names_to_remove.append(blocked_name)
+            fresh_module = importlib.import_module(name)
         finally:
-            for blocked, module in orig_modules.items():
-                sys.modules[blocked] = module
-        return py_module
+            for orig_name, module in orig_modules.items():
+                sys.modules[orig_name] = module
+            for name_to_remove in names_to_remove:
+                del sys.modules[name_to_remove]
+        return fresh_module
 
 
 def get_attribute(obj, name):

Modified: python/branches/py3k/Lib/test/test_heapq.py
==============================================================================
--- python/branches/py3k/Lib/test/test_heapq.py	(original)
+++ python/branches/py3k/Lib/test/test_heapq.py	Wed Apr 22 18:13:36 2009
@@ -8,7 +8,7 @@
 # We do a bit of trickery here to be able to test both the C implementation
 # and the Python implementation of the module.
 import heapq as c_heapq
-py_heapq = support.import_fresh_module('heapq', ['_heapq'])
+py_heapq = support.import_fresh_module('heapq', blocked=['_heapq'])
 
 class TestHeap(unittest.TestCase):
     module = None

Modified: python/branches/py3k/Lib/test/test_warnings.py
==============================================================================
--- python/branches/py3k/Lib/test/test_warnings.py	(original)
+++ python/branches/py3k/Lib/test/test_warnings.py	Wed Apr 22 18:13:36 2009
@@ -10,14 +10,8 @@
 
 import warnings as original_warnings
 
-py_warnings = support.import_fresh_module('warnings', ['_warnings'])
-# XXX (ncoghlan 20090412):
-# Something in Py3k doesn't like sharing the same instance of
-# _warnings between original_warnings and c_warnings
-# Will leave issue 5354 open until I understand why 3.x breaks
-# without the next line, while 2.x doesn't care
-del sys.modules['_warnings']
-c_warnings = support.import_fresh_module('warnings')
+py_warnings = support.import_fresh_module('warnings', blocked=['_warnings'])
+c_warnings = support.import_fresh_module('warnings', fresh=['_warnings'])
 
 @contextmanager
 def warnings_state(module):

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Wed Apr 22 18:13:36 2009
@@ -98,6 +98,15 @@
 - Issue #5359: Readd the Berkley-DB detection code to allow _dbm be built
   using Berkley-DB.
 
+Tests
+-----
+
+- Issue #5354: New test support function import_fresh_module() makes
+  it easy to import both normal and optimised versions of modules.
+  test_heapq and test_warnings have been adjusted to use it, tests for
+  other modules with both C and Python implementations in the stdlib
+  can be adjusted to use it over time.
+
 
 What's New in Python 3.1 alpha 2?
 =================================


More information about the Python-checkins mailing list