From e96a93656b7efa40c9f49b9240b3ecce6a0f1a2a Mon Sep 17 00:00:00 2001 From: Stephan Hoyer Date: Tue, 2 Aug 2016 08:56:47 -0700 Subject: [PATCH] Fix silently ignored AttributeError in custom accessors Fixes GH933 --- xarray/core/extensions.py | 14 +++++++++++++- xarray/test/test_extensions.py | 11 +++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/xarray/core/extensions.py b/xarray/core/extensions.py index 5df1e73868d..0fa40f5e3f4 100644 --- a/xarray/core/extensions.py +++ b/xarray/core/extensions.py @@ -1,5 +1,8 @@ +import traceback + from .dataarray import DataArray from .dataset import Dataset +from .pycompat import PY2 class AccessorRegistrationError(Exception): @@ -16,7 +19,16 @@ def __get__(self, obj, cls): if obj is None: # we're accessing the attribute of the class, i.e., Dataset.geo return self._accessor - accessor_obj = self._accessor(obj) + try: + accessor_obj = self._accessor(obj) + except AttributeError: + # __getattr__ on data object will swallow any AttributeErrors raised + # when initializing the accessor, so we need to raise as something + # else (GH933): + msg = 'error initializing %r accessor.' % self._name + if PY2: + msg += ' Full traceback:\n' + traceback.format_exc() + raise RuntimeError(msg) # Replace the property with the accessor object. Inspired by: # http://www.pydanny.com/cached-property.html # We need to use object.__setattr__ because we overwrite __setattr__ on diff --git a/xarray/test/test_extensions.py b/xarray/test/test_extensions.py index 7a751ea87bd..fd843418d3b 100644 --- a/xarray/test/test_extensions.py +++ b/xarray/test/test_extensions.py @@ -74,3 +74,14 @@ def test_pickle_dataarray(self): assert array.example_accessor is array.example_accessor array_restored = pickle.loads(pickle.dumps(array)) assert array.identical(array_restored) + + def test_broken_accessor(self): + # regression test for GH933 + + @xr.register_dataset_accessor('stupid_accessor') + class BrokenAccessor(object): + def __init__(self, xarray_obj): + raise AttributeError('broken') + + with self.assertRaisesRegexp(RuntimeError, 'error initializing'): + xr.Dataset().stupid_accessor