DefaultTraversable hides the real exception with getattr

Bug #311062 reported by Edwin Grubbs
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Zope 3
Won't Fix
Undecided
Unassigned
zope.traversing
Invalid
Undecided
Unassigned

Bug Description

zope.traversing.adapters.DefaultTraversable.traverse() uses getattr() with a default value that hides the real exception. It should call getattr() without a default value, so that it can log the actual error that occurs.

Traceback (most recent call last):
  File "/home/egrubbs/canonical/lp-branches/trunk/utilities/../lib/zope/publisher/publish.py", line 133, in publish
    result = publication.callObject(request, obj)
  File "/home/egrubbs/canonical/lp-branches/bug-174468-milestone-release-overlap/lib/canonical/launchpad/webapp/publication.py", line 341, in callObject
    return mapply(ob, request.getPositionalArguments(), request)
  File "/home/egrubbs/canonical/lp-branches/trunk/utilities/../lib/zope/publisher/publish.py", line 108, in mapply
    return debug_call(obj, args)
  File "/home/egrubbs/canonical/lp-branches/trunk/utilities/../lib/zope/publisher/publish.py", line 114, in debug_call
    return obj(*args)
  File "/home/egrubbs/canonical/lp-branches/bug-174468-milestone-release-overlap/lib/canonical/launchpad/webapp/publisher.py", line 224, in __call__
    return self.render()
  File "/home/egrubbs/canonical/lp-branches/bug-174468-milestone-release-overlap/lib/canonical/launchpad/webapp/publisher.py", line 209, in render
    return self.template()
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/app/pagetemplate/viewpagetemplatefile.py", line 83, in __call__
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/app/pagetemplate/viewpagetemplatefile.py", line 51, in __call__
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/pagetemplate/pagetemplate.py", line 115, in pt_render
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 271, in __call__
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 891, in do_useMacro
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 536, in do_optTag_tal
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 521, in do_optTag
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 516, in no_tag
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 855, in do_condition
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 855, in do_condition
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 536, in do_optTag_tal
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 521, in do_optTag
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 516, in no_tag
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 949, in do_defineSlot
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 822, in do_loop_tal
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/tales.py", line 682, in setRepeat
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/tales.py", line 696, in evaluate
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/expressions.py", line 217, in __call__
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/expressions.py", line 194, in _eval
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/expressions.py", line 124, in _eval
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/app/pagetemplate/engine.py", line 68, in __call__
  File "/home/egrubbs/canonical/lp-branches/trunk/utilities/../lib/zope/traversing/adapters.py", line 164, in traversePathElement
    return traversable.traverse(nm, further_path)
  File "/home/egrubbs/canonical/lp-branches/trunk/utilities/../lib/zope/traversing/adapters.py", line 52, in traverse
    raise TraversalError(subject, name)
TraversalError: (<zope.app.pagetemplate.simpleviewclass.SimpleViewClass from /home/egrubbs/canonical/lp-branches/bug-174468-milestone-release-overlap/lib/canonical/launchpad/templates/product-index.pt object at 0xcb7c3cc>, 'sorted_series_list')
------
2008-12-23T18:13:46 ERROR SiteError https://launchpad.dev/bzr/+index
Traceback (most recent call last):
  File "/home/egrubbs/canonical/lp-branches/trunk/utilities/../lib/zope/publisher/publish.py", line 133, in publish
    result = publication.callObject(request, obj)
  File "/home/egrubbs/canonical/lp-branches/bug-174468-milestone-release-overlap/lib/canonical/launchpad/webapp/publication.py", line 341, in callObject
    return mapply(ob, request.getPositionalArguments(), request)
  File "/home/egrubbs/canonical/lp-branches/trunk/utilities/../lib/zope/publisher/publish.py", line 108, in mapply
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/app/pagetemplate/viewpagetemplatefile.py", line 51, in __call__
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/pagetemplate/pagetemplate.py", line 115, in pt_render
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 271, in __call__
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 891, in do_useMacro
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 536, in do_optTag_tal
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 521, in do_optTag
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 516, in no_tag
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 855, in do_condition
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 855, in do_condition
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 536, in do_optTag_tal
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 521, in do_optTag
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 516, in no_tag
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 949, in do_defineSlot
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 346, in interpret
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tal/talinterpreter.py", line 822, in do_loop_tal
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/tales.py", line 682, in setRepeat
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/tales.py", line 696, in evaluate
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/expressions.py", line 217, in __call__
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/expressions.py", line 194, in _eval
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/tales/expressions.py", line 124, in _eval
  File "/home/egrubbs/canonical/lp-branches/new-project-bug-256442/lib/zope/app/pagetemplate/engine.py", line 68, in __call__
  File "/home/egrubbs/canonical/lp-branches/trunk/utilities/../lib/zope/traversing/adapters.py", line 164, in traversePathElement
    return traversable.traverse(nm, further_path)
  File "/home/egrubbs/canonical/lp-branches/trunk/utilities/../lib/zope/traversing/adapters.py", line 52, in traverse
    raise TraversalError(subject, name)
TraversalError: (<zope.app.pagetemplate.simpleviewclass.SimpleViewClass from /home/egrubbs/canonical/lp-branches/bug-174468-milestone-release-overlap/lib/canonical/launchpad/templates/product-index.pt object at 0xcb7c3cc>, 'sorted_series_list')

Revision history for this message
Philipp von Weitershausen (philikon) wrote : Re: [Bug 311062] [NEW] DefaultTraversable hides the real exception with getattr

On Dec 24, 2008, at 1:18 AM, Edwin Grubbs wrote:
> zope.traversing.adapters.DefaultTraversable.traverse() uses getattr()
> with a default value that hides the real exception. It should call
> getattr() without a default value, so that it can log the actual error
> that occurs.

To my knowledge, getattr(obj, attr, default) will only "eat"
AttributeErrors. If an AttributeError occurs, it'll return the
default. Any other exception should be penetrate to the caller without
any problems. I think this behaviour makes a lot of sense.

So if you're experiencing that getattr() hides a "real" exception in
the code, it seems to me that this exception must be an
AttributeError. But then you'd be out of luck if getattr() didn't use
a default value, because then DeafultTraversable.traverse() would have
to do something like:

   try:
       subobj = getattr(obj, attr)
   except AttributeError:
       ... do something else

So your exception wouldn't be visible anyways.

Revision history for this message
Edwin Grubbs (edwin-grubbs) wrote :

On Wed, Dec 24, 2008 at 6:10 AM, Philipp von Weitershausen
<email address hidden> wrote:
> To my knowledge, getattr(obj, attr, default) will only "eat"
> AttributeErrors. If an AttributeError occurs, it'll return the
> default. Any other exception should be penetrate to the caller without
> any problems. I think this behaviour makes a lot of sense.
>
> So if you're experiencing that getattr() hides a "real" exception in
> the code, it seems to me that this exception must be an
> AttributeError. But then you'd be out of luck if getattr() didn't use
> a default value, because then DeafultTraversable.traverse() would have
> to do something like:
>
> try:
> subobj = getattr(obj, attr)
> except AttributeError:
> ... do something else
>
> So your exception wouldn't be visible anyways.

It's fine that it doesn't allow the AttributeError to percolate up,
but it is not fine that it doesn't log any information about the
exception that it is catching. It is assuming that the AttributeError
just means that the attribute getattr is trying to access doesn't
exist. If the code for a property fails while accessing some other
objects attribute, it would be very useful to see the original
traceback in the log. Instead, I have to add pdb.set_trace()
inside the property that is failing and restart zope. The only
benefit to not logging the traceback from the original exception
is that it makes the error message shorter, which seems hardly
worth it.

Tres Seaver (tseaver)
Changed in zope3:
status: New → Won't Fix
Revision history for this message
Jean Jordaan (jean-jordaan) wrote :

Edwin explained this again on [zope-dev]. It does indeed seem a lot clearer than the above ;-)
So I'm adding his explanation from the list:

The most common confusing error that I encounter is when some
underlying code has an AttributeError, but zope's traversal code
doesn't tell me about that exception, it just tells me that the
attribute several layers up could not be traversed.

For example, there is a bug in a function like this:

def format_data(foo):
   return "%d: %s" % (foo.id, foo.name)

def baz(foo_id):
   foo = load_foo(foo_id)
   return format_data(foo)

class FooView:
   @property
   def my_foo(self):
        return baz(self.context.foo_id)

When the template tries to traverse view/my_foo, if foo doesn't have
the "name" attribute, it fails, but it only tells you that my_foo
couldn't be found on the view. I used to spend quite a bit of time
trying to figure out whether I changed some configuration that caused
this error. If the attribute was on a context object with a security
wrapper, I would be checking that also. Now, I usually recognize that
I have to add pdb.set_trace() inside of my_foo so that I can see where
the AttributeError is really raised.

Revision history for this message
Colin Watson (cjwatson) wrote :

The zope.traversing project on Launchpad has been archived at the request of the Zope developers (see https://answers.launchpad.net/launchpad/+question/683589 and https://answers.launchpad.net/launchpad/+question/685285). If this bug is still relevant, please refile it at https://github.com/zopefoundation/zope.traversing.

Changed in zope.traversing:
status: New → Invalid
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.