From 45a6e879d9a480d4e2de5635904adf314f722c3f Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Wed, 11 Apr 2018 15:09:41 -0400 Subject: [PATCH 1/3] BF: be resilient to optional module non-ImportError exceptions upon import ATM h5py is giving a grief while trying to work on a filesystem without utf-8 encoding support in filenames. --- nibabel/optpkg.py | 11 ++++++++--- nibabel/tests/test_optpkg.py | 7 +++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/nibabel/optpkg.py b/nibabel/optpkg.py index 794960ddc3..cba1fda256 100644 --- a/nibabel/optpkg.py +++ b/nibabel/optpkg.py @@ -94,9 +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: + except ImportError as exc: + pass + except Exception as exc: # it failed to import 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 pass else: # import worked # top level module @@ -111,8 +116,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/tests/test_optpkg.py b/nibabel/tests/test_optpkg.py index 2bca1f6975..cabd226a13 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 @@ -36,6 +37,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('__builtin__.__import__', side_effect=raise_Exception): + assert_bad('nottriedbefore') def test_versions(): From f80e5ceefd253efc58974ed8c4f73db8e112b0ca Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Wed, 11 Apr 2018 21:15:07 -0400 Subject: [PATCH 2/3] BF(PY3): just catch all Exceptions, patch builtins module now provided in py3k --- nibabel/optpkg.py | 7 +++---- nibabel/py3k.py | 3 +++ nibabel/tests/test_optpkg.py | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/nibabel/optpkg.py b/nibabel/optpkg.py index cba1fda256..4bb8a991d7 100644 --- a/nibabel/optpkg.py +++ b/nibabel/optpkg.py @@ -97,12 +97,11 @@ def optional_package(name, trip_msg=None, min_version=None): exc = None try: pkg = __import__(name, fromlist=fromlist) - except ImportError as exc: - pass - except Exception as exc: # it failed to import for some other reason + 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 - pass + exc = exc_ # So it is accessible outside of the code block else: # import worked # top level module if check_version(pkg): diff --git a/nibabel/py3k.py b/nibabel/py3k.py index 1c3300ac91..41a86d31fa 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 + def getexception(): return sys.exc_info()[1] diff --git a/nibabel/tests/test_optpkg.py b/nibabel/tests/test_optpkg.py index cabd226a13..a4c090e1af 100644 --- a/nibabel/tests/test_optpkg.py +++ b/nibabel/tests/test_optpkg.py @@ -11,6 +11,7 @@ assert_equal) +from nibabel.py3k import builtins from nibabel.optpkg import optional_package from nibabel.tripwire import TripWire, TripWireError @@ -41,7 +42,7 @@ 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('__builtin__.__import__', side_effect=raise_Exception): + with mock.patch.object(builtins, '__import__', side_effect=raise_Exception): assert_bad('nottriedbefore') From 2c510181897d1513a9e929eae745e3ac967e344b Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Thu, 12 Apr 2018 09:55:42 -0400 Subject: [PATCH 3/3] BF: flake8 the import --- nibabel/py3k.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nibabel/py3k.py b/nibabel/py3k.py index 41a86d31fa..c132d7809d 100644 --- a/nibabel/py3k.py +++ b/nibabel/py3k.py @@ -67,7 +67,7 @@ def open_latin1(filename, mode='r'): class FileNotFoundError(IOError): pass - import __builtin__ as builtins + import __builtin__ as builtins # flake8: noqa F401 def getexception():