Gotcha I never ran into before

B

Brian Cole

I've been programming in Python for about 6 years now. One of the
features I adore the most is the very useful error messages and stack
traces that make it easy to debug. However, today I ran into a
difficult to trace bug because the stack trace was reporting the
problem in the wrong place.

class Delegator(object):
def __init__(self, obj):
self.obj = obj
def __getattr__(self, attr):
return getattr(self.obj, attr)

class SpecializedDelegator(Delegator):
def get_blah(self):
return ["Returning Blah"].upper()
blah = property(fget=get_blah)

print SpecializedDelegator("Doesn't Matter").blah

The stack trace is:
Traceback (most recent call last):
File "test.py", line 12, in ?
print SpecializedDelegator("Doesn't Matter").blah
File "test.py", line 5, in __getattr__
return getattr(self.obj, attr)
AttributeError: 'str' object has no attribute 'blah'

Which is correct, but says nothing about the real problem inside the
get_blah method. Is there a good reason that when a property's fget
function throws an AttributeError that it should fall back on
__getattr__? I would think since the attribute was explicitly defined
as a property the property function should be allowed to fully crash
and burn.

Note: This example is broken up into two classes because that is how I
discovered it. Since both classes were in separate files it added to
the agony of debugging this. Luckily I was making a small incremental
change so I could just back up and figure out what went wrong.

Thanks,
Brian
 
J

James Stroud

Brian said:
I've been programming in Python for about 6 years now. One of the
features I adore the most is the very useful error messages and stack
traces that make it easy to debug. However, today I ran into a
difficult to trace bug because the stack trace was reporting the
problem in the wrong place.

class Delegator(object):
def __init__(self, obj):
self.obj = obj
def __getattr__(self, attr):
return getattr(self.obj, attr)

class SpecializedDelegator(Delegator):
def get_blah(self):
return ["Returning Blah"].upper()
blah = property(fget=get_blah)

print SpecializedDelegator("Doesn't Matter").blah

The stack trace is:
Traceback (most recent call last):
File "test.py", line 12, in ?
print SpecializedDelegator("Doesn't Matter").blah
File "test.py", line 5, in __getattr__
return getattr(self.obj, attr)
AttributeError: 'str' object has no attribute 'blah'

Which is correct, but says nothing about the real problem inside the
get_blah method. Is there a good reason that when a property's fget
function throws an AttributeError that it should fall back on
__getattr__? I would think since the attribute was explicitly defined
as a property the property function should be allowed to fully crash
and burn.

Note: This example is broken up into two classes because that is how I
discovered it. Since both classes were in separate files it added to
the agony of debugging this. Luckily I was making a small incremental
change so I could just back up and figure out what went wrong.

Thanks,
Brian

Your __getattr__ in in Delegator is circumventing the property in
SpecializedDelegator:

py> class Delegator(object):
.... def __init__(self, obj):
.... self.obj = obj
.... def __getattr__(self, attr):
.... return getattr(self.obj, attr)
....
py> class SpecializedDelegator(Delegator):
.... def get_blah(self):
.... return ["Returning Blah"].upper()
.... blah = property(fget=get_blah)
....
py> print SpecializedDelegator("Doesn't Matter").blah
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
File "<ipython console>", line 5, in __getattr__
<type 'exceptions.AttributeError'>: 'str' object has no attribute 'blah'

py> class Delegator(object):
.... def __init__(self, obj):
.... self.obj = obj
.... def __getattr__(self, attr):
.... if hasattr(self.obj, attr):
.... return getattr(self.obj, attr)
.... else:
.... return self.__getattribute__(attr)
....
py> class SpecializedDelegator(Delegator):
.... def get_blah(self):
.... return ["Returning Blah"].upper()
.... blah = property(fget=get_blah)
....
py> print SpecializedDelegator("Doesn't Matter").blah
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
File "<ipython console>", line 8, in __getattr__
File "<ipython console>", line 3, in get_blah
<type 'exceptions.AttributeError'>: 'list' object has no attribute 'upper'


James

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,970
Messages
2,570,162
Members
46,710
Latest member
bernietqt

Latest Threads

Top