On 2017-07-05 04:36, Steven D'Aprano wrote:
On Tue, Jul 04, 2017 at 11:37:51PM -0400, Terry Reedy wrote:

I personally been on the side of wanting richer exceptions.

Could you explain what you would use them for? Ken has give two
use-cases which I personally consider are relatively niche, and perhaps
even counter-productive:

- translation into the user's native language;

- providing some sort of "did you mean...?" functionality.

I'm not the one you were replying to, but I just consider it useful debugging information that reduces the work required to track down errors. Suppose I have code like this:

for item in blah:
     do_stuff(item)

def do_stuff(item):
    foo = item['bar']
    do_other_stuff(foo)

# etc., then 10 functions down the call stack. . .

def do_yet_additional_stuff(whatever):
     x = whatever['yadda']

Now I get a KeyError exception in do_yet_additional_stuff. If the object on which the key was not found ("whatever" here) is stored as an attribute of the exception, I can put a try/except in any function in the call stack and still have access to the object that caused the exception further down. This makes it easier to try out hypotheses about what's causing the error. ("Hmmm, I know that in do_stuff it reads the 'bar', attribute, maybe if that value is negative it's resulting in a NaN later on. . .") If the object is not available as an exception attribute, I have to start by going all the way to the bottom of the call stack (to do_yet_additional_stuff) and either creating my own custom exception that does store the object (thus implementing this attribute-rich exception myself) or slowly working my way back up the call stack. Having the object available on the exception is like having your finger in the pages of a book to hold the place where the exception actually occurred, while still being able to flip back and forth to other sections of the call stack to try to figure out how they're leading to that exception.

A related use is when the exception is already caught and logged or handled somewhere higher up. It makes it easier to log messages like "AttributeError was raised when foo had item=-10.345", or to conditionally handle exceptions based on such information, without requiring extra instrumentation elsewhere in the code.

I realize this isn't a life-and-death use case, but to be frank I don't really see that the objections are that strong either. So far I've seen "You don't really need that information", "You don't need that information if you're using exceptions for flow control" and "There might theoretically be a performance penalty of unknown significance". (I seem to recall seeing something like "exceptions aren't supposed to be debugging tools" in an earlier discussion about this, and I basically just disagree with that one.)

Now, obviously there is the generic burden-of-proof argument that the suggestion doesn't meet the bar for changing the status quo, and that's as may be, but that's different from there being no use case. It also doesn't necessarily rule out a potential resolution like "okay, this isn't urgent, but let's try to clean this up gradually as we move forward, by adding useful info to exceptions where possible".

That said, I think this use case of mine is on a different track from where most of the discussion in this thread seems to have gone. For one thing, I agree with you that NameError is a particularly odd exception to pick as the poster child for rich exceptions, because NameError is almost always raised in response to a variable name that's typed literally in the code, so it's much less likely to result in the kind of situation I described above, where the true cause of an exception is far away in the call stack from the point where it's raised.

I also agree that it is much better to have the information available as named attributes on the exception rather than accessing them positionally with something like exception.args[1]. In fact I agree so much that basically what I'm saying is that all exceptions as much as possible should store relevant information in such attributes rather than putting it ONLY into the message string.

Also, in the situation I'm describing, I'm not particularly attached to the idea that the "rich" information would even have to be part of the exception message at all by default (since the object might have a long __str__ that would be irritating). It would just be there, attached to the exception, so that it could be used if needed.

--
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail."
   --author unknown
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to