|
4 | 4 | import sys
|
5 | 5 | import tempfile
|
6 | 6 | import threading
|
| 7 | +import traceback |
7 | 8 | import unittest
|
8 | 9 | from contextlib import * # Tests __all__
|
9 | 10 | from test import support
|
@@ -701,6 +702,38 @@ def test_exit_suppress(self):
|
701 | 702 | stack.push(lambda *exc: True)
|
702 | 703 | 1/0
|
703 | 704 |
|
| 705 | + def test_exit_exception_traceback(self): |
| 706 | + # This test captures the current behavior of ExitStack so that we know |
| 707 | + # if we ever unintendedly change it. It is not a statement of what the |
| 708 | + # desired behavior is (for instance, we may want to remove some of the |
| 709 | + # internal contextlib frames). |
| 710 | + |
| 711 | + def raise_exc(exc): |
| 712 | + raise exc |
| 713 | + |
| 714 | + try: |
| 715 | + with self.exit_stack() as stack: |
| 716 | + stack.callback(raise_exc, ValueError) |
| 717 | + 1/0 |
| 718 | + except ValueError as e: |
| 719 | + exc = e |
| 720 | + |
| 721 | + self.assertIsInstance(exc, ValueError) |
| 722 | + ve_frames = traceback.extract_tb(exc.__traceback__) |
| 723 | + expected = \ |
| 724 | + [('test_exit_exception_traceback', 'with self.exit_stack() as stack:')] + \ |
| 725 | + self.callback_error_internal_frames + \ |
| 726 | + [('_exit_wrapper', 'callback(*args, **kwds)'), |
| 727 | + ('raise_exc', 'raise exc')] |
| 728 | + |
| 729 | + self.assertEqual( |
| 730 | + [(f.name, f.line) for f in ve_frames], expected) |
| 731 | + |
| 732 | + self.assertIsInstance(exc.__context__, ZeroDivisionError) |
| 733 | + zde_frames = traceback.extract_tb(exc.__context__.__traceback__) |
| 734 | + self.assertEqual([(f.name, f.line) for f in zde_frames], |
| 735 | + [('test_exit_exception_traceback', '1/0')]) |
| 736 | + |
704 | 737 | def test_exit_exception_chaining_reference(self):
|
705 | 738 | # Sanity check to make sure that ExitStack chaining matches
|
706 | 739 | # actual nested with statements
|
@@ -968,6 +1001,10 @@ def first():
|
968 | 1001 |
|
969 | 1002 | class TestExitStack(TestBaseExitStack, unittest.TestCase):
|
970 | 1003 | exit_stack = ExitStack
|
| 1004 | + callback_error_internal_frames = [ |
| 1005 | + ('__exit__', 'raise exc_details[1]'), |
| 1006 | + ('__exit__', 'if cb(*exc_details):'), |
| 1007 | + ] |
971 | 1008 |
|
972 | 1009 |
|
973 | 1010 | class TestRedirectStream:
|
|
0 commit comments