Kaydet (Commit) fce769e7 authored tarafından Nick Coghlan's avatar Nick Coghlan

Merged revisions 71465 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r71465 | nick.coghlan | 2009-04-11 23:31:31 +1000 (Sat, 11 Apr 2009) | 1 line

  Issue 5354: 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
........
üst 2d87e429
......@@ -322,6 +322,30 @@ The :mod:`test.support` module defines the following functions:
assert s.getvalue() == "hello"
.. 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:: 3.1
.. 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:: 3.1
The :mod:`test.support` module defines the following classes:
.. class:: TransientResource(exc[, **kwargs])
......
......@@ -41,22 +41,63 @@ class ResourceDenied(unittest.SkipTest):
and unexpected skips.
"""
@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 as 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."""
......
......@@ -7,23 +7,8 @@ import sys
# 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 = support.import_fresh_module('heapq', ['_heapq'])
class TestHeap(unittest.TestCase):
module = None
......@@ -194,6 +179,13 @@ class TestHeap(unittest.TestCase):
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, '__code__'))
class TestHeapC(TestHeap):
module = c_heapq
......@@ -219,6 +211,12 @@ class TestHeapC(TestHeap):
self.assertEqual(hsort(data, LT), target)
self.assertRaises(TypeError, data, LE)
# 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, '__code__'))
#==============================================================================
......
......@@ -10,18 +10,14 @@ from test import warning_tests
import warnings as original_warnings
sys.modules['_warnings'] = 0
del sys.modules['warnings']
import warnings as py_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']
del sys.modules['warnings']
import warnings as c_warnings
sys.modules['warnings'] = original_warnings
c_warnings = support.import_fresh_module('warnings')
@contextmanager
def warnings_state(module):
......@@ -351,9 +347,21 @@ class WarnTests(unittest.TestCase):
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, '__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, '__code__'))
class WCmdLineTests(unittest.TestCase):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment