[Python-ideas] Arguments to exceptions

Ken Kundert python-ideas at shalmirane.com
Mon Jul 3 04:59:02 EDT 2017


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.

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.

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.

The above is an example. It is a bit contrived. I simply wanted to illustrate 
the basic issue in a few lines of code. However, my intent was also to 
illustrate what I see as a basic philosophical problem in the way we approach 
exceptions in Python:

    It is a nice convenience that an error message is provided by the source of 
    the error, but it should not have the final say on the matter.  
    Fundamentally, the code that actually presents the error to the user is in 
    a better position to produce a message that is meaningful to the user.  So, 
    when we raise exceptions, not only should we provide a convenient human 
    readable error message, we should anticipate that the exception handler may 
    need to reformat or reinterpret the exception and provide it with what it 
    need to do so.

The current approach taken by exceptions in Python makes that unnecessarily 
difficult.

PEP 352 suggests that this situation can be handled with a custom exception, and 
that is certainly true, but that only works if the person writing the code that 
raises the exception anticipates the need for passing the components of the 
error message as separate arguments. But as we can see from the NameError, 
AttributeError, etc, they don't always do. And PEP 352 actively discourages them 
from doing so.

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.
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.
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.

-Ken


More information about the Python-ideas mailing list