@@ -89,6 +89,115 @@ def func():
8989 "GeneratorTest.test_name.<locals>.<genexpr>" )
9090
9191
92+ class ExceptionTest (unittest .TestCase ):
93+ # Tests for the issue #23353: check that the currently handled exception
94+ # is correctly saved/restored in PyEval_EvalFrameEx().
95+
96+ def test_except_throw (self ):
97+ def store_raise_exc_generator ():
98+ try :
99+ self .assertEqual (sys .exc_info ()[0 ], None )
100+ yield
101+ except Exception as exc :
102+ # exception raised by gen.throw(exc)
103+ self .assertEqual (sys .exc_info ()[0 ], ValueError )
104+ self .assertIsNone (exc .__context__ )
105+ yield
106+
107+ # ensure that the exception is not lost
108+ self .assertEqual (sys .exc_info ()[0 ], ValueError )
109+ yield
110+
111+ # we should be able to raise back the ValueError
112+ raise
113+
114+ make = store_raise_exc_generator ()
115+ next (make )
116+
117+ try :
118+ raise ValueError ()
119+ except Exception as exc :
120+ try :
121+ make .throw (exc )
122+ except Exception :
123+ pass
124+
125+ next (make )
126+ with self .assertRaises (ValueError ) as cm :
127+ next (make )
128+ self .assertIsNone (cm .exception .__context__ )
129+
130+ self .assertEqual (sys .exc_info (), (None , None , None ))
131+
132+ def test_except_next (self ):
133+ def gen ():
134+ self .assertEqual (sys .exc_info ()[0 ], ValueError )
135+ yield "done"
136+
137+ g = gen ()
138+ try :
139+ raise ValueError
140+ except Exception :
141+ self .assertEqual (next (g ), "done" )
142+ self .assertEqual (sys .exc_info (), (None , None , None ))
143+
144+ def test_except_gen_except (self ):
145+ def gen ():
146+ try :
147+ self .assertEqual (sys .exc_info ()[0 ], None )
148+ yield
149+ # we are called from "except ValueError:", TypeError must
150+ # inherit ValueError in its context
151+ raise TypeError ()
152+ except TypeError as exc :
153+ self .assertEqual (sys .exc_info ()[0 ], TypeError )
154+ self .assertEqual (type (exc .__context__ ), ValueError )
155+ # here we are still called from the "except ValueError:"
156+ self .assertEqual (sys .exc_info ()[0 ], ValueError )
157+ yield
158+ self .assertIsNone (sys .exc_info ()[0 ])
159+ yield "done"
160+
161+ g = gen ()
162+ next (g )
163+ try :
164+ raise ValueError
165+ except Exception :
166+ next (g )
167+
168+ self .assertEqual (next (g ), "done" )
169+ self .assertEqual (sys .exc_info (), (None , None , None ))
170+
171+ def test_except_throw_exception_context (self ):
172+ def gen ():
173+ try :
174+ try :
175+ self .assertEqual (sys .exc_info ()[0 ], None )
176+ yield
177+ except ValueError :
178+ # we are called from "except ValueError:"
179+ self .assertEqual (sys .exc_info ()[0 ], ValueError )
180+ raise TypeError ()
181+ except Exception as exc :
182+ self .assertEqual (sys .exc_info ()[0 ], TypeError )
183+ self .assertEqual (type (exc .__context__ ), ValueError )
184+ # we are still called from "except ValueError:"
185+ self .assertEqual (sys .exc_info ()[0 ], ValueError )
186+ yield
187+ self .assertIsNone (sys .exc_info ()[0 ])
188+ yield "done"
189+
190+ g = gen ()
191+ next (g )
192+ try :
193+ raise ValueError
194+ except Exception as exc :
195+ g .throw (exc )
196+
197+ self .assertEqual (next (g ), "done" )
198+ self .assertEqual (sys .exc_info (), (None , None , None ))
199+
200+
92201tutorial_tests = """
93202Let's try a simple generator:
94203
0 commit comments