[Python-checkins] r71465 - in python/trunk: Doc/library/test.rst Lib/test/test_heapq.py Lib/test/test_support.py Lib/test/test_warnings.py
nick.coghlan
python-checkins at python.org
Sat Apr 11 15:31:32 CEST 2009
Author: nick.coghlan
Date: Sat Apr 11 15:31:31 2009
New Revision: 71465
Log:
Issue 5251: Provide a standardised testing mechanism for doing fresh imports of modules, including the ability to block extension modules in order to test the pure Python fallbacks
Modified:
python/trunk/Doc/library/test.rst
python/trunk/Lib/test/test_heapq.py
python/trunk/Lib/test/test_support.py
python/trunk/Lib/test/test_warnings.py
Modified: python/trunk/Doc/library/test.rst
==============================================================================
--- python/trunk/Doc/library/test.rst (original)
+++ python/trunk/Doc/library/test.rst Sat Apr 11 15:31:31 2009
@@ -339,6 +339,30 @@
.. versionadded:: 2.6
+.. function:: import_module(name, deprecated=False)
+
+ This function imports and returns the named module. Unlike a normal
+ import, this function raises :exc:`unittest.SkipTest` if the module
+ cannot be imported.
+
+ Module and package deprecation messages are suppressed during this import
+ if *deprecated* is :const:`True`.
+
+ .. versionadded:: 2.7
+
+
+.. function:: import_fresh_module(name, blocked_names=None, 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.
+
+ Module and package deprecation messages are suppressed during this import
+ if *deprecated* is :const:`True`.
+
+ .. versionadded:: 2.7
+
+
The :mod:`test.test_support` module defines the following classes:
.. class:: TransientResource(exc[, **kwargs])
Modified: python/trunk/Lib/test/test_heapq.py
==============================================================================
--- python/trunk/Lib/test/test_heapq.py (original)
+++ python/trunk/Lib/test/test_heapq.py Sat Apr 11 15:31:31 2009
@@ -7,23 +7,8 @@
# We do a bit of trickery here to be able to test both the C implementation
# and the Python implementation of the module.
-
-# Make it impossible to import the C implementation anymore.
-sys.modules['_heapq'] = 0
-# We must also handle the case that heapq was imported before.
-if 'heapq' in sys.modules:
- del sys.modules['heapq']
-
-# Now we can import the module and get the pure Python implementation.
-import heapq as py_heapq
-
-# Restore everything to normal.
-del sys.modules['_heapq']
-del sys.modules['heapq']
-
-# This is now the module with the C implementation.
import heapq as c_heapq
-
+py_heapq = test_support.import_fresh_module('heapq', ['_heapq'])
class TestHeap(unittest.TestCase):
module = None
@@ -193,6 +178,13 @@
class TestHeapPython(TestHeap):
module = py_heapq
+ # As an early adopter, we sanity check the
+ # test_support.import_fresh_module utility function
+ def test_pure_python(self):
+ self.assertFalse(sys.modules['heapq'] is self.module)
+ self.assertTrue(hasattr(self.module.heapify, 'func_code'))
+
+
class TestHeapC(TestHeap):
module = c_heapq
@@ -217,6 +209,12 @@
self.assertEqual(hsort(data, LT), target)
self.assertEqual(hsort(data, LE), target)
+ # As an early adopter, we sanity check the
+ # test_support.import_fresh_module utility function
+ def test_accelerated(self):
+ self.assertTrue(sys.modules['heapq'] is self.module)
+ self.assertFalse(hasattr(self.module.heapify, 'func_code'))
+
#==============================================================================
Modified: python/trunk/Lib/test/test_support.py
==============================================================================
--- python/trunk/Lib/test/test_support.py (original)
+++ python/trunk/Lib/test/test_support.py Sat Apr 11 15:31:31 2009
@@ -42,22 +42,63 @@
and unexpected skips.
"""
+ at contextlib.contextmanager
+def _ignore_deprecated_imports(ignore=True):
+ """Context manager to suppress package and module deprecation
+ warnings when importing them.
+
+ If ignore is False, this context manager has no effect."""
+ if ignore:
+ with warnings.catch_warnings():
+ warnings.filterwarnings("ignore", ".+ (module|package)",
+ DeprecationWarning)
+ yield
+ else:
+ yield
+
+
def import_module(name, deprecated=False):
"""Import and return the module to be tested, raising SkipTest if
it is not available.
If deprecated is True, any module or package deprecation messages
will be suppressed."""
- with warnings.catch_warnings():
- if deprecated:
- warnings.filterwarnings("ignore", ".+ (module|package)",
- DeprecationWarning)
+ with _ignore_deprecated_imports(deprecated):
try:
- module = importlib.import_module(name)
+ return importlib.import_module(name)
except ImportError, msg:
raise unittest.SkipTest(str(msg))
- else:
- return module
+
+
+def import_fresh_module(name, blocked_names=None, 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
+ takes place.
+
+ If deprecated is True, any module or package deprecation messages
+ will be suppressed."""
+ # 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 = ()
+ orig_modules = {}
+ if name in sys.modules:
+ orig_modules[name] = sys.modules[name]
+ del sys.modules[name]
+ try:
+ for blocked in blocked_names:
+ orig_modules[blocked] = sys.modules[blocked]
+ sys.modules[blocked] = 0
+ py_module = importlib.import_module(name)
+ finally:
+ for blocked, module in orig_modules.items():
+ sys.modules[blocked] = module
+ return py_module
+
def get_attribute(obj, name):
"""Get an attribute, raising SkipTest if AttributeError is raised."""
Modified: python/trunk/Lib/test/test_warnings.py
==============================================================================
--- python/trunk/Lib/test/test_warnings.py (original)
+++ python/trunk/Lib/test/test_warnings.py Sat Apr 11 15:31:31 2009
@@ -10,18 +10,8 @@
import warnings as original_warnings
-sys.modules['_warnings'] = 0
-del sys.modules['warnings']
-
-import warnings as py_warnings
-
-del sys.modules['_warnings']
-del sys.modules['warnings']
-
-import warnings as c_warnings
-
-sys.modules['warnings'] = original_warnings
-
+py_warnings = test_support.import_fresh_module('warnings', ['_warnings'])
+c_warnings = test_support.import_fresh_module('warnings')
@contextmanager
def warnings_state(module):
@@ -341,9 +331,21 @@
class CWarnTests(BaseTest, WarnTests):
module = c_warnings
+ # As an early adopter, we sanity check the
+ # test_support.import_fresh_module utility function
+ def test_accelerated(self):
+ self.assertFalse(original_warnings is self.module)
+ self.assertFalse(hasattr(self.module.warn, 'func_code'))
+
class PyWarnTests(BaseTest, WarnTests):
module = py_warnings
+ # As an early adopter, we sanity check the
+ # test_support.import_fresh_module utility function
+ def test_pure_python(self):
+ self.assertFalse(original_warnings is self.module)
+ self.assertTrue(hasattr(self.module.warn, 'func_code'))
+
class WCmdLineTests(unittest.TestCase):
More information about the Python-checkins
mailing list