diff options
author | Robert Collins <rbtcollins@hp.com> | 2014-10-29 19:27:27 (GMT) |
---|---|---|
committer | Robert Collins <rbtcollins@hp.com> | 2014-10-29 19:27:27 (GMT) |
commit | 659dd625b4c3489fbefe9fa866d87bc2b5e14366 (patch) | |
tree | 20fe35b94b5a869c3817810a37fa051af09af73e /Lib/unittest/loader.py | |
parent | c1345840202fed6f1405efec97cd2a147aa5a92e (diff) | |
download | cpython-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.py | 35 |
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) |