I haven't seen any further discussion here or in the bug tracker. Below is the latest version of this PEP, now with a section on Language Details. Who makes the final call on this? Any idea how long that will take? (Not that I'm antsy, or anything... ;) PEP: 409 Title: Suppressing exception context Version: $Revision$ Last-Modified: $Date$ Author: Ethan Furman <ethan@stoneleaf.us> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 26-Jan-2012 Post-History: 30-Aug-2002, 01-Feb-2012 Abstract ======== One of the open issues from PEP 3134 is suppressing context: currently there is no way to do it. This PEP proposes one. Rationale ========= There are two basic ways to generate exceptions: 1) Python does it (buggy code, missing resources, ending loops, etc.) 2) manually (with a raise statement) When writing libraries, or even just custom classes, it can become necessary to raise exceptions; moreover it can be useful, even necessary, to change from one exception to another. To take an example from my dbf module:: try: value = int(value) except Exception: raise DbfError(...) Whatever the original exception was (``ValueError``, ``TypeError``, or something else) is irrelevant. The exception from this point on is a ``DbfError``, and the original exception is of no value. However, if this exception is printed, we would currently see both. Alternatives ============ Several possibilities have been put forth: * ``raise as NewException()`` Reuses the ``as`` keyword; can be confusing since we are not really reraising the originating exception * ``raise NewException() from None`` Follows existing syntax of explicitly declaring the originating exception * ``exc = NewException(); exc.__context__ = None; raise exc`` Very verbose way of the previous method * ``raise NewException.no_context(...)`` Make context suppression a class method. All of the above options will require changes to the core. Proposal ======== I proprose going with the second option:: raise NewException from None It has the advantage of using the existing pattern of explicitly setting the cause:: raise KeyError() from NameError() but because the 'cause' is ``None`` the previous context, while retained, is not displayed by the default exception printing routines. Language Details ================ Currently, ``__context__`` and ``__cause__`` start out as None, and then get set as exceptions occur. To support ``from None``, ``__context__`` will stay as it is, but ``__cause__`` will start out as ``False``, and will change to ``None`` when the ``raise ... from None`` method is used. The default exception printing routine will then: * If ``__cause__`` is ``False`` the ``__context__`` (if any) will be printed. * If ``__cause__`` is ``None`` the ``__context__`` will not be printed. * if ``__cause__`` is anything else, ``__cause__`` will be printed. This has the benefit of leaving the ``__context__`` intact for future logging, querying, etc., while suppressing its display if it is not caught. This is important for those times when trying to debug poorly written libraries with `bad error messages`_. Patches ======= There is a patch for CPython implementing this attached to `Issue 6210`_. References ========== Discussion and refinements in this `thread on python-dev`_. .. _bad error messages: http://bugs.python.org/msg152294 .. _Issue 6210: http://bugs.python.org/issue6210 .. _thread on python-dev: http://mail.python.org/pipermail/python-dev/2012-January/115838.html Copyright ========= This document has been placed in the public domain. .. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 coding: utf-8 End:
On Wed, Feb 1, 2012 at 1:57 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
I haven't seen any further discussion here or in the bug tracker. Below is the latest version of this PEP, now with a section on Language Details.
Who makes the final call on this? Any idea how long that will take? (Not that I'm antsy, or anything... ;)
Guido still has the final say on PEP approvals as BDFL - it's just that sometimes he'll tap someone else and say "Your call!" (thus making them a BDFOP - Benevolent Dictator for One PEP). FWIW, I'm personally +1 on the latest version of this. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
Hm... Reading this draft, I like the idea of using "raise X from None", but I still have one quibble. It seems the from clause sets __cause__, and __cause__ can indicate three things: (1) print __cause__ (explicitly set), (2) print __context__ (default), (3) print neither (raise X from None). For (1), __cause__ must of course be a traceback object. The PEP currently proposes to use two special values: False for (2), None for (3). To me, this has a pretty strong code smell, and I don't want this pattern to be enshrined in a PEP as an example for all to follow. (And I also don't like "do as I say, don't do as I do." :-) Can we think of a different special value to distinguish between (2) and (3)? Ideally one that doesn't change the nice "from None" idiom, which I actually like as a way to spell this. Sorry that life isn't easier, --Guido On Tue, Jan 31, 2012 at 9:14 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Wed, Feb 1, 2012 at 1:57 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
I haven't seen any further discussion here or in the bug tracker. Below is the latest version of this PEP, now with a section on Language Details.
Who makes the final call on this? Any idea how long that will take? (Not that I'm antsy, or anything... ;)
Guido still has the final say on PEP approvals as BDFL - it's just that sometimes he'll tap someone else and say "Your call!" (thus making them a BDFOP - Benevolent Dictator for One PEP).
FWIW, I'm personally +1 on the latest version of this.
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia _______________________________________________ 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/guido%40python.org
-- --Guido van Rossum (python.org/~guido)
Guido van Rossum wrote:
Hm... Reading this draft, I like the idea of using "raise X from None", but I still have one quibble. It seems the from clause sets __cause__, and __cause__ can indicate three things: (1) print __cause__ (explicitly set), (2) print __context__ (default), (3) print neither (raise X from None). For (1), __cause__ must of course be a traceback object.
Actually, for (1) __cause__ is an exception object, not a traceback.
The PEP currently proposes to use two special values: False for (2), None for (3). To me, this has a pretty strong code smell, and I don't want this pattern to be enshrined in a PEP as an example for all to follow. (And I also don't like "do as I say, don't do as I do." :-)
My apologies for my ignorance, but is the code smell because both False and None evaluate to bool(False)? I suppose we could use True for (2) to indicate that __context__ should be printed, leaving None for (3)... but having __context__ at None and __cause__ at True could certainly be confusing (the default case when no chaining is in effect).
Can we think of a different special value to distinguish between (2) and (3)? Ideally one that doesn't change the nice "from None" idiom, which I actually like as a way to spell this.
How about this: Exception Life Cycle ==================== Stage 1 - brand new exception ----------------------------- raise ValueError() * __context__ is None * __cause__ is None Stage 2 - exception caught, exception raised -------------------------------------------- try: raise ValueError() except Exception: raise CustomError() * __context__ is previous exception * __cause__ is True Stage 3 - exception raised from [exception | None] -------------------------------------------------- try: raise ValueError() except Exception: raise CustomError() from [OtherException | None] * __context__ is previous exception * __cause__ is [OtherException | None]
Sorry that life isn't easier,
Where would be the fun without the challenge? ~Ethan~
On Wed, Feb 1, 2012 at 10:48 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
Guido van Rossum wrote:
Hm... Reading this draft, I like the idea of using "raise X from None", but I still have one quibble. It seems the from clause sets __cause__, and __cause__ can indicate three things: (1) print __cause__ (explicitly set), (2) print __context__ (default), (3) print neither (raise X from None). For (1), __cause__ must of course be a traceback object.
Actually, for (1) __cause__ is an exception object, not a traceback.
Ah, sorry. I'm not as detail-oriented as I was. :-)
The PEP currently proposes to use two special values: False for (2), None for (3). To me, this has a pretty strong code smell, and I don't want this pattern to be enshrined in a PEP as an example for all to follow. (And I also don't like "do as I say, don't do as I do." :-)
My apologies for my ignorance, but is the code smell because both False and None evaluate to bool(False)?
That's part of it, but the other part is that the type of __context__ is now truly dynamic. I often *think* of variables as having some static type, e.g. "integer" or "Foo instance", and for most Foo instances I consider None an acceptable value (since that's how pointer types work in most static languages). But the type of __context__ you're proposing is now a union of exception and bool, except that the bool can only be False.
I suppose we could use True for (2) to indicate that __context__ should be printed, leaving None for (3)... but having __context__ at None and __cause__ at True could certainly be confusing (the default case when no chaining is in effect).
It seems you really need a marker object. I'd be fine with using some other opaque marker -- IMO that's much better than using False but disallowing True.
Can we think of a different special value to distinguish between (2) and (3)? Ideally one that doesn't change the nice "from None" idiom, which I actually like as a way to spell this.
How about this:
Exception Life Cycle ====================
Stage 1 - brand new exception -----------------------------
raise ValueError()
* __context__ is None * __cause__ is None
Stage 2 - exception caught, exception raised --------------------------------------------
try: raise ValueError() except Exception: raise CustomError()
* __context__ is previous exception * __cause__ is True
Stage 3 - exception raised from [exception | None] --------------------------------------------------
try: raise ValueError() except Exception: raise CustomError() from [OtherException | None]
* __context__ is previous exception * __cause__ is [OtherException | None]
No, this has the same code smell for me. See above.
Sorry that life isn't easier,
Where would be the fun without the challenge?
+1 :-) -- --Guido van Rossum (python.org/~guido)
On 2/1/2012 3:07 PM, Guido van Rossum wrote:
On Wed, Feb 1, 2012 at 10:48 AM, Ethan Furman<ethan@stoneleaf.us> wrote:
Guido van Rossum wrote:
Hm... Reading this draft, I like the idea of using "raise X from None", but I still have one quibble. It seems the from clause sets __cause__, and __cause__ can indicate three things: (1) print __cause__ (explicitly set), (2) print __context__ (default), (3) print neither (raise X from None). For (1), __cause__ must of course be a traceback object.
Actually, for (1) __cause__ is an exception object, not a traceback.
Ah, sorry. I'm not as detail-oriented as I was. :-)
The PEP currently proposes to use two special values: False for (2), None for (3). To me, this has a pretty strong code smell, and I don't want this pattern to be enshrined in a PEP as an example for all to follow. (And I also don't like "do as I say, don't do as I do." :-)
My apologies for my ignorance, but is the code smell because both False and None evaluate to bool(False)?
That's part of it, but the other part is that the type of __context__ is now truly dynamic. I often *think* of variables as having some static type, e.g. "integer" or "Foo instance", and for most Foo instances I consider None an acceptable value (since that's how pointer types work in most static languages). But the type of __context__ you're proposing is now a union of exception and bool, except that the bool can only be False.
It sounds like you are asking for a special class __NoException__(BaseException) to use as the marker. -- Terry Jan Reedy
Not a bad idea. On Wed, Feb 1, 2012 at 12:53 PM, Terry Reedy <tjreedy@udel.edu> wrote:
On 2/1/2012 3:07 PM, Guido van Rossum wrote:
On Wed, Feb 1, 2012 at 10:48 AM, Ethan Furman<ethan@stoneleaf.us> wrote:
Guido van Rossum wrote:
Hm... Reading this draft, I like the idea of using "raise X from None", but I still have one quibble. It seems the from clause sets __cause__, and __cause__ can indicate three things: (1) print __cause__ (explicitly set), (2) print __context__ (default), (3) print neither (raise X from None). For (1), __cause__ must of course be a traceback object.
Actually, for (1) __cause__ is an exception object, not a traceback.
Ah, sorry. I'm not as detail-oriented as I was. :-)
The PEP currently proposes to use two special values: False for (2), None for (3). To me, this has a pretty strong code smell, and I don't want this pattern to be enshrined in a PEP as an example for all to follow. (And I also don't like "do as I say, don't do as I do." :-)
My apologies for my ignorance, but is the code smell because both False and None evaluate to bool(False)?
That's part of it, but the other part is that the type of __context__ is now truly dynamic. I often *think* of variables as having some static type, e.g. "integer" or "Foo instance", and for most Foo instances I consider None an acceptable value (since that's how pointer types work in most static languages). But the type of __context__ you're proposing is now a union of exception and bool, except that the bool can only be False.
It sounds like you are asking for a special class __NoException__(BaseException) to use as the marker.
-- Terry Jan Reedy
_______________________________________________ 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/guido%40python.org
-- --Guido van Rossum (python.org/~guido)
Guido van Rossum wrote:
On Wed, Feb 1, 2012 at 10:48 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
My apologies for my ignorance, but is the code smell because both False and None evaluate to bool(False)?
That's part of it, but the other part is that the type of __context__ is now truly dynamic. I often *think* of variables as having some static type, e.g. "integer" or "Foo instance", and for most Foo instances I consider None an acceptable value (since that's how pointer types work in most static languages). But the type of __context__ you're proposing is now a union of exception and bool, except that the bool can only be False.
It seems you really need a marker object. I'd be fine with using some other opaque marker -- IMO that's much better than using False but disallowing True.
So for __cause__ we need three values: 1) Not set special value (prints __context__ if present) 2) Some exception (print instead of __context__) 3) Ignore __context__ special value (and stop following the __context__ chain) For (3) we're hoping for None, for (2) we have an actual exception, and for (1) -- hmmm. It seems like a stretch, but we could do (looking at both __context__ and __cause__): __context__ __cause__ raise None False [1] reraise previous True [2] reraise from previous None [3] | exception [1] False means non-chained exception [2] True means chained exception [3] None means chained exception, but by default we do not print nor follow the chain The downside to this is that effectively either False and True mean the same thing, i.e. try to follow the __context__ chain, or False and None mean the same thing, i.e. don't bother trying to follow the __context__ chain because it either doesn't exist or is being suppressed. Feels like a bunch of complexity for marginal value. As you were saying, some other object to replace both False and True in the above table would be ideal. ~Ethan~
On Wed, Feb 1, 2012 at 12:55 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
Guido van Rossum wrote:
On Wed, Feb 1, 2012 at 10:48 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
My apologies for my ignorance, but is the code smell because both False and None evaluate to bool(False)?
That's part of it, but the other part is that the type of __context__ is now truly dynamic. I often *think* of variables as having some static type, e.g. "integer" or "Foo instance", and for most Foo instances I consider None an acceptable value (since that's how pointer types work in most static languages). But the type of __context__ you're proposing is now a union of exception and bool, except that the bool can only be False.
It seems you really need a marker object. I'd be fine with using some other opaque marker -- IMO that's much better than using False but disallowing True.
So for __cause__ we need three values:
1) Not set special value (prints __context__ if present)
2) Some exception (print instead of __context__)
3) Ignore __context__ special value (and stop following the __context__ chain)
For (3) we're hoping for None, for (2) we have an actual exception, and for (1) -- hmmm.
It seems like a stretch, but we could do (looking at both __context__ and __cause__):
__context__ __cause__
raise None False [1]
reraise previous True [2]
reraise from previous None [3] | exception
[1] False means non-chained exception [2] True means chained exception [3] None means chained exception, but by default we do not print nor follow the chain
The downside to this is that effectively either False and True mean the same thing, i.e. try to follow the __context__ chain, or False and None mean the same thing, i.e. don't bother trying to follow the __context__ chain because it either doesn't exist or is being suppressed.
Feels like a bunch of complexity for marginal value. As you were saying, some other object to replace both False and True in the above table would be ideal.
So what did you think of Terry Reedy's idea of using a special exception class? -- --Guido van Rossum (python.org/~guido)
raise from None seems pretty "in band". A NoException class could have many other uses and leaves no confusion about intent.
Terry Reedy wrote:
It sounds like you are asking for a special class __NoException__(BaseException) to use as the marker.
Guido van Rossum wrote:
So what did you think of Terry Reedy's idea of using a special exception class?
Our table would then look like: __context__ __cause__ raise None __NoException__ reraise previous __NoException__ reraise from previous None | exception It is certainly simpler than trying to force the use of both True and False. :) The purist side of me thinks it's still slightly awkward; the practical side recognizes that there probably is not a perfect solution and thinks this is workable, and is willing to deal with the slight awkwardness to get 'from None' up and running. :) The main reason for the effort in keeping the previous exception in __context__ instead of just clobbering it is for custom error handlers, yes? So here is a brief comparison of the two: def complete_traceback(): .... Actually, I got about three lines into that and realized that whatever __cause__ is set to is completely irrelevant for that function: if *__context__* is not None, follow the chain; the only relevance __cause__ has is when would it print? If it is a (valid) exception. And how do we know if it's valid? # True, False, None if isinstance(exc.__cause__, BaseException): print_exc(exc) or if exc.__cause__ not in (True, False, None): print_exc(exc) vs # None, __NoException__ (forced to be an instance) if (exc.__cause__ is not None and not isinstance(exc.__cause__, __NoException__): print_exc(exc) or # None, __NoException__ (forced to stay a class) if exc.__cause__ not in (None, __NoException__): print_exc(exc) Having gone through all that, I'm equally willing to go either way (True/False/None or __NoException__). Implementation questions for the __NoException__ route: 1) Do we want double underscores, or just a single one? I'm thinking double to mark it as special as opposed to private. 2) This is a new exception class -- do we want to store the class itself in __context__, or it's instance? If its class, should we somehow disallow instantiation of it? 3) Should it be an exception, or just inherit from object? Is it worth worrying about somebody trying to raise it, or raise from it? 4) Is the name '__NoException__' confusing? ~Ethan~
On 2 February 2012 11:18, Ethan Furman <ethan@stoneleaf.us> wrote:
Implementation questions for the __NoException__ route:
1) Do we want double underscores, or just a single one?
I'm thinking double to mark it as special as opposed to private.
Double and exposed allows someone to explicitly the __cause__ to __NoException__ on an existing exception.
2) This is a new exception class -- do we want to store the class itself in __context__, or it's instance? If its class, should we somehow disallow instantiation of it?
3) Should it be an exception, or just inherit from object? Is it worth worrying about somebody trying to raise it, or raise from it?
If it's not actually an exception, we get prevention of instantiation for free. My feeling is just make it a singleton object.
4) Is the name '__NoException__' confusing?
Seems perfectly expressive to me so long as it can't itself be raised. Tim Delaney
On Thu, Feb 2, 2012 at 10:44 AM, Tim Delaney <timothy.c.delaney@gmail.com> wrote:
3) Should it be an exception, or just inherit from object? Is it worth worrying about somebody trying to raise it, or raise from it?
If it's not actually an exception, we get prevention of instantiation for free. My feeling is just make it a singleton object.
Yeah, a new Ellipsis/None style singleton probably makes more sense than an exception instance. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On 2/1/2012 7:49 PM, Nick Coghlan wrote:
On Thu, Feb 2, 2012 at 10:44 AM, Tim Delaney <timothy.c.delaney@gmail.com> wrote:
3) Should it be an exception, or just inherit from object? Is it worth worrying about somebody trying to raise it, or raise from it?
If it's not actually an exception, we get prevention of instantiation for free. My feeling is just make it a singleton object.
Yeah, a new Ellipsis/None style singleton probably makes more sense than an exception instance.
But now we're adding a new singleton, unrelated to exceptions (other than its name) because we don't want to use an existing singleton (False). Maybe the name difference is good enough justification. Eric.
On Thu, Feb 2, 2012 at 11:01 AM, Eric V. Smith <eric@trueblade.com> wrote:
On 2/1/2012 7:49 PM, Nick Coghlan wrote:
On Thu, Feb 2, 2012 at 10:44 AM, Tim Delaney <timothy.c.delaney@gmail.com> wrote:
3) Should it be an exception, or just inherit from object? Is it worth worrying about somebody trying to raise it, or raise from it?
If it's not actually an exception, we get prevention of instantiation for free. My feeling is just make it a singleton object.
Yeah, a new Ellipsis/None style singleton probably makes more sense than an exception instance.
But now we're adding a new singleton, unrelated to exceptions (other than its name) because we don't want to use an existing singleton (False).
Maybe the name difference is good enough justification.
That's exactly the thought process that led me to endorse the idea of using False as the "not set" marker in the first place. With None being stolen to mean "No cause and don't print the context either", the choices become: - set some *other* exception attribute to indicate whether or not to print the context - use an existing singleton like False to mean "not set, use the context" - add a new singleton specifically to mean "not set, use the context" - use a new exception type to mean "not set, use the context" Hmm, after writing up that list, the idea of using "__cause__ is Ellipsis" (or even "__cause__ is ...")to mean "use __context__ instead" occurs to me. After all, "..." has the right connotations of "fill this in from somewhere else", and since we really just want a known sentinel object that isn't None and isn't a meaningful type like the boolean singletons... Regards, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On 2 February 2012 12:43, Nick Coghlan <ncoghlan@gmail.com> wrote:
Hmm, after writing up that list, the idea of using "__cause__ is Ellipsis" (or even "__cause__ is ...")to mean "use __context__ instead" occurs to me. After all, "..." has the right connotations of "fill this in from somewhere else", and since we really just want a known sentinel object that isn't None and isn't a meaningful type like the boolean singletons...
It's cute yet seems appropriate ... I quite like it. Tim Delaney
Tim Delaney wrote:
On 2 February 2012 12:43, Nick Coghlan wrote:
Hmm, after writing up that list, the idea of using "__cause__ is Ellipsis" (or even "__cause__ is ...")to mean "use __context__ instead" occurs to me. After all, "..." has the right connotations of "fill this in from somewhere else", and since we really just want a known sentinel object that isn't None and isn't a meaningful type like the boolean singletons...
It's cute yet seems appropriate ... I quite like it.
I find it very amusing, yet also appropriate -- I'm happy with it. ~Ethan~
PEP: 409 Title: Suppressing exception context Version: $Revision$ Last-Modified: $Date$ Author: Ethan Furman <ethan@stoneleaf.us> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 26-Jan-2012 Post-History: 30-Aug-2002, 01-Feb-2012, 03-Feb-2012 Abstract ======== One of the open issues from PEP 3134 is suppressing context: currently there is no way to do it. This PEP proposes one. Rationale ========= There are two basic ways to generate exceptions: 1) Python does it (buggy code, missing resources, ending loops, etc.) 2) manually (with a raise statement) When writing libraries, or even just custom classes, it can become necessary to raise exceptions; moreover it can be useful, even necessary, to change from one exception to another. To take an example from my dbf module: try: value = int(value) except Exception: raise DbfError(...) Whatever the original exception was (/ValueError/, /TypeError/, or something else) is irrelevant. The exception from this point on is a /DbfError/, and the original exception is of no value. However, if this exception is printed, we would currently see both. Alternatives ============ Several possibilities have been put forth: * /raise as NewException()/ Reuses the /as/ keyword; can be confusing since we are not really reraising the originating exception * /raise NewException() from None/ Follows existing syntax of explicitly declaring the originating exception * /exc = NewException(); exc.__context__ = None; raise exc/ Very verbose way of the previous method * /raise NewException.no_context(...)/ Make context suppression a class method. All of the above options will require changes to the core. Proposal ======== I proprose going with the second option: raise NewException from None It has the advantage of using the existing pattern of explicitly setting the cause: raise KeyError() from NameError() but because the cause is /None/ the previous context is not displayed by the default exception printing routines. Implementation Discussion ========================= Currently, /None/ is the default for both /__context__/ and /__cause__/. In order to support /raise ... from None/ (which would set /__cause__/ to /None/) we need a different default value for /__cause__/. Several ideas were put forth on how to implement this at the language level: * Overwrite the previous exception information (side-stepping the issue and leaving /__cause__/ at /None/). Rejected as this can seriously hinder debugging due to `poor error messages`_. * Use one of the boolean values in /__cause__/: /False/ would be the default value, and would be replaced when /from .../ was used with the explicity chained exception or /None/. Rejected as this encourages the use of two different objects types for /__cause__/ with one of them (boolean) not allowed to have the full range of possible values (/True/ would never be used). * Create a special exception class, /__NoException__/. Rejected as possibly confusing, possibly being mistakenly raised by users, and not being a truly unique value as /None/, /True/, and /False/ are. * Use /Ellipsis/ as the default value (the /.../ singleton). Accepted. There are no other possible values; it cannot be raised as it is not an acception; it has the connotation of 'fill in the rest...' as in /__cause__/ is not set, look in /__context__/ for it. Language Details ================ To support /from None/, /__context__/ will stay as it is, but /__cause__/ will start out as /Ellipsis/ and will change to /None/ when the /raise ... from None/ method is used. ============================== ================== ================== form __context__ __cause__ ============================== ================== ================== raise /None/ /Ellipsis/ reraise previous exception /Ellipsis/ reraise from previous exception /None/ | /None/ | /ChainedException/ explicitly chained exception ============================== ================== ================== The default exception printing routine will then: * If /__cause__/ is /Ellipsis/ the /__context__/ (if any) will be printed. * If /__cause__/ is /None/ the /__context__/ will not be printed. * if /__cause__/ is anything else, /__cause__/ will be printed. Patches ======= There is a patch for CPython implementing this attached to `Issue 6210`_. References ========== Discussion and refinements in this `thread on python-dev`_. .. _poor error messages: http://bugs.python.org/msg152294 .. _issue 6210: http://bugs.python.org/issue6210 .. _Thread on python-dev: http://mail.python.org/pipermail/python-dev/2012-January/115838.html Copyright ========= This document has been placed in the public domain.
On 2/2/2012 2:10 PM, Ethan Furman wrote:
* Use /Ellipsis/ as the default value (the /.../ singleton).
Accepted. There are no other possible values; it cannot be raised as it is not an acception; it has the connotation of 'fill in the rest...' as in /__cause__/ is not set, look in /__context__/ for it.
"exception" rather that "acception" (whatever that means)
Glenn Linderman wrote:
On 2/2/2012 2:10 PM, Ethan Furman wrote:
* Use /Ellipsis/ as the default value (the /.../ singleton).
Accepted. There are no other possible values; it cannot be raised as it is not an acception; it has the connotation of 'fill in the rest...' as in /__cause__/ is not set, look in /__context__/ for it.
"exception" rather that "acception" (whatever that means)
Argh. Kinda sounds like a royal ball... Thanks. ~Ethan~
Great, PEP 409 is accepted with Ellipsis instead of False! On Thu, Feb 2, 2012 at 2:40 PM, Glenn Linderman <v+python@g.nevcal.com> wrote:
On 2/2/2012 2:10 PM, Ethan Furman wrote:
* Use /Ellipsis/ as the default value (the /.../ singleton).
Accepted. There are no other possible values; it cannot be raised as it is not an acception; it has the connotation of 'fill in the rest...' as in /__cause__/ is not set, look in /__context__/ for it.
"exception" rather that "acception" (whatever that means)
_______________________________________________ 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/guido%40python.org
-- --Guido van Rossum (python.org/~guido)
In my opinion using Ellipsis is just wrong. It is completely non-obvious not only to a beginner, but even to an experienced python developer. Writing 'raise Something() from None' looks less suspicious, but still strange. Isn't 'raise Exception().no_context()' or 'raise Exception().no_cause()' more obvious and easy to implement? More readable, less complex and ambiguous. On 2012-02-02, at 5:10 PM, Ethan Furman wrote:
PEP: 409 Title: Suppressing exception context Version: $Revision$ Last-Modified: $Date$ Author: Ethan Furman <ethan@stoneleaf.us> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 26-Jan-2012 Post-History: 30-Aug-2002, 01-Feb-2012, 03-Feb-2012
Abstract ========
One of the open issues from PEP 3134 is suppressing context: currently there is no way to do it. This PEP proposes one.
Rationale =========
There are two basic ways to generate exceptions:
1) Python does it (buggy code, missing resources, ending loops, etc.)
2) manually (with a raise statement)
When writing libraries, or even just custom classes, it can become necessary to raise exceptions; moreover it can be useful, even necessary, to change from one exception to another. To take an example from my dbf module:
try: value = int(value) except Exception: raise DbfError(...)
Whatever the original exception was (/ValueError/, /TypeError/, or something else) is irrelevant. The exception from this point on is a /DbfError/, and the original exception is of no value. However, if this exception is printed, we would currently see both.
Alternatives ============ Several possibilities have been put forth:
* /raise as NewException()/
Reuses the /as/ keyword; can be confusing since we are not really reraising the originating exception
* /raise NewException() from None/
Follows existing syntax of explicitly declaring the originating exception
* /exc = NewException(); exc.__context__ = None; raise exc/
Very verbose way of the previous method
* /raise NewException.no_context(...)/
Make context suppression a class method.
All of the above options will require changes to the core.
Proposal ========
I proprose going with the second option:
raise NewException from None
It has the advantage of using the existing pattern of explicitly setting the cause:
raise KeyError() from NameError()
but because the cause is /None/ the previous context is not displayed by the default exception printing routines.
Implementation Discussion =========================
Currently, /None/ is the default for both /__context__/ and /__cause__/. In order to support /raise ... from None/ (which would set /__cause__/ to /None/) we need a different default value for /__cause__/. Several ideas were put forth on how to implement this at the language level:
* Overwrite the previous exception information (side-stepping the issue and leaving /__cause__/ at /None/).
Rejected as this can seriously hinder debugging due to `poor error messages`_.
* Use one of the boolean values in /__cause__/: /False/ would be the default value, and would be replaced when /from .../ was used with the explicity chained exception or /None/.
Rejected as this encourages the use of two different objects types for /__cause__/ with one of them (boolean) not allowed to have the full range of possible values (/True/ would never be used).
* Create a special exception class, /__NoException__/.
Rejected as possibly confusing, possibly being mistakenly raised by users, and not being a truly unique value as /None/, /True/, and /False/ are.
* Use /Ellipsis/ as the default value (the /.../ singleton).
Accepted. There are no other possible values; it cannot be raised as it is not an acception; it has the connotation of 'fill in the rest...' as in /__cause__/ is not set, look in /__context__/ for it.
Language Details ================
To support /from None/, /__context__/ will stay as it is, but /__cause__/ will start out as /Ellipsis/ and will change to /None/ when the /raise ... from None/ method is used.
============================== ================== ================== form __context__ __cause__ ============================== ================== ================== raise /None/ /Ellipsis/
reraise previous exception /Ellipsis/
reraise from previous exception /None/ | /None/ | /ChainedException/ explicitly chained exception ============================== ================== ==================
The default exception printing routine will then:
* If /__cause__/ is /Ellipsis/ the /__context__/ (if any) will be printed.
* If /__cause__/ is /None/ the /__context__/ will not be printed.
* if /__cause__/ is anything else, /__cause__/ will be printed.
Patches =======
There is a patch for CPython implementing this attached to `Issue 6210`_.
References ==========
Discussion and refinements in this `thread on python-dev`_.
.. _poor error messages: http://bugs.python.org/msg152294 .. _issue 6210: http://bugs.python.org/issue6210 .. _Thread on python-dev: http://mail.python.org/pipermail/python-dev/2012-January/115838.html
Copyright =========
This document has been placed in the public domain.
_______________________________________________ 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/yselivanov.ml%40gmail.com
On Fri, Feb 3, 2012 at 9:32 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
In my opinion using Ellipsis is just wrong. It is completely non-obvious not only to a beginner, but even to an experienced python developer. Writing 'raise Something() from None' looks less suspicious, but still strange.
Beginners will never even see it (unless they're printing out __cause__ explicitly for some unknown reason). Experienced devs can go read language reference or PEP 409 for the rationale (that's one of the reasons we have a PEP process). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Thu, Feb 2, 2012 at 3:41 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Fri, Feb 3, 2012 at 9:32 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
In my opinion using Ellipsis is just wrong. It is completely non-obvious not only to a beginner, but even to an experienced python developer. Writing 'raise Something() from None' looks less suspicious, but still strange.
Beginners will never even see it (unless they're printing out __cause__ explicitly for some unknown reason). Experienced devs can go read language reference or PEP 409 for the rationale (that's one of the reasons we have a PEP process).
I somehow have a feeling that Yury misread the PEP (or maybe my +1) as saying that the syntax for suppressing the context would be "raise <exception> from Ellipsis". That's not the case, it's "from None". -- --Guido van Rossum (python.org/~guido)
On Fri, Feb 3, 2012 at 10:04 AM, Guido van Rossum <guido@python.org> wrote:
On Thu, Feb 2, 2012 at 3:41 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Fri, Feb 3, 2012 at 9:32 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
In my opinion using Ellipsis is just wrong. It is completely non-obvious not only to a beginner, but even to an experienced python developer. Writing 'raise Something() from None' looks less suspicious, but still strange.
Beginners will never even see it (unless they're printing out __cause__ explicitly for some unknown reason). Experienced devs can go read language reference or PEP 409 for the rationale (that's one of the reasons we have a PEP process).
I somehow have a feeling that Yury misread the PEP (or maybe my +1) as saying that the syntax for suppressing the context would be "raise <exception> from Ellipsis". That's not the case, it's "from None".
Oh right, that objection makes more sense. FWIW, I expect the implementation will *allow* "raise exc from Ellipsis" as an odd synonym for "raise exc". I'd want to allow "exc.__cause__ = Ellipsis" to reset an exception with a previously set __cause__ back to the default state, at which point the synonym follows from the semantics of "raise X from Y" as syntactic sugar for "_exc = X; _exc.__cause__ = Y; raise _exc" Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Thu, Feb 2, 2012 at 4:34 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Fri, Feb 3, 2012 at 10:04 AM, Guido van Rossum <guido@python.org> wrote:
On Thu, Feb 2, 2012 at 3:41 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Fri, Feb 3, 2012 at 9:32 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
In my opinion using Ellipsis is just wrong. It is completely non-obvious not only to a beginner, but even to an experienced python developer. Writing 'raise Something() from None' looks less suspicious, but still strange.
Beginners will never even see it (unless they're printing out __cause__ explicitly for some unknown reason). Experienced devs can go read language reference or PEP 409 for the rationale (that's one of the reasons we have a PEP process).
I somehow have a feeling that Yury misread the PEP (or maybe my +1) as saying that the syntax for suppressing the context would be "raise <exception> from Ellipsis". That's not the case, it's "from None".
Oh right, that objection makes more sense.
FWIW, I expect the implementation will *allow* "raise exc from Ellipsis" as an odd synonym for "raise exc". I'd want to allow "exc.__cause__ = Ellipsis" to reset an exception with a previously set __cause__ back to the default state, at which point the synonym follows from the semantics of "raise X from Y" as syntactic sugar for "_exc = X; _exc.__cause__ = Y; raise _exc"
Sure. But those are all rather obscure cases. Ellipsis reads no less or more obscure than False when written explicitly. But that doesn't bother me. -- --Guido van Rossum (python.org/~guido)
Nick Coghlan wrote:
FWIW, I expect the implementation will *allow* "raise exc from Ellipsis" as an odd synonym for "raise exc".
Are we sure we want that? Raising from something not an exception seems counter-intuitive (None being the obvious exception).
I'd want to allow "exc.__cause__ = Ellipsis" to reset an exception with a previously set __cause__ back to the default state,
Already done. :)
at which point the synonym follows from the semantics of "raise X from Y" as syntactic sugar for "_exc = X; _exc.__cause__ = Y; raise _exc"
I can see where it would make some sense that way, but it still seems odd. ~Ethan~
On Fri, Feb 3, 2012 at 12:42 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
Nick Coghlan wrote:
FWIW, I expect the implementation will *allow* "raise exc from Ellipsis" as an odd synonym for "raise exc".
Are we sure we want that? Raising from something not an exception seems counter-intuitive (None being the obvious exception).
It isn't so much a matter of wanting it as "Is it problematic enough to put any effort into preventing it?" (since allowing it is a natural outcome of the obvious implementation). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Thu, Feb 2, 2012 at 6:49 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Fri, Feb 3, 2012 at 12:42 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
Nick Coghlan wrote:
FWIW, I expect the implementation will *allow* "raise exc from Ellipsis" as an odd synonym for "raise exc".
Are we sure we want that? Raising from something not an exception seems counter-intuitive (None being the obvious exception).
It isn't so much a matter of wanting it as "Is it problematic enough to put any effort into preventing it?" (since allowing it is a natural outcome of the obvious implementation).
I would say yes we want that. It would be strange if you couldn't reset a variable explicitly to its default value. I don't expect people to do this often. But somebody might want to do a deep copy of an exception (with some systematic change), or there might be other reasons. I'm sure a few Python zen items apply here. :-) -- --Guido van Rossum (python.org/~guido)
Guido van Rossum wrote:
On Thu, Feb 2, 2012 at 6:49 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Fri, Feb 3, 2012 at 12:42 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
Nick Coghlan wrote:
FWIW, I expect the implementation will *allow* "raise exc from Ellipsis" as an odd synonym for "raise exc".
Are we sure we want that? Raising from something not an exception seems counter-intuitive (None being the obvious exception). It isn't so much a matter of wanting it as "Is it problematic enough to put any effort into preventing it?" (since allowing it is a natural outcome of the obvious implementation).
I would say yes we want that. It would be strange if you couldn't reset a variable explicitly to its default value. I don't expect people to do this often. But somebody might want to do a deep copy of an exception (with some systematic change), or there might be other reasons. I'm sure a few Python zen items apply here. :-)
Okey-doke, I'll get it going. ~Ethan~
On 3 February 2012 13:54, Guido van Rossum <guido@python.org> wrote:
On Thu, Feb 2, 2012 at 6:49 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Fri, Feb 3, 2012 at 12:42 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
Nick Coghlan wrote:
FWIW, I expect the implementation will *allow* "raise exc from Ellipsis" as an odd synonym for "raise exc".
Are we sure we want that? Raising from something not an exception seems counter-intuitive (None being the obvious exception).
It isn't so much a matter of wanting it as "Is it problematic enough to put any effort into preventing it?" (since allowing it is a natural outcome of the obvious implementation).
I would say yes we want that. It would be strange if you couldn't reset a variable explicitly to its default value.
In that case, would the best syntax be: raise Exception() from Ellipsis or: raise Exception() from ... ? I kinda like the second - it feels more self-descriptive to me than "from Ellipsis" - but there's the counter-argument that it could look like noise, and I think would require a grammar change to allow it there. Tim Delaney
Tim Delaney wrote:
In that case, would the best syntax be:
raise Exception() from Ellipsis
or:
raise Exception() from ...
? I kinda like the second - it feels more self-descriptive to me than "from Ellipsis" - but there's the counter-argument that it could look like noise, and I think would require a grammar change to allow it there.
raise Exception() from ... is... well, I am now gleeful -- especially since I went to my fresh copy of Python 3.3.0a0 and did this: --> ... Ellipsis --> raise ValueError from ... Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError Have I said lately how much I *love* Python? ~Ethan~
Re "raise ValueError from ..." So what does it mean now? Just resetting __cause__ to make __context__ printed? Can you show the down-to-earth snippet of code where such syntax would be useful? Speaking of Zen of Python - I think this stuff contradicts with it more than it follows. On 2012-02-02, at 10:43 PM, Ethan Furman wrote:
Tim Delaney wrote:
In that case, would the best syntax be: raise Exception() from Ellipsis or: raise Exception() from ... ? I kinda like the second - it feels more self-descriptive to me than "from Ellipsis" - but there's the counter-argument that it could look like noise, and I think would require a grammar change to allow it there.
raise Exception() from ...
is... well, I am now gleeful -- especially since I went to my fresh copy of Python 3.3.0a0 and did this:
--> ... Ellipsis
--> raise ValueError from ... Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError
Have I said lately how much I *love* Python?
~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/yselivanov.ml%40gmail.com
Yury Selivanov wrote:
Re "raise ValueError from ..."
So what does it mean now? Just resetting __cause__ to make __context__ printed?
Whatever __cause__ was before (None, or an actual exception), it is now Ellipsis -- so __context__ will be printed and the exception chain will be followed.
Can you show the down-to-earth snippet of code where such syntax would be useful?
Not sure I'll ever use it this way, but: try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all raise e from Ellipsis ~Ethan~
While the example is valid, I doubt that it is in any sense "common" case. OTOH the language will allow strange mess of reserved words with '...', that hurts readability and even gives you an instrument to write tangled and obscured code. Most of the python code is readable in plain english, that's something a lot of people fond of. I can't read 'raise from ...' or 'raise from Ellipsis', and I even had mixed understanding of it after reading the PEP. It's much more than a simple behaviour of "raise from None" (which many of us eagerly want). I'm -1 on adding 'raise from ...'. On 2012-02-03, at 11:52 AM, Ethan Furman wrote:
Yury Selivanov wrote:
Re "raise ValueError from ..." So what does it mean now? Just resetting __cause__ to make __context__ printed?
Whatever __cause__ was before (None, or an actual exception), it is now Ellipsis -- so __context__ will be printed and the exception chain will be followed.
Can you show the down-to-earth snippet of code where such syntax would be useful?
Not sure I'll ever use it this way, but:
try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all raise e from Ellipsis
~Ethan~
Yury Selivanov wrote:
While the example is valid, I doubt that it is in any sense "common" case.
No it is a corner case. Another way to spell it is: try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all e.__cause__ = Ellipsis raise e Ethan
I got it, and I think it's fine to use explicit __cause__ reset, using Ellipsis, or even some __NoException__ special object if we decide to introduce one. I'm against allowing 'from ...' syntax. On 2012-02-03, at 12:29 PM, Ethan Furman wrote:
Yury Selivanov wrote:
While the example is valid, I doubt that it is in any sense "common" case.
No it is a corner case. Another way to spell it is:
try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all e.__cause__ = Ellipsis raise e
Ethan
Yury Selivanov wrote:
I got it, and I think it's fine to use explicit __cause__ reset, using Ellipsis, or even some __NoException__ special object if we decide to introduce one.
I'm against allowing 'from ...' syntax.
Well, ... /is/ Ellipsis -- no way to tell them apart by them time this part of the code sees it. ~Ethan~
;) I completely understand what Ellipsis object and its short syntax (...) is. And for me 'raise from Ellipsis' or 'raise from ...', or even using the Ellipsis object internally instead of special __NoContext__ object is godawful. Why do we want to use some completely unrelated singleton in the exception contexts? Is the policy of "think before adding a new builtin object" really worth it in this concrete case? On 2012-02-03, at 1:01 PM, Ethan Furman wrote:
Yury Selivanov wrote:
I got it, and I think it's fine to use explicit __cause__ reset, using Ellipsis, or even some __NoException__ special object if we decide to introduce one. I'm against allowing 'from ...' syntax.
Well, ... /is/ Ellipsis -- no way to tell them apart by them time this part of the code sees it.
~Ethan~
On Feb 03, 2012, at 08:52 AM, Ethan Furman wrote:
Not sure I'll ever use it this way, but:
try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all raise e from Ellipsis
In that context, I have to say that the last line, even if it were written raise e from ... is certainly cute, but not very informative. Triple-dots will be confusing and difficult to read in documentation and code, and Ellipsis has no logical connection to the purpose of this PEP. So while I'm +1 on everything else in the PEP, I'm -1 on this particular decision. One of the alternatives states: Create a special exception class, __NoException__. Rejected as possibly confusing, possibly being mistakenly raised by users, and not being a truly unique value as None, True, and False are. I think this should be revisited. First, `__NoException__` doesn't need to be an exception class. Ellipsis isn't so this doesn't need to be either. I have no problem adding a new non-exception derived singleton to mark this. And while __NoException__ may be a little confusing, something like __NoCause__ reads great and can't be mistaken for a raiseable exception. So your example would then be: try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all raise e from __NoCause__ Cheers, -Barry
Barry Warsaw wrote:
raise e from ...
is certainly cute, but not very informative. Triple-dots will be confusing and difficult to read in documentation and code, and Ellipsis has no logical connection to the purpose of this PEP. So while I'm +1 on everything else in the PEP, I'm -1 on this particular decision.
One of the alternatives states:
Create a special exception class, __NoException__.
Rejected as possibly confusing, possibly being mistakenly raised by users, and not being a truly unique value as None, True, and False are.
I think this should be revisited. First, `__NoException__` doesn't need to be an exception class. Ellipsis isn't so this doesn't need to be either. I have no problem adding a new non-exception derived singleton to mark this. And while __NoException__ may be a little confusing, something like __NoCause__ reads great and can't be mistaken for a raiseable exception.
The problem I have with names like __NoException__, __NoCause__, __NoWhatever__ is that is sounds a lot like None -- in otherwords, like there won't be any chaining.
So your example would then be:
try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all raise e from __NoCause__
If we do switch from Ellipsis to something else I think a name like __Chain__ would be more appropriate. Or __ExcChain__. raise e from __ExcChain__ Less cute, but probably less confusing. ~Ethan~
Funny thing, it seems like you don't get it in the same way I did not in the first place. His example is more like: try: try: raise IndexError() except: raise CustomError() from __NoContext__ except CustomError as e: # nevermind, let's see the whole thing after all raise e from __OupsLooksLikeINeedContextAfterAll__ On 2012-02-03, at 12:29 PM, Barry Warsaw wrote:
On Feb 03, 2012, at 08:52 AM, Ethan Furman wrote:
Not sure I'll ever use it this way, but:
try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all raise e from Ellipsis
In that context, I have to say that the last line, even if it were written
raise e from ...
is certainly cute, but not very informative. Triple-dots will be confusing and difficult to read in documentation and code, and Ellipsis has no logical connection to the purpose of this PEP. So while I'm +1 on everything else in the PEP, I'm -1 on this particular decision.
One of the alternatives states:
Create a special exception class, __NoException__.
Rejected as possibly confusing, possibly being mistakenly raised by users, and not being a truly unique value as None, True, and False are.
I think this should be revisited. First, `__NoException__` doesn't need to be an exception class. Ellipsis isn't so this doesn't need to be either. I have no problem adding a new non-exception derived singleton to mark this. And while __NoException__ may be a little confusing, something like __NoCause__ reads great and can't be mistaken for a raiseable exception.
So your example would then be:
try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all raise e from __NoCause__
Cheers, -Barry _______________________________________________ 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/yselivanov.ml%40gmail.com
On Fri, Feb 3, 2012 at 9:29 AM, Barry Warsaw <barry@python.org> wrote:
On Feb 03, 2012, at 08:52 AM, Ethan Furman wrote:
Not sure I'll ever use it this way, but:
try: try: raise IndexError() except: raise CustomError() from None except CustomError as e: # nevermind, let's see the whole thing after all raise e from Ellipsis
In that context, I have to say that the last line, even if it were written
raise e from ...
is certainly cute, but not very informative.
Please. Let's stop this. There is no known use case to ever write that. We're just not putting specific measures to prevent it. Writing
a = ...
Is likewise cute but not very informative. But it is valid syntax. -- --Guido van Rossum (python.org/~guido)
On 2012-02-03, at 1:20 PM, Guido van Rossum wrote:
Please. Let's stop this. There is no known use case to ever write that. We're just not putting specific measures to prevent it. Writing
a = ...
Is likewise cute but not very informative. But it is valid syntax.
Well, right now you'll get TypeError if you want to raise an exception from something that is not an exception. 'raise from None' will loosen the check allowing None values, in the 'raise from' statement, but that should be it. To achieve the same effect as 'raise from ...' just do 'e.__cause__ = ...'. On the question of using Ellipsis instead of some new singleton like __NoContext__: how's Ellipsis semantically related to exceptions after all? - Yury
Yury Selivanov wrote:
On 2012-02-03, at 1:20 PM, Guido van Rossum wrote:
Please. Let's stop this. There is no known use case to ever write that. We're just not putting specific measures to prevent it. Writing
a = ... Is likewise cute but not very informative. But it is valid syntax.
Well, right now you'll get TypeError if you want to raise an exception from something that is not an exception. 'raise from None' will loosen the check allowing None values, in the 'raise from' statement, but that should be it.
To achieve the same effect as 'raise from ...' just do 'e.__cause__ = ...'.
On the question of using Ellipsis instead of some new singleton like __NoContext__: how's Ellipsis semantically related to exceptions after all?
Merrian Webster says: --------------------- el·lip·sis noun \i-ˈlip-səs, e-\ plural el·lip·ses\-ˌsēz\ Definition of ELLIPSIS 1 a : the omission of one or more words that are obviously understood but that must be supplied to make a construction grammatically complete --------------------- Relation to exceptions: Two places to look: __context__ and __cause__ Priority? __cause__ When do we check __context__? if __cause__ is omitted (or Ellipsis) ~Ethan~
That's a bit far-fetched. Using same level argumentation we can utilize even `0`. `raise e from 0` (or `-1`), and use `0` object instead of Ellipsis. Anyways, if the PEP is not yet fully approved, I'm minus one on allowing of using anything other than Exception instance or None in 'raise from' statement. On 2012-02-03, at 2:03 PM, Ethan Furman wrote:
Yury Selivanov wrote:
On 2012-02-03, at 1:20 PM, Guido van Rossum wrote:
Please. Let's stop this. There is no known use case to ever write that. We're just not putting specific measures to prevent it. Writing
a = ... Is likewise cute but not very informative. But it is valid syntax. Well, right now you'll get TypeError if you want to raise an exception from something that is not an exception. 'raise from None' will loosen the check allowing None values, in the 'raise from' statement, but that should be it. To achieve the same effect as 'raise from ...' just do 'e.__cause__ = ...'. On the question of using Ellipsis instead of some new singleton like __NoContext__: how's Ellipsis semantically related to exceptions after all?
Merrian Webster says: --------------------- el·lip·sis noun \i-ˈlip-səs, e-\ plural el·lip·ses\-ˌsēz\ Definition of ELLIPSIS 1 a : the omission of one or more words that are obviously understood but that must be supplied to make a construction grammatically complete ---------------------
Relation to exceptions: Two places to look: __context__ and __cause__ Priority? __cause__ When do we check __context__? if __cause__ is omitted (or Ellipsis)
~Ethan~
On Fri, Feb 3, 2012 at 11:18 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
That's a bit far-fetched. Using same level argumentation we can utilize even `0`. `raise e from 0` (or `-1`), and use `0` object instead of Ellipsis.
Anyways, if the PEP is not yet fully approved, I'm minus one on allowing of using anything other than Exception instance or None in 'raise from' statement.
I read your objection and disagree. The PEP *is* fully approved.
On 2012-02-03, at 2:03 PM, Ethan Furman wrote:
Yury Selivanov wrote:
On 2012-02-03, at 1:20 PM, Guido van Rossum wrote:
Please. Let's stop this. There is no known use case to ever write that. We're just not putting specific measures to prevent it. Writing
> a = ... Is likewise cute but not very informative. But it is valid syntax. Well, right now you'll get TypeError if you want to raise an exception from something that is not an exception. 'raise from None' will loosen the check allowing None values, in the 'raise from' statement, but that should be it. To achieve the same effect as 'raise from ...' just do 'e.__cause__ = ...'. On the question of using Ellipsis instead of some new singleton like __NoContext__: how's Ellipsis semantically related to exceptions after all?
Merrian Webster says: --------------------- el·lip·sis noun \i-ˈlip-səs, e-\ plural el·lip·ses\-ˌsēz\ Definition of ELLIPSIS 1 a : the omission of one or more words that are obviously understood but that must be supplied to make a construction grammatically complete ---------------------
Relation to exceptions: Two places to look: __context__ and __cause__ Priority? __cause__ When do we check __context__? if __cause__ is omitted (or Ellipsis)
~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/guido%40python.org
-- --Guido van Rossum (python.org/~guido)
On 3 February 2012 19:18, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
That's a bit far-fetched. Using same level argumentation we can utilize even `0`. `raise e from 0` (or `-1`), and use `0` object instead of Ellipsis.
Anyways, if the PEP is not yet fully approved, I'm minus one on allowing of using anything other than Exception instance or None in 'raise from' statement.
I may have missed something here, but as far as I am aware, the PEP is fundamentally only about allowing raise...from None to suppress chaining. There is an extremely obscure case where certain (generally library, not end user) code might want to reinstate chaining. For that very obscure case, the PEP suggests setting __cause__ to a sentinel value, and Ellipsis is used rather than inventing a new singleton for such a rare case. Purely by accident, the form "raise X from ..." will do the same as explicitly setting __cause__, and it's not worth the effort of testing for and rejecting this case. This issue is so not worth arguing about, it's silly. Paul.
On Feb 03, 2012, at 10:20 AM, Guido van Rossum wrote:
a = ...
Is likewise cute but not very informative. But it is valid syntax.
FWIW (probably not much at this point), it's not the syntax I have a problem with, but the semantics as described in the PEP of setting __cause__ to Ellipsis to mean use __context__. -Barry
On 2/3/2012 9:53 AM, Yury Selivanov wrote:
Re "raise ValueError from ..."
The use cases for Ellipsis/... are 99.99% internal. The typical Python programmer will never see or have cause to worry about such a thing. The problem is that we really want an exception attribute that is missing in certain cases. But C does not allow missing struct members (the corresponding block of memory *will* have some bit pattern!). So unset attributes requires a dict instead of slots (I am presuming each builting exception class uses slots now) and the use of the C equivalent of hasattr (or try: except:) and delattr. So instead the proposal is to use a marker value that effectively means 'unset' or 'unspecified'. But what? None cannot be used because it is being used as a set value. Ethan initially proposed 'False', but then realizaed that 'True' fits as well, so neither fit. I proposed a new internal exception class primarily to get us thinking about alternatives to True/False. Ellipsis, properly understoo, comes close to meaning 'unspecified'. My memory is that that it how it is used in NumPy slicings. The manual gives no meaning for Ellipsis, only saying that it is used in slicings. The linked slicings section does not mention it. Ethan: I think the PEP should say more about ... being a grammatical placeholder in English, much like 'pass' is in Python. Otherwise, we will see periodic posts objecting to it in python-list. -- Terry Jan Reedy
On 2012-02-03, at 7:23 PM, Terry Reedy wrote:
On 2/3/2012 9:53 AM, Yury Selivanov wrote:
Re "raise ValueError from ..."
The use cases for Ellipsis/... are 99.99% internal. The typical Python programmer will never see or have cause to worry about such a thing.
I get your points. But I don't like this argument about some spherical "typical Python programmer". Any programmer at some point may go and investigate some bug in stdlib or any other library and see this "raise Exc() from ...", or "e = Exc(); e.__cause__ = ...; raise e" nonsense. BTW, will "raise .. from .." statement allow raising only from exceptions, None, and Ellipsis exclusively, or any python object can be used? Right now it would throw a TypeError if you try to raise from None or Ellipsis. And as Benjamin said in the later latter of his -- simple __chain__ attribute will be much more understandable, easy to document and explain. That can be used as simple as writing "raise Exception().no_chaining()" or something like that. - Yury
On Fri, Feb 3, 2012 at 1:34 PM, Tim Delaney <timothy.c.delaney@gmail.com> wrote:
? I kinda like the second - it feels more self-descriptive to me than "from Ellipsis" - but there's the counter-argument that it could look like noise, and I think would require a grammar change to allow it there.
Both will be allowed - in 3.x, '...' is just an ordinary expression that means exactly the same thing as the builtin Ellipsis:
Ellipsis Ellipsis ... Ellipsis
Sane code almost certainly won't include *either* form, though. If you're reraising an exception, you should generally be leaving __cause__ and __context__ alone, and if you're raising a *new* exception, then __cause__ will already be Ellipsis by default - you only need to use "raise X from Y" to set it to something *else*. As I noted earlier, supporting Ellipsis in the "raise X from Y" syntax shouldn't require a code change in Ethan's implementation, just a few additional tests to ensure it works as expected. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On 3 February 2012 15:02, Nick Coghlan <ncoghlan@gmail.com> wrote:
Both will be allowed - in 3.x, '...' is just an ordinary expression that means exactly the same thing as the builtin Ellipsis:
Ellipsis Ellipsis ... Ellipsis
I'd totally forgotten that was the case in 3.x ... it's still not exactly common to use Ellipsis/... directly except in extended slicing.
Sane code almost certainly won't include *either* form, though. If you're reraising an exception, you should generally be leaving __cause__ and __context__ alone, and if you're raising a *new* exception, then __cause__ will already be Ellipsis by default - you only need to use "raise X from Y" to set it to something *else*.
Absolutely - I can't think of a reason to want to reraise an existing exception while supressing any existing __cause__ in favour of __context__. But I'm sure someone can. Tim Delaney
Good news! PEP 409 has been accepted! Not so good news: There is no one assigned to Issue 6210 to review the patches... any volunteers? http://bugs.python.org/issue6210 ~Ethan~
2012/2/3 Ethan Furman <ethan@stoneleaf.us>:
Good news! PEP 409 has been accepted!
It may be too late for this, but I find the whole Ellipsis business most unpleasant. Why not just have a extra attribute on exception objects like __chain__ = False/True? -- Regards, Benjamin
On Fri, 3 Feb 2012 19:19:21 -0500 Benjamin Peterson <benjamin@python.org> wrote:
2012/2/3 Ethan Furman <ethan@stoneleaf.us>:
Good news! PEP 409 has been accepted!
It may be too late for this, but I find the whole Ellipsis business most unpleasant. Why not just have a extra attribute on exception objects like __chain__ = False/True?
Incredibly agreed with Benjamin. Regards Antoine.
On Fri, Feb 3, 2012 at 22:14, Ethan Furman <ethan@stoneleaf.us> wrote:
Good news! PEP 409 has been accepted!
Not so good news: There is no one assigned to Issue 6210 to review the patches... any volunteers?
Hi Ethan, I've just looked at PEP 409 online (http://www.python.org/dev/peps/pep-0409/) and I'm not sure where it details the final syntax that was chosen. The "Proposal" section says: " I proprose going with the second option: raise NewException from None " This makes no mention of ellipsis / .... Could you please clarify the PEP to make it detail the new syntax and its proposed semantics more precisely? Thanks in advance, Eli
There is no new syntax! It's going to remain "raise <expression1> from <expression2>". The types of the expressions are constrained by the runtime, not by the syntax. If either type is unacceptable, a TypeError (with the default context :-) will be raised. None of that is new. Really, there is no new syntax to clarify, only new allowable types for <expression2>, and a new meaning assigned to those types. On Fri, Feb 3, 2012 at 7:28 PM, Eli Bendersky <eliben@gmail.com> wrote:
On Fri, Feb 3, 2012 at 22:14, Ethan Furman <ethan@stoneleaf.us> wrote:
Good news! PEP 409 has been accepted!
Not so good news: There is no one assigned to Issue 6210 to review the patches... any volunteers?
Hi Ethan,
I've just looked at PEP 409 online (http://www.python.org/dev/peps/pep-0409/) and I'm not sure where it details the final syntax that was chosen.
The "Proposal" section says:
" I proprose going with the second option:
raise NewException from None "
This makes no mention of ellipsis / ....
Could you please clarify the PEP to make it detail the new syntax and its proposed semantics more precisely?
Thanks in advance, Eli _______________________________________________ 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/guido%40python.org
-- --Guido van Rossum (python.org/~guido)
participants (14)
-
Antoine Pitrou -
Barry Warsaw -
Benjamin Peterson -
Eli Bendersky -
Eric V. Smith -
Ethan Furman -
Glenn Linderman -
Guido van Rossum -
Matt Joiner -
Nick Coghlan -
Paul Moore -
Terry Reedy -
Tim Delaney -
Yury Selivanov