diff --git a/nibabel/optpkg.py b/nibabel/optpkg.py index 794960ddc3..4bb8a991d7 100644 --- a/nibabel/optpkg.py +++ b/nibabel/optpkg.py @@ -94,10 +94,14 @@ def optional_package(name, trip_msg=None, min_version=None): # fromlist=[''] results in submodule being returned, rather than the top # level module. See help(__import__) fromlist = [''] if '.' in name else [] + exc = None try: pkg = __import__(name, fromlist=fromlist) - except ImportError: - pass + except Exception as exc_: + # Could fail due to some ImportError or for some other reason + # e.g. h5py might have been checking file system to support UTF-8 + # etc. We should not blow if they blow + exc = exc_ # So it is accessible outside of the code block else: # import worked # top level module if check_version(pkg): @@ -111,8 +115,8 @@ def optional_package(name, trip_msg=None, min_version=None): (name, min_version)) if trip_msg is None: trip_msg = ('We need package %s for these functions, but ' - '``import %s`` raised an ImportError' - % (name, name)) + '``import %s`` raised %s' + % (name, name, exc)) pkg = TripWire(trip_msg) def setup_module(): diff --git a/nibabel/py3k.py b/nibabel/py3k.py index 1c3300ac91..c132d7809d 100644 --- a/nibabel/py3k.py +++ b/nibabel/py3k.py @@ -41,6 +41,7 @@ def open_latin1(filename, mode='r'): ints2bytes = lambda seq: bytes(seq) ZEROB = bytes([0]) FileNotFoundError = FileNotFoundError + import builtins else: import StringIO StringIO = BytesIO = StringIO.StringIO @@ -66,6 +67,8 @@ def open_latin1(filename, mode='r'): class FileNotFoundError(IOError): pass + import __builtin__ as builtins # flake8: noqa F401 + def getexception(): return sys.exc_info()[1] diff --git a/nibabel/tests/test_optpkg.py b/nibabel/tests/test_optpkg.py index 2bca1f6975..a4c090e1af 100644 --- a/nibabel/tests/test_optpkg.py +++ b/nibabel/tests/test_optpkg.py @@ -1,6 +1,7 @@ """ Testing optpkg module """ +import mock import types import sys from distutils.version import LooseVersion @@ -10,6 +11,7 @@ assert_equal) +from nibabel.py3k import builtins from nibabel.optpkg import optional_package from nibabel.tripwire import TripWire, TripWireError @@ -36,6 +38,12 @@ def test_basic(): assert_good('os.path') # We never have package _not_a_package assert_bad('_not_a_package') + def raise_Exception(*args, **kwargs): + raise Exception( + "non ImportError could be thrown by some malfunctioning module " + "upon import, and optional_package should catch it too") + with mock.patch.object(builtins, '__import__', side_effect=raise_Exception): + assert_bad('nottriedbefore') def test_versions():