VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE)
+ class _FailedTest(case.TestCase):
+ _testMethodName = None
+
+ def __init__(self, method_name, exception):
+ self._exception = exception
+ super(_FailedTest, self).__init__(method_name)
+
+ def __getattr__(self, name):
+ if name != self._testMethodName:
+ return super(_FailedTest, self).__getattr__(name)
+ def testFailure():
+ raise self._exception
+ return testFailure
+
+
def _make_failed_import_test(name, suiteClass):
- message = 'Failed to import test module: %s\n%s' % (name, traceback.format_exc())
- return _make_failed_test(name, ImportError(message), suiteClass)
+ message = 'Failed to import test module: %s\n%s' % (
+ name, traceback.format_exc())
- return _make_failed_test('ModuleImportFailure', name, ImportError(message),
- suiteClass, message)
++ return _make_failed_test(name, ImportError(message), suiteClass, message)
def _make_failed_load_tests(name, exception, suiteClass):
- return _make_failed_test(name, exception, suiteClass)
+ message = 'Failed to call load_tests:\n%s' % (traceback.format_exc(),)
+ return _make_failed_test(
- 'LoadTestsFailure', name, exception, suiteClass, message)
++ name, exception, suiteClass, message)
- def _make_failed_test(classname, methodname, exception, suiteClass, message):
- def testFailure(self):
- raise exception
- attrs = {methodname: testFailure}
- TestClass = type(classname, (case.TestCase,), attrs)
- return suiteClass((TestClass(methodname),)), message
-def _make_failed_test(methodname, exception, suiteClass):
++def _make_failed_test(methodname, exception, suiteClass, message):
+ test = _FailedTest(methodname, exception)
- return suiteClass((test,))
++ return suiteClass((test,)), message
def _make_skipped_test(methodname, exception, suiteClass):
@case.skip(str(exception))
parts = parts[1:]
obj = module
for part in parts:
- parent, obj = obj, getattr(obj, part)
+ try:
+ parent, obj = obj, getattr(obj, part)
+ except AttributeError as e:
+ # We can't traverse some part of the name.
+ if (getattr(obj, '__path__', None) is not None
+ and error_case is not None):
+ # This is a package (no __path__ per importlib docs), and we
+ # encountered an error importing something. We cannot tell
+ # the difference between package.WrongNameTestClass and
+ # package.wrong_module_name so we just report the
+ # ImportError - it is more informative.
+ self.errors.append(error_message)
+ return error_case
+ else:
+ # Otherwise, we signal that an AttributeError has occurred.
+ error_case, error_message = _make_failed_test(
- 'AttributeError', part, e, self.suiteClass,
++ part, e, self.suiteClass,
+ 'Failed to access attribute:\n%s' % (
+ traceback.format_exc(),))
+ self.errors.append(error_message)
+ return error_case
if isinstance(obj, types.ModuleType):
return self.loadTestsFromModule(obj)
with self.assertRaises(ImportError):
test.test_this_does_not_exist()
+ def test_discover_with_init_modules_that_fail_to_import(self):
+ vfs = {abspath('/foo'): ['my_package'],
+ abspath('/foo/my_package'): ['__init__.py', 'test_module.py']}
+ self.setup_import_issue_package_tests(vfs)
+ import_calls = []
+ def _get_module_from_name(name):
+ import_calls.append(name)
+ raise ImportError("Cannot import Name")
+ loader = unittest.TestLoader()
+ loader._get_module_from_name = _get_module_from_name
+ suite = loader.discover(abspath('/foo'))
+
+ self.assertIn(abspath('/foo'), sys.path)
+ self.assertEqual(suite.countTestCases(), 1)
+ # Errors loading the suite are also captured for introspection.
+ self.assertNotEqual([], loader.errors)
+ self.assertEqual(1, len(loader.errors))
+ error = loader.errors[0]
+ self.assertTrue(
+ 'Failed to import test module: my_package' in error,
+ 'missing error string in %r' % error)
+ test = list(list(suite)[0])[0] # extract test from suite
+ with self.assertRaises(ImportError):
+ test.my_package()
+ self.assertEqual(import_calls, ['my_package'])
+
+ # Check picklability
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ pickle.loads(pickle.dumps(test, proto))
+
def test_discover_with_module_that_raises_SkipTest_on_import(self):
loader = unittest.TestLoader()
suite.run(result)
self.assertEqual(len(result.skipped), 1)
+ # Check picklability
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ pickle.loads(pickle.dumps(suite, proto))
+
+ def test_discover_with_init_module_that_raises_SkipTest_on_import(self):
+ vfs = {abspath('/foo'): ['my_package'],
+ abspath('/foo/my_package'): ['__init__.py', 'test_module.py']}
+ self.setup_import_issue_package_tests(vfs)
+ import_calls = []
+ def _get_module_from_name(name):
+ import_calls.append(name)
+ raise unittest.SkipTest('skipperoo')
+ loader = unittest.TestLoader()
+ loader._get_module_from_name = _get_module_from_name
+ suite = loader.discover(abspath('/foo'))
+
+ self.assertIn(abspath('/foo'), sys.path)
+ self.assertEqual(suite.countTestCases(), 1)
+ result = unittest.TestResult()
+ suite.run(result)
+ self.assertEqual(len(result.skipped), 1)
+ self.assertEqual(result.testsRun, 1)
+ self.assertEqual(import_calls, ['my_package'])
+
++ # Check picklability
++ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
++ pickle.loads(pickle.dumps(suite, proto))
++
def test_command_line_handling_parseArgs(self):
program = TestableTestProgram()
Library
-------
+ - Issue #22903: The fake test case created by unittest.loader when it fails
+ importing a test module is now picklable.
+
+- Issue #22181: On Linux, os.urandom() now uses the new getrandom() syscall if
+ available, syscall introduced in the Linux kernel 3.17. It is more reliable
+ and more secure, because it avoids the need of a file descriptor and waits
+ until the kernel has enough entropy.
+
+- Issue #2211: Updated the implementation of the http.cookies.Morsel class.
+ Setting attributes key, value and coded_value directly now is deprecated.
+ update() and setdefault() now transform and check keys. Comparing for
+ equality now takes into account attributes key, value and coded_value.
+ copy() now returns a Morsel, not a dict. repr() now contains all attributes.
+ Optimized checking keys and quoting values. Added new tests.
+ Original patch by Demian Brecht.
+
+- Issue #18983: Allow selection of output units in timeit.
+ Patch by Julian Gindi.
+
+- Issue #23631: Fix traceback.format_list when a traceback has been mutated.
+
- Issue #23568: Add rdivmod support to MagicMock() objects.
Patch by Håkan Lövdahl.