1# Copyright 2007 Google, Inc. All Rights Reserved.
2# Licensed to PSF under a Contributor Agreement.
3
4"""Tests for the raise statement."""
5
6from test import support
7import sys
8import types
9import unittest
10
11
12def get_tb():
13    try:
14        raise OSError()
15    except:
16        return sys.exc_info()[2]
17
18
19class Context:
20    def __enter__(self):
21        return self
22    def __exit__(self, exc_type, exc_value, exc_tb):
23        return True
24
25
26class TestRaise(unittest.TestCase):
27    def test_invalid_reraise(self):
28        try:
29            raise
30        except RuntimeError as e:
31            self.assertIn("No active exception", str(e))
32        else:
33            self.fail("No exception raised")
34
35    def test_reraise(self):
36        try:
37            try:
38                raise IndexError()
39            except IndexError as e:
40                exc1 = e
41                raise
42        except IndexError as exc2:
43            self.assertIs(exc1, exc2)
44        else:
45            self.fail("No exception raised")
46
47    def test_except_reraise(self):
48        def reraise():
49            try:
50                raise TypeError("foo")
51            except:
52                try:
53                    raise KeyError("caught")
54                except KeyError:
55                    pass
56                raise
57        self.assertRaises(TypeError, reraise)
58
59    def test_finally_reraise(self):
60        def reraise():
61            try:
62                raise TypeError("foo")
63            except:
64                try:
65                    raise KeyError("caught")
66                finally:
67                    raise
68        self.assertRaises(KeyError, reraise)
69
70    def test_nested_reraise(self):
71        def nested_reraise():
72            raise
73        def reraise():
74            try:
75                raise TypeError("foo")
76            except:
77                nested_reraise()
78        self.assertRaises(TypeError, reraise)
79
80    def test_raise_from_None(self):
81        try:
82            try:
83                raise TypeError("foo")
84            except:
85                raise ValueError() from None
86        except ValueError as e:
87            self.assertIsInstance(e.__context__, TypeError)
88            self.assertIsNone(e.__cause__)
89
90    def test_with_reraise1(self):
91        def reraise():
92            try:
93                raise TypeError("foo")
94            except:
95                with Context():
96                    pass
97                raise
98        self.assertRaises(TypeError, reraise)
99
100    def test_with_reraise2(self):
101        def reraise():
102            try:
103                raise TypeError("foo")
104            except:
105                with Context():
106                    raise KeyError("caught")
107                raise
108        self.assertRaises(TypeError, reraise)
109
110    def test_yield_reraise(self):
111        def reraise():
112            try:
113                raise TypeError("foo")
114            except:
115                yield 1
116                raise
117        g = reraise()
118        next(g)
119        self.assertRaises(TypeError, lambda: next(g))
120        self.assertRaises(StopIteration, lambda: next(g))
121
122    def test_erroneous_exception(self):
123        class MyException(Exception):
124            def __init__(self):
125                raise RuntimeError()
126
127        try:
128            raise MyException
129        except RuntimeError:
130            pass
131        else:
132            self.fail("No exception raised")
133
134    def test_new_returns_invalid_instance(self):
135        # See issue #11627.
136        class MyException(Exception):
137            def __new__(cls, *args):
138                return object()
139
140        with self.assertRaises(TypeError):
141            raise MyException
142
143    def test_assert_with_tuple_arg(self):
144        try:
145            assert False, (3,)
146        except AssertionError as e:
147            self.assertEqual(str(e), "(3,)")
148
149
150
151class TestCause(unittest.TestCase):
152
153    def testCauseSyntax(self):
154        try:
155            try:
156                try:
157                    raise TypeError
158                except Exception:
159                    raise ValueError from None
160            except ValueError as exc:
161                self.assertIsNone(exc.__cause__)
162                self.assertTrue(exc.__suppress_context__)
163                exc.__suppress_context__ = False
164                raise exc
165        except ValueError as exc:
166            e = exc
167
168        self.assertIsNone(e.__cause__)
169        self.assertFalse(e.__suppress_context__)
170        self.assertIsInstance(e.__context__, TypeError)
171
172    def test_invalid_cause(self):
173        try:
174            raise IndexError from 5
175        except TypeError as e:
176            self.assertIn("exception cause", str(e))
177        else:
178            self.fail("No exception raised")
179
180    def test_class_cause(self):
181        try:
182            raise IndexError from KeyError
183        except IndexError as e:
184            self.assertIsInstance(e.__cause__, KeyError)
185        else:
186            self.fail("No exception raised")
187
188    def test_instance_cause(self):
189        cause = KeyError()
190        try:
191            raise IndexError from cause
192        except IndexError as e:
193            self.assertIs(e.__cause__, cause)
194        else:
195            self.fail("No exception raised")
196
197    def test_erroneous_cause(self):
198        class MyException(Exception):
199            def __init__(self):
200                raise RuntimeError()
201
202        try:
203            raise IndexError from MyException
204        except RuntimeError:
205            pass
206        else:
207            self.fail("No exception raised")
208
209
210class TestTraceback(unittest.TestCase):
211
212    def test_sets_traceback(self):
213        try:
214            raise IndexError()
215        except IndexError as e:
216            self.assertIsInstance(e.__traceback__, types.TracebackType)
217        else:
218            self.fail("No exception raised")
219
220    def test_accepts_traceback(self):
221        tb = get_tb()
222        try:
223            raise IndexError().with_traceback(tb)
224        except IndexError as e:
225            self.assertNotEqual(e.__traceback__, tb)
226            self.assertEqual(e.__traceback__.tb_next, tb)
227        else:
228            self.fail("No exception raised")
229
230
231class TestTracebackType(unittest.TestCase):
232
233    def raiser(self):
234        raise ValueError
235
236    def test_attrs(self):
237        try:
238            self.raiser()
239        except Exception as exc:
240            tb = exc.__traceback__
241
242        self.assertIsInstance(tb.tb_next, types.TracebackType)
243        self.assertIs(tb.tb_frame, sys._getframe())
244        self.assertIsInstance(tb.tb_lasti, int)
245        self.assertIsInstance(tb.tb_lineno, int)
246
247        self.assertIs(tb.tb_next.tb_next, None)
248
249        # Invalid assignments
250        with self.assertRaises(TypeError):
251            del tb.tb_next
252
253        with self.assertRaises(TypeError):
254            tb.tb_next = "asdf"
255
256        # Loops
257        with self.assertRaises(ValueError):
258            tb.tb_next = tb
259
260        with self.assertRaises(ValueError):
261            tb.tb_next.tb_next = tb
262
263        # Valid assignments
264        tb.tb_next = None
265        self.assertIs(tb.tb_next, None)
266
267        new_tb = get_tb()
268        tb.tb_next = new_tb
269        self.assertIs(tb.tb_next, new_tb)
270
271    def test_constructor(self):
272        other_tb = get_tb()
273        frame = sys._getframe()
274
275        tb = types.TracebackType(other_tb, frame, 1, 2)
276        self.assertEqual(tb.tb_next, other_tb)
277        self.assertEqual(tb.tb_frame, frame)
278        self.assertEqual(tb.tb_lasti, 1)
279        self.assertEqual(tb.tb_lineno, 2)
280
281        tb = types.TracebackType(None, frame, 1, 2)
282        self.assertEqual(tb.tb_next, None)
283
284        with self.assertRaises(TypeError):
285            types.TracebackType("no", frame, 1, 2)
286
287        with self.assertRaises(TypeError):
288            types.TracebackType(other_tb, "no", 1, 2)
289
290        with self.assertRaises(TypeError):
291            types.TracebackType(other_tb, frame, "no", 2)
292
293        with self.assertRaises(TypeError):
294            types.TracebackType(other_tb, frame, 1, "nuh-uh")
295
296
297class TestContext(unittest.TestCase):
298    def test_instance_context_instance_raise(self):
299        context = IndexError()
300        try:
301            try:
302                raise context
303            except:
304                raise OSError()
305        except OSError as e:
306            self.assertEqual(e.__context__, context)
307        else:
308            self.fail("No exception raised")
309
310    def test_class_context_instance_raise(self):
311        context = IndexError
312        try:
313            try:
314                raise context
315            except:
316                raise OSError()
317        except OSError as e:
318            self.assertNotEqual(e.__context__, context)
319            self.assertIsInstance(e.__context__, context)
320        else:
321            self.fail("No exception raised")
322
323    def test_class_context_class_raise(self):
324        context = IndexError
325        try:
326            try:
327                raise context
328            except:
329                raise OSError
330        except OSError as e:
331            self.assertNotEqual(e.__context__, context)
332            self.assertIsInstance(e.__context__, context)
333        else:
334            self.fail("No exception raised")
335
336    def test_c_exception_context(self):
337        try:
338            try:
339                1/0
340            except:
341                raise OSError
342        except OSError as e:
343            self.assertIsInstance(e.__context__, ZeroDivisionError)
344        else:
345            self.fail("No exception raised")
346
347    def test_c_exception_raise(self):
348        try:
349            try:
350                1/0
351            except:
352                xyzzy
353        except NameError as e:
354            self.assertIsInstance(e.__context__, ZeroDivisionError)
355        else:
356            self.fail("No exception raised")
357
358    def test_noraise_finally(self):
359        try:
360            try:
361                pass
362            finally:
363                raise OSError
364        except OSError as e:
365            self.assertIsNone(e.__context__)
366        else:
367            self.fail("No exception raised")
368
369    def test_raise_finally(self):
370        try:
371            try:
372                1/0
373            finally:
374                raise OSError
375        except OSError as e:
376            self.assertIsInstance(e.__context__, ZeroDivisionError)
377        else:
378            self.fail("No exception raised")
379
380    def test_context_manager(self):
381        class ContextManager:
382            def __enter__(self):
383                pass
384            def __exit__(self, t, v, tb):
385                xyzzy
386        try:
387            with ContextManager():
388                1/0
389        except NameError as e:
390            self.assertIsInstance(e.__context__, ZeroDivisionError)
391        else:
392            self.fail("No exception raised")
393
394    def test_cycle_broken(self):
395        # Self-cycles (when re-raising a caught exception) are broken
396        try:
397            try:
398                1/0
399            except ZeroDivisionError as e:
400                raise e
401        except ZeroDivisionError as e:
402            self.assertIsNone(e.__context__)
403
404    def test_reraise_cycle_broken(self):
405        # Non-trivial context cycles (through re-raising a previous exception)
406        # are broken too.
407        try:
408            try:
409                xyzzy
410            except NameError as a:
411                try:
412                    1/0
413                except ZeroDivisionError:
414                    raise a
415        except NameError as e:
416            self.assertIsNone(e.__context__.__context__)
417
418    def test_3118(self):
419        # deleting the generator caused the __context__ to be cleared
420        def gen():
421            try:
422                yield 1
423            finally:
424                pass
425
426        def f():
427            g = gen()
428            next(g)
429            try:
430                try:
431                    raise ValueError
432                except:
433                    del g
434                    raise KeyError
435            except Exception as e:
436                self.assertIsInstance(e.__context__, ValueError)
437
438        f()
439
440    def test_3611(self):
441        import gc
442        # A re-raised exception in a __del__ caused the __context__
443        # to be cleared
444        class C:
445            def __del__(self):
446                try:
447                    1/0
448                except:
449                    raise
450
451        def f():
452            x = C()
453            try:
454                try:
455                    f.x
456                except AttributeError:
457                    # make x.__del__ trigger
458                    del x
459                    gc.collect()  # For PyPy or other GCs.
460                    raise TypeError
461            except Exception as e:
462                self.assertNotEqual(e.__context__, None)
463                self.assertIsInstance(e.__context__, AttributeError)
464
465        with support.catch_unraisable_exception() as cm:
466            f()
467
468            self.assertEqual(ZeroDivisionError, cm.unraisable.exc_type)
469
470
471class TestRemovedFunctionality(unittest.TestCase):
472    def test_tuples(self):
473        try:
474            raise (IndexError, KeyError) # This should be a tuple!
475        except TypeError:
476            pass
477        else:
478            self.fail("No exception raised")
479
480    def test_strings(self):
481        try:
482            raise "foo"
483        except TypeError:
484            pass
485        else:
486            self.fail("No exception raised")
487
488
489if __name__ == "__main__":
490    unittest.main()
491