__getattribute__'s error is not available in __getattr__

Ethan Furman ethan at stoneleaf.us
Tue May 2 22:37:13 EDT 2017


On 05/02/2017 05:59 PM, Jason Maldonis wrote:

> @Steve they asked me to move it here because it was more fitting. I hope that's okay?

Yes, it's okay.  ;)

> After some testing, it looks like I'm okay with how things work if the problem-object isn't a descriptor (although I do
> still things it's a bit odd that an error gets squashed, but it's no big deal).
>
> However, I use @property all the time, so that's likely why I'm running into this so often.  If you can help explain to
> me what's going on in that case, that would be great!  I have two examples below for the sake of discussion.
>
> 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
>
>
> Here the real reason the code errors (`sys.this_doesnt_exist` throwing an AttributeError) is not in the traceback's stack.

The problem is that Python cannot tell the difference between `A.x` not existing (which would raise AttributeError), and 
some attribute inside `A.x` not existing (which also raises AttributeError).

There's an issue to fix this somewhere in the Python Bug Tracker (bugs.python.org) but I cannot find it at the moment 
(it's quite old).

> My current opinion on this is that the error that triggered __getattr__ should be passed to __getattr__. This would
> allow us to use the "raise from" syntax.

Hmm.  Since the other issue isn't making any headway this might be the best we get -- you should open a thread for it 
over at Python Ideas.  :)

Until then Chris' decorator is probably the easiest work around -- but you should only catch AttributeError, not everything.

--
~Ethan~



More information about the Python-list mailing list