From fd74e35582907607c413d97589851b0bf95ae31c Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Mon, 30 May 2011 17:18:27 +1000 Subject: [PATCH] Add an error_callback parameter to try_import and try_imports --- testtools/helpers.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/testtools/helpers.py b/testtools/helpers.py index 40edfee..3ce8e97 100644 --- a/testtools/helpers.py +++ b/testtools/helpers.py @@ -6,7 +6,7 @@ __all__ = [ ] -def try_import(name, alternative=None): +def try_import(name, alternative=None, error_callback=None): """Attempt to import ``name``. If it fails, return ``alternative``. When supporting multiple versions of Python or optional dependencies, it @@ -16,29 +16,37 @@ def try_import(name, alternative=None): ``os.path.join``. :param alternative: The value to return if no module can be imported. Defaults to None. + :param error_callback: If non-None, a callable that is passed the ImportError + when the module cannot be loaded. """ module_segments = name.split('.') + last_error = None while module_segments: module_name = '.'.join(module_segments) try: module = __import__(module_name) - except ImportError: + except ImportError, e: + last_error = e module_segments.pop() continue else: break else: + if last_error is not None and error_callback is not None: + error_callback(last_error) return alternative nonexistent = object() for segment in name.split('.')[1:]: module = getattr(module, segment, nonexistent) if module is nonexistent: + if last_error is not None and error_callback is not None: + error_callback(last_error) return alternative return module _RAISE_EXCEPTION = object() -def try_imports(module_names, alternative=_RAISE_EXCEPTION): +def try_imports(module_names, alternative=_RAISE_EXCEPTION, error_callback=None): """Attempt to import modules. Tries to import the first module in ``module_names``. If it can be @@ -50,12 +58,14 @@ def try_imports(module_names, alternative=_RAISE_EXCEPTION): :param module_names: A sequence of module names to try to import. :param alternative: The value to return if no module can be imported. If unspecified, we raise an ImportError. + :param error_callback: If None, called with the ImportError for *each* + module that fails to load. :raises ImportError: If none of the modules can be imported and no alternative value was specified. """ module_names = list(module_names) for module_name in module_names: - module = try_import(module_name) + module = try_import(module_name, error_callback=error_callback) if module: return module if alternative is _RAISE_EXCEPTION: