PEP 409 and the stdlib
As a quick reminder, PEP 409 allows this: try: ... except AnError: raise SomeOtherError from None so that if the exception is not caught, we get the traditional single exception traceback, instead of the new: During handling of the above exception, another exception occurred My question: How do we go about putting this in the stdlib? Is this one of the occasions where we don't do it unless we're modifying a module already for some other reason? For that matter, should we? Pros: Makes tracebacks much less confusing, especially coming from a library Cons: Could hide bugs unrelated to what is being caught and transformed -- ~Ethan~
On 20 May 2013 23:38, "Ethan Furman" <ethan@stoneleaf.us> wrote:
As a quick reminder, PEP 409 allows this:
try: ... except AnError: raise SomeOtherError from None
so that if the exception is not caught, we get the traditional single
exception traceback, instead of the new:
During handling of the above exception, another exception occurred
My question:
How do we go about putting this in the stdlib? Is this one of the
occasions where we don't do it unless we're modifying a module already for some other reason?
For that matter, should we?
Pros: Makes tracebacks much less confusing, especially coming from a
library
Cons: Could hide bugs unrelated to what is being caught and transformed
Be pretty conservative with this one - we should only use it when we're confident we know the original exception is almost certain to be irrelevant noise. Ensuring the traceback module makes it easy to display both would also be a good preliminary step. Cheers, Nick.
-- ~Ethan~ _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe:
http://mail.python.org/mailman/options/python-dev/ncoghlan%40gmail.com
On 05/20/2013 06:47 AM, Nick Coghlan wrote:
On 20 May 2013 23:38, Ethan Furman wrote:
As a quick reminder, PEP 409 allows this:
try: ... except AnError: raise SomeOtherError from None
so that if the exception is not caught, we get the traditional single exception traceback, instead of the new:
During handling of the above exception, another exception occurred
My question:
How do we go about putting this in the stdlib? Is this one of the occasions where we don't do it unless we're modifying a module already for some other reason?
For that matter, should we?
Pros: Makes tracebacks much less confusing, especially coming from a library
Cons: Could hide bugs unrelated to what is being caught and transformed
Be pretty conservative with this one - we should only use it when we're confident we know the original exception is almost certain to be irrelevant noise.
Ensuring the traceback module makes it easy to display both would also be a good preliminary step.
As a case in point, base64.py is currently getting a bug fix, and also contains this code: def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding') Does the KeyError qualify as irrelevant noise? If we're not going to suppress the originating error I think we should at least change the double trace back message as it implies two failures, instead of just one. -- ~Ethan~
On Mon, 20 May 2013 07:12:07 -0700, Ethan Furman <ethan@stoneleaf.us> wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
I don't see that it is of benefit to suppress it.
If we're not going to suppress the originating error I think we should at least change the double trace back message as it implies two failures, instead of just one.
I don't understand what you want to do here. --David
On 05/20/2013 07:50 AM, R. David Murray wrote:
On Mon, 20 May 2013 07:12:07 -0700, Ethan Furman wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
I don't see that it is of benefit to suppress it.
If we're not going to suppress the originating error I think we should at least change the double trace back message as it implies two failures, instead of just one.
I don't understand what you want to do here.
As a user of the b32decode the KeyError is an implementation detail and noise in the traceback. If I've got a non-base32 digit in my submitted string then the only exception I care about is the binascii.Error... but I'm going to see both, and the wording is such that it seems like I have two errors to deal with instead of just one. So I guess I see three options here: 1) Do nothing and be happy I use 'raise ... from None' in my own libraries 2) Change the wording of 'During handling of the above exception, another exception occurred' (no ideas as to what at the moment) 3) have the traceback module be configurable to show both exceptions even when 'raise ... from None' is used to help with debugging, then we can make the changes in stdlib confident that in our own testing of bugs we can see all available information. I would prefer 3, but I can live with 1. :) -- ~Ethan~
On 05/20/2013 05:15 PM, Ethan Furman wrote:
1) Do nothing and be happy I use 'raise ... from None' in my own libraries
2) Change the wording of 'During handling of the above exception, another exception occurred' (no ideas as to what at the moment)
The word "occurred" misleads one to think that, during handling of the real exception, an unrelated and unintended exception occurred. This is not the case when the "raise" keyword is used. In that case, the exception was intentionally *converted* from one type to another. For the "raise" case a wording like the following might work better: The above exception was converted to the following exception: ... That makes it clear that the conversion was explicit and (hopefully) intentional, and that the latter exception supersedes the former. Hrvoje
21.05.13 10:17, Hrvoje Niksic написав(ла):
On 05/20/2013 05:15 PM, Ethan Furman wrote:
1) Do nothing and be happy I use 'raise ... from None' in my own libraries
2) Change the wording of 'During handling of the above exception, another exception occurred' (no ideas as to what at the moment)
The word "occurred" misleads one to think that, during handling of the real exception, an unrelated and unintended exception occurred. This is not the case when the "raise" keyword is used. In that case, the exception was intentionally *converted* from one type to another. For the "raise" case a wording like the following might work better:
The above exception was converted to the following exception: ...
That makes it clear that the conversion was explicit and (hopefully) intentional, and that the latter exception supersedes the former.
How do you distinguish intentional and unintentional exceptions?
On 05/21/2013 10:36 AM, Serhiy Storchaka wrote:
The above exception was converted to the following exception: ...
That makes it clear that the conversion was explicit and (hopefully) intentional, and that the latter exception supersedes the former.
How do you distinguish intentional and unintentional exceptions?
By the use of the "raise" keyword. Given the code: try: x = d['key'] except KeyError: raise BusinessError(...) ...the explicit raising is a giveaway that the new exception was quite intentional. Hrvoje
21.05.13 12:28, Hrvoje Niksic написав(ла):
On 05/21/2013 10:36 AM, Serhiy Storchaka wrote:
The above exception was converted to the following exception: ...
That makes it clear that the conversion was explicit and (hopefully) intentional, and that the latter exception supersedes the former.
How do you distinguish intentional and unintentional exceptions?
By the use of the "raise" keyword. Given the code:
try: x = d['key'] except KeyError: raise BusinessError(...)
....the explicit raising is a giveaway that the new exception was quite intentional.
try: x = d['key'] except KeyError: x = fallback('key') def fallback(key): if key not in a: raise BusinessError(...) return 1 / a[key] # possible TypeError, ZeroDivisionError, etc
On 05/21/2013 11:56 AM, Serhiy Storchaka wrote:
try: x = d['key'] except KeyError: x = fallback('key')
def fallback(key): if key not in a: raise BusinessError(...) return 1 / a[key] # possible TypeError, ZeroDivisionError, etc
Yes, in that case the exception will appear unintentional and you get the old message — it's on a best-effort basis. Hrvoje
21.05.13 13:05, Hrvoje Niksic написав(ла):
On 05/21/2013 11:56 AM, Serhiy Storchaka wrote:
try: x = d['key'] except KeyError: x = fallback('key')
def fallback(key): if key not in a: raise BusinessError(...) return 1 / a[key] # possible TypeError, ZeroDivisionError, etc
Yes, in that case the exception will appear unintentional and you get the old message — it's on a best-effort basis.
In both cases the BusinessError exception raised explicitly. How do you distinguish one case from another?
On 05/21/2013 02:57 PM, Serhiy Storchaka wrote:
21.05.13 13:05, Hrvoje Niksic написав(ла):
On 05/21/2013 11:56 AM, Serhiy Storchaka wrote:
try: x = d['key'] except KeyError: x = fallback('key')
def fallback(key): if key not in a: raise BusinessError(...) return 1 / a[key] # possible TypeError, ZeroDivisionError, etc
Yes, in that case the exception will appear unintentional and you get the old message — it's on a best-effort basis.
In both cases the BusinessError exception raised explicitly. How do you distinguish one case from another?
In my example code the "raise" keyword appears lexically inside the "except" clause. The compiler would automatically emit a different raise opcode in that case. NB in your example the "raise" is just as intentional, but invoked from a different function, which causes the above criterion to result in a false negative. Even in so, the behavior would be no worse than now, you'd just get the old message. Hrvoje
On Tue, May 21, 2013 at 11:23 PM, Hrvoje Niksic <hrvoje.niksic@avl.com> wrote:
In my example code the "raise" keyword appears lexically inside the "except" clause. The compiler would automatically emit a different raise opcode in that case.
Hrvoje, can we drop this subthread please. The topic was addressed way back when PEP 3134 was written, and there is already dedicated syntax to distinguish incidental exceptions in error handlers ("raise new") from deliberate replacement of an exception with a new one ("raise new from original") Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On 05/21/2013 10:36 AM, Serhiy Storchaka wrote:
21.05.13 10:17, Hrvoje Niksic написав(ла):
On 05/20/2013 05:15 PM, Ethan Furman wrote:
1) Do nothing and be happy I use 'raise ... from None' in my own libraries
2) Change the wording of 'During handling of the above exception, another exception occurred' (no ideas as to what at the moment)
The word "occurred" misleads one to think that, during handling of the real exception, an unrelated and unintended exception occurred. This is not the case when the "raise" keyword is used. In that case, the exception was intentionally *converted* from one type to another. For the "raise" case a wording like the following might work better:
The above exception was converted to the following exception: ...
That makes it clear that the conversion was explicit and (hopefully) intentional, and that the latter exception supersedes the former.
How do you distinguish intentional and unintentional exceptions?
By the use of the "raise" keyword. Given the code: try: x = bla['foo'] except KeyError: raise BusinessError(...) ...explicit raise is a giveaway that the exception replacement was quite intentional. Hrvoje
On Tue, May 21, 2013 at 5:17 PM, Hrvoje Niksic <hrvoje.niksic@avl.com> wrote:
On 05/20/2013 05:15 PM, Ethan Furman wrote:
1) Do nothing and be happy I use 'raise ... from None' in my own libraries
2) Change the wording of 'During handling of the above exception, another exception occurred' (no ideas as to what at the moment)
The word "occurred" misleads one to think that, during handling of the real exception, an unrelated and unintended exception occurred. This is not the case when the "raise" keyword is used. In that case, the exception was intentionally *converted* from one type to another. For the "raise" case a wording like the following might work better:
The above exception was converted to the following exception: ...
That makes it clear that the conversion was explicit and (hopefully) intentional, and that the latter exception supersedes the former.
This ship sailed long ago (it was covered by the original exception chaining spec in PEP 3134). If you want to deliberately replace an exception while retaining the full traceback, you use "raise X from Y", and the intro text will change to something like "This exception was the direct cause of the following exception:" This thread is about the case where you want to use "raise X from None" to suppress the display of the original exception completely, which is a new capability in Python 3.3. So whenever we consider changing the standard library, we should also look at the explicit chaining option, particularly when the original exception may have happened inside a user provided callback (including method calls) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On 05/21/2013 04:23 AM, Nick Coghlan wrote:
On Tue, May 21, 2013 at 5:17 PM, Hrvoje Niksic <hrvoje.niksic@avl.com> wrote:
On 05/20/2013 05:15 PM, Ethan Furman wrote:
1) Do nothing and be happy I use 'raise ... from None' in my own libraries
2) Change the wording of 'During handling of the above exception, another exception occurred' (no ideas as to what at the moment)
The word "occurred" misleads one to think that, during handling of the real exception, an unrelated and unintended exception occurred. This is not the case when the "raise" keyword is used. In that case, the exception was intentionally *converted* from one type to another. For the "raise" case a wording like the following might work better:
The above exception was converted to the following exception: ...
That makes it clear that the conversion was explicit and (hopefully) intentional, and that the latter exception supersedes the former.
This ship sailed long ago (it was covered by the original exception chaining spec in PEP 3134). If you want to deliberately replace an exception while retaining the full traceback, you use "raise X from Y", and the intro text will change to something like "This exception was the direct cause of the following exception:"
I had forgotten about that, Nick, thanks. So the moral of the story for our library code and replacing exceptions is we should either do raise ... from OldException or raise ... from None depending on the importance of the originating exception. And, of course, we only make these changes when we're already modifying the module for some other reason. -- ~Ethan~
Am 21.05.13 18:03, schrieb Ethan Furman:
And, of course, we only make these changes when we're already modifying the module for some other reason.
In the specific case, the KeyError has indeed useful information that the TypeError does not, namely the specific character that is the culprit. So if you do drop the KeyError entirely, please carry over information about the character into the TypeError. Regards, Martin
On 05/23/2013 04:36 AM, "Martin v. Löwis" wrote:
Am 21.05.13 18:03, schrieb Ethan Furman:
And, of course, we only make these changes when we're already modifying the module for some other reason.
In the specific case, the KeyError has indeed useful information that the TypeError does not, namely the specific character that is the culprit.
So if you do drop the KeyError entirely, please carry over information about the character into the TypeError.
Here's the code that existed at one point: for c in s: val = _b32rev.get(c) if val is None: raise TypeError('Non-base32 digit found') Even though there is no KeyError to convert in this incarnation, providing the cause of failure is still appreciated by the user who's trying to figure out what, exactly, went wrong. -- ~Ethan~
On 24/05/13 00:24, Ethan Furman wrote:
Here's the code that existed at one point:
for c in s: val = _b32rev.get(c) if val is None: raise TypeError('Non-base32 digit found')
Even though there is no KeyError to convert in this incarnation, providing the cause of failure is still appreciated by the user who's trying to figure out what, exactly, went wrong.
For the record, that is the implementation used in Python 3.3.0rc3, so "at some point" is actually very recently. -- Steven
On 21/05/13 00:12, Ethan Furman wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
IMO, it is irrelevant noise, and obviously so. The binascii.Error raised is not a bug to be fixed, it is a deliberate exception and part of the API of the binascii module. That it occurs inside an "except KeyError" block is a mere implementation detail. It merely happens to be that digits are converted by looking up in a mapping, another implementation might use a completely different mechanism. In fact, the implementation in Python 3.3 *is* completely different, and there is no KeyError to suppress. In another reply, R.David Murray answered: "I don't see that it is of benefit to suppress [the KeyError]." Can I suggest that it's obviously been a long, long time since you were a beginner to the language, and you've forgotten how intimidating error messages can be? Error messages should be *relevant*. Irrelevant details don't help, they hinder, and I suggest that the KeyError is irrelevant. -- Steven
Am 20.05.2013 17:39, schrieb Steven D'Aprano:
On 21/05/13 00:12, Ethan Furman wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
IMO, it is irrelevant noise, and obviously so. The binascii.Error raised is not a bug to be fixed, it is a deliberate exception and part of the API of the binascii module. That it occurs inside an "except KeyError" block is a mere implementation detail. It merely happens to be that digits are converted by looking up in a mapping, another implementation might use a completely different mechanism. In fact, the implementation in Python 3.3 *is* completely different, and there is no KeyError to suppress.
In another reply, R.David Murray answered:
"I don't see that it is of benefit to suppress [the KeyError]."
Can I suggest that it's obviously been a long, long time since you were a beginner to the language, and you've forgotten how intimidating error messages can be? Error messages should be *relevant*. Irrelevant details don't help, they hinder, and I suggest that the KeyError is irrelevant.
I agree. This is a case of a well isolated exception where there's no chance of hiding a bug because the KeyError was exceptional (<wink/>). The argument of not making it harder than necessary to beginners (or casual users) seems valid to me, and since the code is being touched anyway, there shouldn't be unnecessary code churn. Georg
On 5/20/2013 11:39 AM, Steven D'Aprano wrote:
On 21/05/13 00:12, Ethan Furman wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
IMO, it is irrelevant noise, and obviously so. The binascii.Error raised is not a bug to be fixed, it is a deliberate exception and part of the API of the binascii module. That it occurs inside an "except KeyError" block is a mere implementation detail.
Yes, the code could be revised to make a check on c before the indexing. This would be redundant (and a slowdown) in that the check is already done by the indexing mechanism. The whole point of the above is to *replace* the default KeyError with a custom binascii.Error for too-large chars. And I agree with Georg, please say which bad digit was found. Terry
On 05/20/2013 11:32 AM, Terry Jan Reedy wrote:
On 5/20/2013 11:39 AM, Steven D'Aprano wrote:
On 21/05/13 00:12, Ethan Furman wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
IMO, it is irrelevant noise, and obviously so. The binascii.Error raised is not a bug to be fixed, it is a deliberate exception and part of the API of the binascii module. That it occurs inside an "except KeyError" block is a mere implementation detail.
Yes, the code could be revised to make a check on c before the indexing. This would be redundant (and a slowdown) in that the check is already done by the indexing mechanism. The whole point of the above is to *replace* the default KeyError with a custom binascii.Error for too-large chars.
And I agree with Georg, please say which bad digit was found.
Actually, that was Antoine, but I'm sure Georg also agrees. ;) -- ~Ethan~
On 21 May 2013 05:01, "Ethan Furman" <ethan@stoneleaf.us> wrote:
On 05/20/2013 11:32 AM, Terry Jan Reedy wrote:
On 5/20/2013 11:39 AM, Steven D'Aprano wrote:
On 21/05/13 00:12, Ethan Furman wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
IMO, it is irrelevant noise, and obviously so. The binascii.Error raised is not a bug to be fixed, it is a deliberate exception and part of the API of the binascii module. That it occurs inside an "except KeyError" block is a mere implementation detail.
Yes, the code could be revised to make a check on c before the indexing. This would be redundant (and a slowdown) in that the check is already
done by the indexing mechanism. The whole point of
the above is to *replace* the default KeyError with a custom binascii.Error for too-large chars.
And I agree with Georg, please say which bad digit was found.
Actually, that was Antoine, but I'm sure Georg also agrees. ;)
Indeed, a good question to ask when making use of PEP 409 is what debugging info is being lost by suppressing the original exception, and then making sure that info is captured and reported by the outer exception. There's probably a new PEP 8 guideline in this thread - perhaps something based on the above paragraph. Cheers, Nick.
-- ~Ethan~
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe:
http://mail.python.org/mailman/options/python-dev/ncoghlan%40gmail.com
On Tue, 21 May 2013 01:39:03 +1000, Steven D'Aprano <steve@pearwood.info> wrote:
On 21/05/13 00:12, Ethan Furman wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
[...]
In another reply, R.David Murray answered:
"I don't see that it is of benefit to suppress [the KeyError]."
Can I suggest that it's obviously been a long, long time since you were a beginner to the language, and you've forgotten how intimidating error messages can be? Error messages should be *relevant*. Irrelevant details don't help, they hinder, and I suggest that the KeyError is irrelevant.
Doubtless you are correct. Now that you mention it I do remember being confused, even as an experienced programmer, by the chained exceptions when I first started dealing with them, but at this point I suppose it has become second nature :). I agree with the subsequent discussion that this error is a good case for 'from None', given that any such conversion should make sure all essential information is contained in the new error message. And I agree with Nick that there are probably many more places where 'raise from' will help clarify things when we *don't* want 'from None'. --David
On Mon, 20 May 2013 07:12:07 -0700 Ethan Furman <ethan@stoneleaf.us> wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
I think it is a legitimate case where to silence the original exception. However, the binascii.Error would be more informative if it said *which* non-base32 digit was encountered. Regards Antoine.
On May 20, 2013, at 11:46 AM, Antoine Pitrou <solipsis@pitrou.net> wrote:
On Mon, 20 May 2013 07:12:07 -0700 Ethan Furman <ethan@stoneleaf.us> wrote:
As a case in point, base64.py is currently getting a bug fix, and also contains this code:
def b32decode(s, casefold=False, map01=None): . . . for i in range(0, len(s), 8): quanta = s[i: i + 8] acc = 0 try: for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: raise binascii.Error('Non-base32 digit found') . . . else: raise binascii.Error('Incorrect padding')
Does the KeyError qualify as irrelevant noise?
I think it is a legitimate case where to silence the original exception. However, the binascii.Error would be more informative if it said *which* non-base32 digit was encountered.
And, if possible, the location (index) in the string. Eric.
20.05.13 18:46, Antoine Pitrou написав(ла):
I think it is a legitimate case where to silence the original exception. However, the binascii.Error would be more informative if it said *which* non-base32 digit was encountered.
Please open a new issue for this request (note that no other binascii or base64 functions provide such information).
On 5/28/2013 6:02 AM, Serhiy Storchaka wrote:
20.05.13 18:46, Antoine Pitrou написав(ла):
I think it is a legitimate case where to silence the original exception. However, the binascii.Error would be more informative if it said *which* non-base32 digit was encountered.
Please open a new issue for this request (note that no other binascii or base64 functions provide such information).
Sounds like perhaps multiple issues would be useful to suggest enhancements for the error messages provided by other binascii and base64 functions.
On Tue, 28 May 2013 16:02:00 +0300 Serhiy Storchaka <storchaka@gmail.com> wrote:
20.05.13 18:46, Antoine Pitrou написав(ла):
I think it is a legitimate case where to silence the original exception. However, the binascii.Error would be more informative if it said *which* non-base32 digit was encountered.
Please open a new issue for this request (note that no other binascii or base64 functions provide such information).
No, my point was that the KeyError gives you this information (when displayed as a context), silencing it removes the information. Regards Antoine.
On 29/05/13 04:00, Antoine Pitrou wrote:
On Tue, 28 May 2013 16:02:00 +0300 Serhiy Storchaka <storchaka@gmail.com> wrote:
20.05.13 18:46, Antoine Pitrou написав(ла):
I think it is a legitimate case where to silence the original exception. However, the binascii.Error would be more informative if it said *which* non-base32 digit was encountered.
Please open a new issue for this request (note that no other binascii or base64 functions provide such information).
No, my point was that the KeyError gives you this information (when displayed as a context), silencing it removes the information.
That is an accidental side-effect of the specific implementation, and does not occur in any of the versions of Python I have access to (production versions of 2.4 through 2.7, plus 3.2 and 3.3.0rc3). If the implementation changes again in the future, that information will be lost again. Relying on the context in this case to display this information is harmful for at least three reasons: - it's an accident of implementation; - it suggests that the binascii.Error is a bug in the error handling, when that is not the case; - and it is semantically irrelevant to the error being reported. The semantics of the error are "an invalid character has been found", not "an expected key is not found". I try not to throw references to the Zen around too lightly, but I think "Explicit is better than implicit" is appropriate here. If it is helpful for the error to show the invalid character, and I hope that we all agree that it is, then the binascii.Error message should explicitly show that character, rather than rely on the implementation implicitly showing it as a side-effect. -- Steven
On Mon, 20 May 2013 06:12:41 -0700, Ethan Furman <ethan@stoneleaf.us> wrote:
As a quick reminder, PEP 409 allows this:
try: ... except AnError: raise SomeOtherError from None
so that if the exception is not caught, we get the traditional single exception traceback, instead of the new:
During handling of the above exception, another exception occurred
My question:
How do we go about putting this in the stdlib? Is this one of the occasions where we don't do it unless we're modifying a module already for some other reason?
For that matter, should we?
Pros: Makes tracebacks much less confusing, especially coming from a library
Cons: Could hide bugs unrelated to what is being caught and transformed
I'm pretty sure the answer is "almost never". I think a case needs to be made for any place that seems like it would actually improve things, because usually I don't think it will, in the stdlib. --David
20.05.13 16:12, Ethan Furman написав(ла):
As a quick reminder, PEP 409 allows this:
try: ... except AnError: raise SomeOtherError from None
so that if the exception is not caught, we get the traditional single exception traceback, instead of the new:
During handling of the above exception, another exception occurred
My question:
How do we go about putting this in the stdlib? Is this one of the occasions where we don't do it unless we're modifying a module already for some other reason?
Usually I use "from None" in a new code when it hides irrelevant details. But in case of b32decode() (changeset 1b5ef05d6ced) I didn't do it. It's my fault, I'll fix it in next commit.
participants (12)
-
"Martin v. Löwis"
-
Antoine Pitrou
-
Eric V. Smith
-
Ethan Furman
-
Georg Brandl
-
Glenn Linderman
-
Hrvoje Niksic
-
Nick Coghlan
-
R. David Murray
-
Serhiy Storchaka
-
Steven D'Aprano
-
Terry Jan Reedy