mirror of
https://github.com/python/cpython.git
synced 2025-11-10 06:24:12 +00:00
bpo-23556: [doc] Fix inaccuracy in documentation for raise without args. Improve tests for context in nested except handlers. (GH-29236)
This commit is contained in:
parent
606e496dd6
commit
08c0ed2d9c
3 changed files with 36 additions and 19 deletions
|
|
@ -38,15 +38,14 @@ information on defining exceptions is available in the Python Tutorial under
|
||||||
Exception context
|
Exception context
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
When raising (or re-raising) an exception in an :keyword:`except` or
|
When raising a new exception while another exception
|
||||||
:keyword:`finally` clause
|
is already being handled, the new exception's
|
||||||
:attr:`__context__` is automatically set to the last exception caught; if the
|
:attr:`__context__` attribute is automatically set to the handled
|
||||||
new exception is not handled the traceback that is eventually displayed will
|
exception. An exception may be handled when an :keyword:`except` or
|
||||||
include the originating exception(s) and the final exception.
|
:keyword:`finally` clause, or a :keyword:`with` statement, is used.
|
||||||
|
|
||||||
When raising a new exception (rather than using a bare ``raise`` to re-raise
|
This implicit exception context can be
|
||||||
the exception currently being handled), the implicit exception context can be
|
supplemented with an explicit cause by using :keyword:`!from` with
|
||||||
supplemented with an explicit cause by using :keyword:`from<raise>` with
|
|
||||||
:keyword:`raise`::
|
:keyword:`raise`::
|
||||||
|
|
||||||
raise new_exc from original_exc
|
raise new_exc from original_exc
|
||||||
|
|
|
||||||
|
|
@ -563,10 +563,10 @@ The :keyword:`!raise` statement
|
||||||
.. productionlist:: python-grammar
|
.. productionlist:: python-grammar
|
||||||
raise_stmt: "raise" [`expression` ["from" `expression`]]
|
raise_stmt: "raise" [`expression` ["from" `expression`]]
|
||||||
|
|
||||||
If no expressions are present, :keyword:`raise` re-raises the last exception
|
If no expressions are present, :keyword:`raise` re-raises the
|
||||||
that was active in the current scope. If no exception is active in the current
|
exception that is currently being handled, which is also known as the *active exception*.
|
||||||
scope, a :exc:`RuntimeError` exception is raised indicating that this is an
|
If there isn't currently an active exception, a :exc:`RuntimeError` exception is raised
|
||||||
error.
|
indicating that this is an error.
|
||||||
|
|
||||||
Otherwise, :keyword:`raise` evaluates the first expression as the exception
|
Otherwise, :keyword:`raise` evaluates the first expression as the exception
|
||||||
object. It must be either a subclass or an instance of :class:`BaseException`.
|
object. It must be either a subclass or an instance of :class:`BaseException`.
|
||||||
|
|
@ -581,8 +581,8 @@ The :dfn:`type` of the exception is the exception instance's class, the
|
||||||
A traceback object is normally created automatically when an exception is raised
|
A traceback object is normally created automatically when an exception is raised
|
||||||
and attached to it as the :attr:`__traceback__` attribute, which is writable.
|
and attached to it as the :attr:`__traceback__` attribute, which is writable.
|
||||||
You can create an exception and set your own traceback in one step using the
|
You can create an exception and set your own traceback in one step using the
|
||||||
:meth:`with_traceback` exception method (which returns the same exception
|
:meth:`~BaseException.with_traceback` exception method (which returns the
|
||||||
instance, with its traceback set to its argument), like so::
|
same exception instance, with its traceback set to its argument), like so::
|
||||||
|
|
||||||
raise Exception("foo occurred").with_traceback(tracebackobj)
|
raise Exception("foo occurred").with_traceback(tracebackobj)
|
||||||
|
|
||||||
|
|
@ -614,8 +614,10 @@ exceptions will be printed::
|
||||||
File "<stdin>", line 4, in <module>
|
File "<stdin>", line 4, in <module>
|
||||||
RuntimeError: Something bad happened
|
RuntimeError: Something bad happened
|
||||||
|
|
||||||
A similar mechanism works implicitly if an exception is raised inside an
|
A similar mechanism works implicitly if a new exception is raised when
|
||||||
exception handler or a :keyword:`finally` clause: the previous exception is then
|
an exception is already being handled. An exception may be handled
|
||||||
|
when an :keyword:`except` or :keyword:`finally` clause, or a
|
||||||
|
:keyword:`with` statement, is used. The previous exception is then
|
||||||
attached as the new exception's :attr:`__context__` attribute::
|
attached as the new exception's :attr:`__context__` attribute::
|
||||||
|
|
||||||
>>> try:
|
>>> try:
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ class TestContext(unittest.TestCase):
|
||||||
except:
|
except:
|
||||||
raise OSError()
|
raise OSError()
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
self.assertEqual(e.__context__, context)
|
self.assertIs(e.__context__, context)
|
||||||
else:
|
else:
|
||||||
self.fail("No exception raised")
|
self.fail("No exception raised")
|
||||||
|
|
||||||
|
|
@ -315,7 +315,7 @@ class TestContext(unittest.TestCase):
|
||||||
except:
|
except:
|
||||||
raise OSError()
|
raise OSError()
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
self.assertNotEqual(e.__context__, context)
|
self.assertIsNot(e.__context__, context)
|
||||||
self.assertIsInstance(e.__context__, context)
|
self.assertIsInstance(e.__context__, context)
|
||||||
else:
|
else:
|
||||||
self.fail("No exception raised")
|
self.fail("No exception raised")
|
||||||
|
|
@ -328,7 +328,7 @@ class TestContext(unittest.TestCase):
|
||||||
except:
|
except:
|
||||||
raise OSError
|
raise OSError
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
self.assertNotEqual(e.__context__, context)
|
self.assertIsNot(e.__context__, context)
|
||||||
self.assertIsInstance(e.__context__, context)
|
self.assertIsInstance(e.__context__, context)
|
||||||
else:
|
else:
|
||||||
self.fail("No exception raised")
|
self.fail("No exception raised")
|
||||||
|
|
@ -415,6 +415,22 @@ class TestContext(unittest.TestCase):
|
||||||
except NameError as e:
|
except NameError as e:
|
||||||
self.assertIsNone(e.__context__.__context__)
|
self.assertIsNone(e.__context__.__context__)
|
||||||
|
|
||||||
|
def test_not_last(self):
|
||||||
|
# Context is not necessarily the last exception
|
||||||
|
context = Exception("context")
|
||||||
|
try:
|
||||||
|
raise context
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
raise Exception("caught")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
raise Exception("new")
|
||||||
|
except Exception as exc:
|
||||||
|
raised = exc
|
||||||
|
self.assertIs(raised.__context__, context)
|
||||||
|
|
||||||
def test_3118(self):
|
def test_3118(self):
|
||||||
# deleting the generator caused the __context__ to be cleared
|
# deleting the generator caused the __context__ to be cleared
|
||||||
def gen():
|
def gen():
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue