[Python-ideas] Arguments to exceptions

Paul Moore p.f.moore at gmail.com
Mon Jul 3 05:37:25 EDT 2017

On 3 July 2017 at 09:59, Ken Kundert <python-ideas at shalmirane.com> wrote:
> I think in trying to illustrate the existing behavior I made things more
> confusing than they needed to be.  Let me try again.
> Consider this code.
>     >>> import Food
>     >>> try:
>     ...     import meals
>     ... except NameError as e:
>     ...     name = str(e).split("'")[1]   # <-- fragile code
>     ...     from difflib import get_close_matches
>     ...     candidates = ', '.join(get_close_matches(name, Food.foods, 1, 0.6))
>     ...     print(f'{name}: not found. Did you mean {candidates}?')
> In this case *meals* instantiates a collection of foods. It is a Python file,
> but it is also a data file (in this case the user knows Python, so Python is
> a convenient data format). In that file thousands of foods may be instantiated.
> If the user misspells a food, I would like to present the available
> alternatives. To do so, I need the misspelled name.  The only way I can get it
> is by parsing the error message.

As Steven pointed out, this is a pretty good example of a code smell.
My feeling is that you may have just proved that Python isn't quite as
good a fit for your data file format as you thought - or that your
design has flaws. Suppose your user had a breakfast menu, and did
something like:

    if now < lunchtim: # Should have been "lunchtime"

Your error handling will be fairly confusing in that case.

> That is the problem.  To write the error handler, I need the misspelled name.
> The only way to get it is to extract it from the error message. The need to
> unpack information that was just packed suggests that the packing was done too
> early.  That is my point.

I don't have any problem with *having* the misspelled name as an
attribute to the error, I just don't think it's going to be as useful
as you hope, and it may indeed (as above) encourage people to use it
without thinking about whether there might be problems with using
error handling that way.

> Fundamentally, pulling the name out of an error message is a really bad coding
> practice because it is fragile.  The code will likely break if the formatting or
> the wording of the message changes.  But given the way the exception was
> implemented, I am forced to choose between two unpleasant choices: pulling the
> name from the error message or not giving the enhanced message at all.

Or using a different approach. ("Among our different approaches...!"
:-)) Agreed that's also an unpleasant choice at this point.

> What I am hoping to do with this proposal is to get the Python developer
> community to see that:
> 1. The code that handles the exception benefits from having access to the
>    components of the error message.  In the least it can present the message to
>    the user is the best possible way. Perhaps that means enforcing a particular
>    style, or presenting it in the user's native language, or perhaps it means
>    providing additional related information as in the example above.

I see it as a minor bug magnet, but not really a problem in principle.

> 2. The current approach to exceptions follows the opposite philosophy,
>    suggesting that the best place to construct the error message is at the
>    source of the error. It inadvertently puts obstacles in place that make it
>    difficult to customize the message in the handler.

It's more about implicitly enforcing the policy of "catch errors over
as small a section of code as practical". In your example, you're
trapping NameError from anywhere in a "many thousands" of line file.
That's about as far from the typical use of one or two lines in a try
block as you can get.

> 3. Changing the approach in the BaseException class to provide the best of both
>    approaches provides considerable value and is both trivial and backward
>    compatible.

A small amount of value in a case we don't particularly want to encourage.
Whether it's trivial comes down to implementation - I'll leave that to
whoever writes the PR to demonstrate. (Although if it *is* trivial, is
it something you could write a PR for?)

Also, given that this would be Python 3.7 only, would people needing
this functionality (only you have expressed a need so far) be OK with
either insisting their users go straight to Python 3.7, or including
backward compatible code for older versions?

Overall, I'm -0 on this request (assuming it is trivial to implement -
I certainly don't feel it's worth significant implementation effort).


More information about the Python-ideas mailing list