Skip to content

Commit 2572c67

Browse files
[3.10] bpo-23556: [doc] Fix inaccuracy in documentation for raise without args. Improve tests for context in nested except handlers. (GH-29236) (GH-30953)
(cherry picked from commit 08c0ed2) Co-authored-by: Kinshuk Dua <[email protected]> Automerge-Triggered-By: GH:iritkatriel
1 parent 1ecc98d commit 2572c67

File tree

3 files changed

+37
-20
lines changed

3 files changed

+37
-20
lines changed

Doc/library/exceptions.rst

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,14 @@ information on defining exceptions is available in the Python Tutorial under
3838
Exception context
3939
-----------------
4040

41-
When raising (or re-raising) an exception in an :keyword:`except` or
42-
:keyword:`finally` clause
43-
:attr:`__context__` is automatically set to the last exception caught; if the
44-
new exception is not handled the traceback that is eventually displayed will
45-
include the originating exception(s) and the final exception.
46-
47-
When raising a new exception (rather than using a bare ``raise`` to re-raise
48-
the exception currently being handled), the implicit exception context can be
49-
supplemented with an explicit cause by using :keyword:`from<raise>` with
41+
When raising a new exception while another exception
42+
is already being handled, the new exception's
43+
:attr:`__context__` attribute is automatically set to the handled
44+
exception. An exception may be handled when an :keyword:`except` or
45+
:keyword:`finally` clause, or a :keyword:`with` statement, is used.
46+
47+
This implicit exception context can be
48+
supplemented with an explicit cause by using :keyword:`!from` with
5049
:keyword:`raise`::
5150

5251
raise new_exc from original_exc

Doc/reference/simple_stmts.rst

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -563,10 +563,10 @@ The :keyword:`!raise` statement
563563
.. productionlist:: python-grammar
564564
raise_stmt: "raise" [`expression` ["from" `expression`]]
565565

566-
If no expressions are present, :keyword:`raise` re-raises the last exception
567-
that was active in the current scope. If no exception is active in the current
568-
scope, a :exc:`RuntimeError` exception is raised indicating that this is an
569-
error.
566+
If no expressions are present, :keyword:`raise` re-raises the
567+
exception that is currently being handled, which is also known as the *active exception*.
568+
If there isn't currently an active exception, a :exc:`RuntimeError` exception is raised
569+
indicating that this is an error.
570570

571571
Otherwise, :keyword:`raise` evaluates the first expression as the exception
572572
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
581581
A traceback object is normally created automatically when an exception is raised
582582
and attached to it as the :attr:`__traceback__` attribute, which is writable.
583583
You can create an exception and set your own traceback in one step using the
584-
:meth:`with_traceback` exception method (which returns the same exception
585-
instance, with its traceback set to its argument), like so::
584+
:meth:`~BaseException.with_traceback` exception method (which returns the
585+
same exception instance, with its traceback set to its argument), like so::
586586

587587
raise Exception("foo occurred").with_traceback(tracebackobj)
588588

@@ -614,8 +614,10 @@ exceptions will be printed::
614614
File "<stdin>", line 4, in <module>
615615
RuntimeError: Something bad happened
616616

617-
A similar mechanism works implicitly if an exception is raised inside an
618-
exception handler or a :keyword:`finally` clause: the previous exception is then
617+
A similar mechanism works implicitly if a new exception is raised when
618+
an exception is already being handled. An exception may be handled
619+
when an :keyword:`except` or :keyword:`finally` clause, or a
620+
:keyword:`with` statement, is used. The previous exception is then
619621
attached as the new exception's :attr:`__context__` attribute::
620622

621623
>>> try:

Lib/test/test_raise.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ def test_instance_context_instance_raise(self):
303303
except:
304304
raise OSError()
305305
except OSError as e:
306-
self.assertEqual(e.__context__, context)
306+
self.assertIs(e.__context__, context)
307307
else:
308308
self.fail("No exception raised")
309309

@@ -315,7 +315,7 @@ def test_class_context_instance_raise(self):
315315
except:
316316
raise OSError()
317317
except OSError as e:
318-
self.assertNotEqual(e.__context__, context)
318+
self.assertIsNot(e.__context__, context)
319319
self.assertIsInstance(e.__context__, context)
320320
else:
321321
self.fail("No exception raised")
@@ -328,7 +328,7 @@ def test_class_context_class_raise(self):
328328
except:
329329
raise OSError
330330
except OSError as e:
331-
self.assertNotEqual(e.__context__, context)
331+
self.assertIsNot(e.__context__, context)
332332
self.assertIsInstance(e.__context__, context)
333333
else:
334334
self.fail("No exception raised")
@@ -415,6 +415,22 @@ def test_reraise_cycle_broken(self):
415415
except NameError as e:
416416
self.assertIsNone(e.__context__.__context__)
417417

418+
def test_not_last(self):
419+
# Context is not necessarily the last exception
420+
context = Exception("context")
421+
try:
422+
raise context
423+
except Exception:
424+
try:
425+
raise Exception("caught")
426+
except Exception:
427+
pass
428+
try:
429+
raise Exception("new")
430+
except Exception as exc:
431+
raised = exc
432+
self.assertIs(raised.__context__, context)
433+
418434
def test_3118(self):
419435
# deleting the generator caused the __context__ to be cleared
420436
def gen():

0 commit comments

Comments
 (0)