Skip to content

Commit d833779

Browse files
committed
Issue python#22903: The fake test case created by unittest.loader when it fails importing a test module is now picklable.
1 parent c4c19b3 commit d833779

File tree

3 files changed

+32
-9
lines changed

3 files changed

+32
-9
lines changed

Lib/unittest/loader.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,31 @@
1919
VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE)
2020

2121

22+
class _FailedTest(case.TestCase):
23+
_testMethodName = None
24+
25+
def __init__(self, method_name, exception):
26+
self._exception = exception
27+
super(_FailedTest, self).__init__(method_name)
28+
29+
def __getattr__(self, name):
30+
if name != self._testMethodName:
31+
return super(_FailedTest, self).__getattr__(name)
32+
def testFailure():
33+
raise self._exception
34+
return testFailure
35+
36+
2237
def _make_failed_import_test(name, suiteClass):
2338
message = 'Failed to import test module: %s\n%s' % (name, traceback.format_exc())
24-
return _make_failed_test('ModuleImportFailure', name, ImportError(message),
25-
suiteClass)
39+
return _make_failed_test(name, ImportError(message), suiteClass)
2640

2741
def _make_failed_load_tests(name, exception, suiteClass):
28-
return _make_failed_test('LoadTestsFailure', name, exception, suiteClass)
42+
return _make_failed_test(name, exception, suiteClass)
2943

30-
def _make_failed_test(classname, methodname, exception, suiteClass):
31-
def testFailure(self):
32-
raise exception
33-
attrs = {methodname: testFailure}
34-
TestClass = type(classname, (case.TestCase,), attrs)
35-
return suiteClass((TestClass(methodname),))
44+
def _make_failed_test(methodname, exception, suiteClass):
45+
test = _FailedTest(methodname, exception)
46+
return suiteClass((test,))
3647

3748
def _make_skipped_test(methodname, exception, suiteClass):
3849
@case.skip(str(exception))

Lib/unittest/test/test_discovery.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import re
33
import sys
44
import types
5+
import pickle
56
import builtins
67
from test import support
78

@@ -216,6 +217,10 @@ def test_discover_with_modules_that_fail_to_import(self):
216217
with self.assertRaises(ImportError):
217218
test.test_this_does_not_exist()
218219

220+
# Check picklability
221+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
222+
pickle.loads(pickle.dumps(test, proto))
223+
219224
def test_discover_with_module_that_raises_SkipTest_on_import(self):
220225
loader = unittest.TestLoader()
221226

@@ -232,6 +237,10 @@ def _get_module_from_name(name):
232237
suite.run(result)
233238
self.assertEqual(len(result.skipped), 1)
234239

240+
# Check picklability
241+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
242+
pickle.loads(pickle.dumps(suite, proto))
243+
235244
def test_command_line_handling_parseArgs(self):
236245
program = TestableTestProgram()
237246

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ Core and Builtins
1818
Library
1919
-------
2020

21+
- Issue #22903: The fake test case created by unittest.loader when it fails
22+
importing a test module is now picklable.
23+
2124
- Issue #23568: Add rdivmod support to MagicMock() objects.
2225
Patch by Håkan Lövdahl.
2326

0 commit comments

Comments
 (0)