On Wed, May 3, 2017 at 10:59 AM, Jason Maldonis <jjmaldo...@gmail.com> wrote: > Here's an example where the underlying error is completely hidden: > > class A(object): > def _some_complex_code_hidden_from_the_user(self): > # Run a bunch of complex stuff that raises an attribute error > internally > # This could go layers deep into different modules > return self.this_doesnt_exist > > @property > def x(self): > return self._some_complex_code_hidden_from_the_user() > > def __getattr__(self, attr): > raise AttributeError("raised from A.__getattr__ to stop execution") > > a = A() > print(a.x) > > > This results in the following output: > > Traceback (most recent call last): > File "test3.py", line 17, in <module> > print(a.x) > File "test3.py", line 14, in __getattr__ > raise AttributeError("raised from A.__getattr__ to stop execution") > AttributeError: raised from A.__getattr__ to stop execution
AIUI, the problem here is that a property function that leaks an AttributeError looks like a missing property and calls __getattr__. Is that correct? What you could do is put in a little guard decorator. Basically, mark this function as "should never raise AttributeError": def wont_raise(*exc): def deco(func): @functools.wraps(func) def wrapper(*a, **kw): try: return func(*a, **kw) except exc as e: raise RuntimeError("Faulty exception raised") from e # Note that in Py2, you may want manual exception chaining # to avoid losing the original (this uses Py3's __cause__). return wrapper return deco class A: @property @wont_raise(AttributeError) def x(self): return self._x def __getattr__(self, attr): raise AttributeError("raised from A.__getattr__ to stop execution") >>> A().x Traceback (most recent call last): File "<stdin>", line 6, in wrapper File "<stdin>", line 5, in x File "<stdin>", line 7, in __getattr__ AttributeError: raised from A.__getattr__ to stop execution The above exception was the direct cause of the following exception: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 8, in wrapper RuntimeError: Faulty exception raised You now have the entire exception traceback. ChrisA -- https://mail.python.org/mailman/listinfo/python-list