This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author mark.dickinson
Recipients cool-RR, mark.dickinson, steven.daprano
Date 2021-01-23.12:08:29
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1611403710.11.0.552470383388.issue43002@roundup.psfhosted.org>
In-reply-to
Content
Ram: I think you're conflating two separate things, here:

(1) The ability to use an exception *class* instead of an exception *instance* in the "from" clause - that is, the ability to do "raise ValueError from TypeError" in place of "raise ValueError from TypeError()"

(2) The lack of a traceback from the local exception-handling context when doing raise from.

The two are independent: you'll see the same lack of traceback that you described if you do "raise ValueError from TypeError()" instead of "raise ValueError from TypeError".

Both behaviours are by design (as Steven already pointed out for (2)). However, on point (1), there may be a documentation bug here. The reference manual, under https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement, says:

> The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable).

However, this description appears not to match the implementation. In the case that the second expression is an exception class, it's *not* attached to the raised exception as the __cause__ attribute. Instead, the exception class is first instantiated, and then the resulting exception *instance* is attached to the raised exception as the __cause__ attribute.

The corresponding part of the implementation is here: https://github.com/python/cpython/blob/b745a6143ae79efe00aa46affe5ea31a06b0b532/Python/ceval.c#L4758-L4763

Demonstration:

    >>> try:
    ...     raise ZeroDivisionError() from RuntimeError
    ... except Exception as e:
    ...     exc = e
    ... 
    >>> exc.__cause__
    RuntimeError()
    >>> exc.__cause__ is RuntimeError  # reference manual would suggest this is True
    False
    >>> isinstance(exc.__cause__, RuntimeError)  # actual behaviour
    True
History
Date User Action Args
2021-01-23 12:08:30mark.dickinsonsetrecipients: + mark.dickinson, steven.daprano, cool-RR
2021-01-23 12:08:30mark.dickinsonsetmessageid: <1611403710.11.0.552470383388.issue43002@roundup.psfhosted.org>
2021-01-23 12:08:30mark.dickinsonlinkissue43002 messages
2021-01-23 12:08:29mark.dickinsoncreate