[Python-Dev] PEP for allowing 'raise NewException from None' (original) (raw)
Nick Coghlan ncoghlan at gmail.com
Fri Jan 27 06🔞49 CET 2012
- Previous message: [Python-Dev] PEP for allowing 'raise NewException from None'
- Next message: [Python-Dev] PEP for allowing 'raise NewException from None'
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Fri, Jan 27, 2012 at 1:54 PM, Benjamin Peterson <benjamin at python.org> wrote:
BTW, I don't really think this needs a PEP.
That's largely my influence - the discussion in the relevant tracker item (http://bugs.python.org/issue6210) had covered enough ground that I didn't notice that Ethan's specific proposal isn't a syntax change, but is rather just a matter of giving some additional semantics to the "raise X from Y" syntax (some of the other suggestions like "raise as " really were syntax changes).
So I've changed my mind to being +1 on the idea and proposed syntax of the draft PEP, but I think there are still some details to be worked through in terms of the detailed semantics. (The approach in Ethan's patch actually clobbers the context info when "from None" is used, and I don't believe that's a good idea. My own suggestions in the tracker item aren't very good either, for exactly the same reason)
Currently, the raise from syntax is just syntactic sugar for setting cause manually:
try: ... 1/0 ... except ZeroDivisionError as ex: ... new_exc = ValueError("Denominator is zero") ... new_exc.cause = ex ... raise new_exc ... Traceback (most recent call last): File "", line 2, in ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last): File "", line 6, in ValueError: Denominator is zero
The context information isn't lost in that case, the display of it is simply suppressed when an explicit cause is set:
try: ... try: ... 1/0 ... except ZeroDivisionError as ex: ... new_exc = ValueError() ... new_exc.cause = ex ... raise new_exc ... except ValueError as ex: ... saved = ex ... saved.context ZeroDivisionError('division by zero',) saved.cause ZeroDivisionError('division by zero',)
This behaviour (i.e. preserving the context, but not displaying it by default) is retained when using the dedicated syntax:
try: ... try: ... 1/0 ... except ZeroDivisionError as ex: ... raise ValueError() from ex ... except ValueError as ex: ... saved = ex ... saved.context ZeroDivisionError('division by zero',) saved.cause ZeroDivisionError('division by zero',)
However, if you try to set the cause to None explicitly, then the display falls back to showing the context:
try: ... 1/0 ... except ZeroDivisionError as ex: ... new_exc = ValueError("Denominator is zero") ... new_exc.cause = None ... raise new_exc ... Traceback (most recent call last): File "", line 2, in ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last): File "", line 6, in ValueError: Denominator is zero
This happens because None is used by the exception display logic to indicate "no specific cause, so report the context if that is set".
My proposal would be that instead of using None as the "not set" sentinel value for cause, we instead use a dedicated sentinel object (exposed to Python at least as "BaseException().cause", but potentially being given its own name somewhere).
Then the display logic for exceptions would be changed to be:
- if the cause is None, then don't report a cause or exception context at all
- if the cause is BaseException().cause, report the exception context (from context)
- otherwise report cause as the specific cause of the raised exception
That way we make it easy to emit nicer default tracebacks when replacing exceptions without completely hiding the potentially useful data that can be provided by retaining information in context.
I've been burnt by too much code that replaces detailed, informative and useful error messages that tell me exactly what is going wrong with bland, useless garbage to be in favour of an approach that doesn't even set the context attribute in the first place. If context is always set regardless, and then cause is used to control whether or not context gets displayed in the standard tracebacks, that's a much more flexible approach.
Cheers, Nick.
-- Nick Coghlan  |  ncoghlan at gmail.com  |  Brisbane, Australia
- Previous message: [Python-Dev] PEP for allowing 'raise NewException from None'
- Next message: [Python-Dev] PEP for allowing 'raise NewException from None'
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]