summaryrefslogtreecommitdiffstats
path: root/Lib/unittest/loader.py
diff options
context:
space:
mode:
authorRobert Collins <rbtcollins@hp.com>2014-10-29 19:27:27 (GMT)
committerRobert Collins <rbtcollins@hp.com>2014-10-29 19:27:27 (GMT)
commit659dd625b4c3489fbefe9fa866d87bc2b5e14366 (patch)
tree20fe35b94b5a869c3817810a37fa051af09af73e /Lib/unittest/loader.py
parentc1345840202fed6f1405efec97cd2a147aa5a92e (diff)
downloadcpython-659dd625b4c3489fbefe9fa866d87bc2b5e14366.zip
cpython-659dd625b4c3489fbefe9fa866d87bc2b5e14366.tar.gz
cpython-659dd625b4c3489fbefe9fa866d87bc2b5e14366.tar.bz2
Close #7559: ImportError when loading a test now shown as ImportError.
Previously the ImportError was only shown if the top level containing package failed to import, with other ImportErrors showing up as AttributeError - hiding the real cause. As part of this, `TestLoader.loadTestsFromNames` now captures errors to self.errors.
Diffstat (limited to 'Lib/unittest/loader.py')
-rw-r--r--Lib/unittest/loader.py35
1 files changed, 31 insertions, 4 deletions
diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py
index aaee52a..811bedf 100644
--- a/Lib/unittest/loader.py
+++ b/Lib/unittest/loader.py
@@ -130,20 +130,47 @@ class TestLoader(object):
The method optionally resolves the names relative to a given module.
"""
parts = name.split('.')
+ error_case, error_message = None, None
if module is None:
parts_copy = parts[:]
while parts_copy:
try:
- module = __import__('.'.join(parts_copy))
+ module_name = '.'.join(parts_copy)
+ module = __import__(module_name)
break
except ImportError:
- del parts_copy[-1]
+ next_attribute = parts_copy.pop()
+ # Last error so we can give it to the user if needed.
+ error_case, error_message = _make_failed_import_test(
+ next_attribute, self.suiteClass)
if not parts_copy:
- raise
+ # Even the top level import failed: report that error.
+ self.errors.append(error_message)
+ return error_case
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,
+ '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)