<div dir="ltr">This is a good example.  I like this idea.  I think that a good place to start would be setting the right example in the standard library: IndexError could have the offending index, KeyError the offending key, TypeError the offending type, etc.<div><div><div><div><br>On Monday, July 3, 2017 at 3:49:23 PM UTC-4, Jeff Walker wrote:<blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Paul,
<br>     I think you are fixating too much on Ken's example. I think I understand what he
<br>is saying and I agree with him. It is a problem I struggle with routinely. It occurs in
<br> the following situations:
<br>
<br>1. You are handling an exception that you are not raising. This could be because
<br>    Python itself is raising the exception, as in Ken's example, or it could be raised
<br>    by some package you did not write.
<br>2. You need to process or transform the message in some way.
<br>
<br>Consider this example:
<br>
<br>    import json                                                                      
<br>                                                                                 
<br>    >>> s = '{"abc": 0, "cdf: 1}'                                                        
<br>                                                                                 
<br>    >>> try:                                                                             
<br>    ...     d = json.loads(s)                                                            
<br>    ... except Exception as e:                                                           
<br>    ...     print(e)                                                                     
<br>    ...     print(e.args)
<br>    Unterminated string starting at: line 1 column 12 (char 11)
<br>    ('Unterminated string starting at: line 1 column 12 (char 11)',)
<br>
<br>Okay, I have caught an exception for which I have no control over how the
<br>exception was raised. Now, imagine that I am writing an application that highlights
<br>json errors in place. To do so, I would need the line and column numbers to
<br>highlight the location of the error, and ideally I'd like to strip them from the base
<br>message and just show that. You can see from my second print statement that
<br>the line and column numbers were not passed as separate arguments. Thus
<br>I need to parse the error message to extract them. Not a difficult job, but fragile.
<br>Any change to the error message could break my code.
<br>
<br>I don't know what this code smell is that people keep referring to, but to me,
<br>that code would smell.
<br>
<br>Jeff
<br>
<br>
<br>> On 3 July 2017 at 09:59, Ken Kundert <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="7cVbsAzaAAAJ" rel="nofollow" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">python...@shalmirane.com</a>> wrote:
<br>> > I think in trying to illustrate the existing behavior I made things more
<br>> > confusing than they needed to be.  Let me try again.
<br>> >
<br>> > Consider this code.
<br>> >
<br>> >     >>> import Food
<br>> >     >>> try:
<br>> >     ...     import meals
<br>> >     ... except NameError as e:
<br>> >     ...     name = str(e).split("'")[1]   # <-- fragile code
<br>> >     ...     from difflib import get_close_matches
<br>> >     ...     candidates = ', '.join(get_close_matches(name, Food.foods, 1, 0.6))
<br>> >     ...     print(f'{name}: not found. Did you mean {candidates}?')
<br>> >
<br>> > In this case *meals* instantiates a collection of foods. It is a Python file,
<br>> > but it is also a data file (in this case the user knows Python, so Python is
<br>> > a convenient data format). In that file thousands of foods may be instantiated.
<br>> > If the user misspells a food, I would like to present the available
<br>> > alternatives. To do so, I need the misspelled name.  The only way I can get it
<br>> > is by parsing the error message.
<br>> 
<br>> As Steven pointed out, this is a pretty good example of a code smell.
<br>> My feeling is that you may have just proved that Python isn't quite as
<br>> good a fit for your data file format as you thought - or that your
<br>> design has flaws. Suppose your user had a breakfast menu, and did
<br>> something like:
<br>> 
<br>>     if now < lunchtim: # Should have been "lunchtime"
<br>> 
<br>> Your error handling will be fairly confusing in that case.
<br>> 
<br>> > That is the problem.  To write the error handler, I need the misspelled name.
<br>> > The only way to get it is to extract it from the error message. The need to
<br>> > unpack information that was just packed suggests that the packing was done too
<br>> > early.  That is my point.
<br>> 
<br>> I don't have any problem with *having* the misspelled name as an
<br>> attribute to the error, I just don't think it's going to be as useful
<br>> as you hope, and it may indeed (as above) encourage people to use it
<br>> without thinking about whether there might be problems with using
<br>> error handling that way.
<br>> 
<br>> > Fundamentally, pulling the name out of an error message is a really bad coding
<br>> > practice because it is fragile.  The code will likely break if the formatting or
<br>> > the wording of the message changes.  But given the way the exception was
<br>> > implemented, I am forced to choose between two unpleasant choices: pulling the
<br>> > name from the error message or not giving the enhanced message at all.
<br>> 
<br>> Or using a different approach. ("Among our different approaches...!"
<br>> :-)) Agreed that's also an unpleasant choice at this point.
<br>> 
<br>> > What I am hoping to do with this proposal is to get the Python developer
<br>> > community to see that:
<br>> > 1. The code that handles the exception benefits from having access to the
<br>> >    components of the error message.  In the least it can present the message to
<br>> >    the user is the best possible way. Perhaps that means enforcing a particular
<br>> >    style, or presenting it in the user's native language, or perhaps it means
<br>> >    providing additional related information as in the example above.
<br>> 
<br>> I see it as a minor bug magnet, but not really a problem in principle.
<br>> 
<br>> > 2. The current approach to exceptions follows the opposite philosophy,
<br>> >    suggesting that the best place to construct the error message is at the
<br>> >    source of the error. It inadvertently puts obstacles in place that make it
<br>> >    difficult to customize the message in the handler.
<br>> 
<br>> It's more about implicitly enforcing the policy of "catch errors over
<br>> as small a section of code as practical". In your example, you're
<br>> trapping NameError from anywhere in a "many thousands" of line file.
<br>> That's about as far from the typical use of one or two lines in a try
<br>> block as you can get.
<br>> 
<br>> > 3. Changing the approach in the BaseException class to provide the best of both
<br>> >    approaches provides considerable value and is both trivial and backward
<br>> >    compatible.
<br>> 
<br>> A small amount of value in a case we don't particularly want to encourage.
<br>> Whether it's trivial comes down to implementation - I'll leave that to
<br>> whoever writes the PR to demonstrate. (Although if it *is* trivial, is
<br>> it something you could write a PR for?)
<br>> 
<br>> Also, given that this would be Python 3.7 only, would people needing
<br>> this functionality (only you have expressed a need so far) be OK with
<br>> either insisting their users go straight to Python 3.7, or including
<br>> backward compatible code for older versions?
<br>> 
<br>> Overall, I'm -0 on this request (assuming it is trivial to implement -
<br>> I certainly don't feel it's worth significant implementation effort).
<br>> 
<br>> Paul
<br>______________________________<wbr>_________________
<br>Python-ideas mailing list
<br><a href="javascript:" target="_blank" gdf-obfuscated-mailto="7cVbsAzaAAAJ" rel="nofollow" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">Python...@python.org</a>
<br><a href="https://mail.python.org/mailman/listinfo/python-ideas" target="_blank" rel="nofollow" onmousedown="this.href='https://www.google.com/url?q\x3dhttps%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Fpython-ideas\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFj1EaNHnVmh20FnFPoUi4J-MpfQw';return true;" onclick="this.href='https://www.google.com/url?q\x3dhttps%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Fpython-ideas\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFj1EaNHnVmh20FnFPoUi4J-MpfQw';return true;">https://mail.python.org/<wbr>mailman/listinfo/python-ideas</a>
<br>Code of Conduct: <a href="http://python.org/psf/codeofconduct/" target="_blank" rel="nofollow" onmousedown="this.href='http://www.google.com/url?q\x3dhttp%3A%2F%2Fpython.org%2Fpsf%2Fcodeofconduct%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHJOrArSUDKkjrnthO6_CznMzkPsA';return true;" onclick="this.href='http://www.google.com/url?q\x3dhttp%3A%2F%2Fpython.org%2Fpsf%2Fcodeofconduct%2F\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHJOrArSUDKkjrnthO6_CznMzkPsA';return true;">http://python.org/psf/<wbr>codeofconduct/</a>
<br></blockquote></div></div></div></div></div>