1import sys
2import unittest
3import textwrap
4
5class TestInvalidExceptStar(unittest.TestCase):
6    def test_mixed_except_and_except_star_is_syntax_error(self):
7        errors = [
8            "try: pass\nexcept ValueError: pass\nexcept* TypeError: pass\n",
9            "try: pass\nexcept* ValueError: pass\nexcept TypeError: pass\n",
10            "try: pass\nexcept ValueError as e: pass\nexcept* TypeError: pass\n",
11            "try: pass\nexcept* ValueError as e: pass\nexcept TypeError: pass\n",
12            "try: pass\nexcept ValueError: pass\nexcept* TypeError as e: pass\n",
13            "try: pass\nexcept* ValueError: pass\nexcept TypeError as e: pass\n",
14            "try: pass\nexcept ValueError: pass\nexcept*: pass\n",
15            "try: pass\nexcept* ValueError: pass\nexcept: pass\n",
16        ]
17
18        for err in errors:
19            with self.assertRaises(SyntaxError):
20                compile(err, "<string>", "exec")
21
22    def test_except_star_ExceptionGroup_is_runtime_error_single(self):
23        with self.assertRaises(TypeError):
24            try:
25                raise OSError("blah")
26            except* ExceptionGroup as e:
27                pass
28
29    def test_except_star_ExceptionGroup_is_runtime_error_tuple(self):
30        with self.assertRaises(TypeError):
31            try:
32                raise ExceptionGroup("eg", [ValueError(42)])
33            except* (TypeError, ExceptionGroup):
34                pass
35
36    def test_except_star_invalid_exception_type(self):
37        with self.assertRaises(TypeError):
38            try:
39                raise ValueError
40            except* 42:
41                pass
42
43        with self.assertRaises(TypeError):
44            try:
45                raise ValueError
46            except* (ValueError, 42):
47                pass
48
49
50class TestBreakContinueReturnInExceptStarBlock(unittest.TestCase):
51    MSG = (r"'break', 'continue' and 'return'"
52           r" cannot appear in an except\* block")
53
54    def check_invalid(self, src):
55        with self.assertRaisesRegex(SyntaxError, self.MSG):
56            compile(textwrap.dedent(src), "<string>", "exec")
57
58    def test_break_in_except_star(self):
59        self.check_invalid(
60            """
61            try:
62                raise ValueError
63            except* Exception as e:
64                break
65            """)
66
67        self.check_invalid(
68            """
69            for i in range(5):
70                try:
71                    pass
72                except* Exception as e:
73                    if i == 2:
74                        break
75            """)
76
77        self.check_invalid(
78            """
79            for i in range(5):
80                try:
81                    pass
82                except* Exception as e:
83                    if i == 2:
84                        break
85                finally:
86                    return 0
87            """)
88
89
90    def test_continue_in_except_star_block_invalid(self):
91        self.check_invalid(
92            """
93            for i in range(5):
94                try:
95                    raise ValueError
96                except* Exception as e:
97                    continue
98            """)
99
100        self.check_invalid(
101            """
102            for i in range(5):
103                try:
104                    pass
105                except* Exception as e:
106                    if i == 2:
107                        continue
108            """)
109
110        self.check_invalid(
111            """
112            for i in range(5):
113                try:
114                    pass
115                except* Exception as e:
116                    if i == 2:
117                        continue
118                finally:
119                    return 0
120            """)
121
122    def test_return_in_except_star_block_invalid(self):
123        self.check_invalid(
124            """
125            def f():
126                try:
127                    raise ValueError
128                except* Exception as e:
129                    return 42
130            """)
131
132        self.check_invalid(
133            """
134            def f():
135                try:
136                    pass
137                except* Exception as e:
138                    return 42
139                finally:
140                    finished = True
141            """)
142
143    def test_break_continue_in_except_star_block_valid(self):
144        try:
145            raise ValueError(42)
146        except* Exception as e:
147            count = 0
148            for i in range(5):
149                if i == 0:
150                    continue
151                if i == 4:
152                    break
153                count += 1
154
155            self.assertEqual(count, 3)
156            self.assertEqual(i, 4)
157            exc = e
158        self.assertIsInstance(exc, ExceptionGroup)
159
160    def test_return_in_except_star_block_valid(self):
161        try:
162            raise ValueError(42)
163        except* Exception as e:
164            def f(x):
165                return 2*x
166            r = f(3)
167            exc = e
168        self.assertEqual(r, 6)
169        self.assertIsInstance(exc, ExceptionGroup)
170
171
172class ExceptStarTest(unittest.TestCase):
173    def assertExceptionIsLike(self, exc, template):
174        if exc is None and template is None:
175            return
176
177        if template is None:
178            self.fail(f"unexpected exception: {exc}")
179
180        if exc is None:
181            self.fail(f"expected an exception like {template!r}, got None")
182
183        if not isinstance(exc, ExceptionGroup):
184            self.assertEqual(exc.__class__, template.__class__)
185            self.assertEqual(exc.args[0], template.args[0])
186        else:
187            self.assertEqual(exc.message, template.message)
188            self.assertEqual(len(exc.exceptions), len(template.exceptions))
189            for e, t in zip(exc.exceptions, template.exceptions):
190                self.assertExceptionIsLike(e, t)
191
192    def assertMetadataEqual(self, e1, e2):
193        if e1 is None or e2 is None:
194            self.assertTrue(e1 is None and e2 is None)
195        else:
196            self.assertEqual(e1.__context__, e2.__context__)
197            self.assertEqual(e1.__cause__, e2.__cause__)
198            self.assertEqual(e1.__traceback__, e2.__traceback__)
199
200    def assertMetadataNotEqual(self, e1, e2):
201        if e1 is None or e2 is None:
202            self.assertNotEqual(e1, e2)
203        else:
204            return not (e1.__context__ == e2.__context__
205                        and e1.__cause__ == e2.__cause__
206                        and e1.__traceback__ == e2.__traceback__)
207
208
209class TestExceptStarSplitSemantics(ExceptStarTest):
210    def doSplitTestNamed(self, exc, T, match_template, rest_template):
211        initial_sys_exception = sys.exception()
212        sys_exception = match = rest = None
213        try:
214            try:
215                raise exc
216            except* T as e:
217                sys_exception = sys.exception()
218                match = e
219        except BaseException as e:
220            rest = e
221
222        self.assertEqual(sys_exception, match)
223        self.assertExceptionIsLike(match, match_template)
224        self.assertExceptionIsLike(rest, rest_template)
225        self.assertEqual(sys.exception(), initial_sys_exception)
226
227    def doSplitTestUnnamed(self, exc, T, match_template, rest_template):
228        initial_sys_exception = sys.exception()
229        sys_exception = match = rest = None
230        try:
231            try:
232                raise exc
233            except* T:
234                sys_exception = match = sys.exception()
235            else:
236                if rest_template:
237                    self.fail("Exception not raised")
238        except BaseException as e:
239            rest = e
240        self.assertExceptionIsLike(match, match_template)
241        self.assertExceptionIsLike(rest, rest_template)
242        self.assertEqual(sys.exception(), initial_sys_exception)
243
244    def doSplitTestInExceptHandler(self, exc, T, match_template, rest_template):
245        try:
246            raise ExceptionGroup('eg', [TypeError(1), ValueError(2)])
247        except Exception:
248            self.doSplitTestNamed(exc, T, match_template, rest_template)
249            self.doSplitTestUnnamed(exc, T, match_template, rest_template)
250
251    def doSplitTestInExceptStarHandler(self, exc, T, match_template, rest_template):
252        try:
253            raise ExceptionGroup('eg', [TypeError(1), ValueError(2)])
254        except* Exception:
255            self.doSplitTestNamed(exc, T, match_template, rest_template)
256            self.doSplitTestUnnamed(exc, T, match_template, rest_template)
257
258    def doSplitTest(self, exc, T, match_template, rest_template):
259        self.doSplitTestNamed(exc, T, match_template, rest_template)
260        self.doSplitTestUnnamed(exc, T, match_template, rest_template)
261        self.doSplitTestInExceptHandler(exc, T, match_template, rest_template)
262        self.doSplitTestInExceptStarHandler(exc, T, match_template, rest_template)
263
264    def test_no_match_single_type(self):
265        self.doSplitTest(
266            ExceptionGroup("test1", [ValueError("V"), TypeError("T")]),
267            SyntaxError,
268            None,
269            ExceptionGroup("test1", [ValueError("V"), TypeError("T")]))
270
271    def test_match_single_type(self):
272        self.doSplitTest(
273            ExceptionGroup("test2", [ValueError("V1"), ValueError("V2")]),
274            ValueError,
275            ExceptionGroup("test2", [ValueError("V1"), ValueError("V2")]),
276            None)
277
278    def test_match_single_type_partial_match(self):
279        self.doSplitTest(
280            ExceptionGroup(
281                "test3",
282                [ValueError("V1"), OSError("OS"), ValueError("V2")]),
283            ValueError,
284            ExceptionGroup("test3", [ValueError("V1"), ValueError("V2")]),
285            ExceptionGroup("test3", [OSError("OS")]))
286
287    def test_match_single_type_nested(self):
288        self.doSplitTest(
289            ExceptionGroup(
290                "g1", [
291                ValueError("V1"),
292                OSError("OS1"),
293                ExceptionGroup(
294                    "g2", [
295                    OSError("OS2"),
296                    ValueError("V2"),
297                    TypeError("T")])]),
298            ValueError,
299            ExceptionGroup(
300                "g1", [
301                ValueError("V1"),
302                ExceptionGroup("g2", [ValueError("V2")])]),
303            ExceptionGroup("g1", [
304                OSError("OS1"),
305                ExceptionGroup("g2", [
306                    OSError("OS2"), TypeError("T")])]))
307
308    def test_match_type_tuple_nested(self):
309        self.doSplitTest(
310            ExceptionGroup(
311                "h1", [
312                ValueError("V1"),
313                OSError("OS1"),
314                ExceptionGroup(
315                    "h2", [OSError("OS2"), ValueError("V2"), TypeError("T")])]),
316            (ValueError, TypeError),
317            ExceptionGroup(
318                "h1", [
319                ValueError("V1"),
320                ExceptionGroup("h2", [ValueError("V2"), TypeError("T")])]),
321            ExceptionGroup(
322                "h1", [
323                OSError("OS1"),
324                ExceptionGroup("h2", [OSError("OS2")])]))
325
326    def test_empty_groups_removed(self):
327        self.doSplitTest(
328            ExceptionGroup(
329                "eg", [
330                ExceptionGroup("i1", [ValueError("V1")]),
331                ExceptionGroup("i2", [ValueError("V2"), TypeError("T1")]),
332                ExceptionGroup("i3", [TypeError("T2")])]),
333            TypeError,
334            ExceptionGroup("eg", [
335                ExceptionGroup("i2", [TypeError("T1")]),
336                ExceptionGroup("i3", [TypeError("T2")])]),
337            ExceptionGroup("eg", [
338                    ExceptionGroup("i1", [ValueError("V1")]),
339                    ExceptionGroup("i2", [ValueError("V2")])]))
340
341    def test_singleton_groups_are_kept(self):
342        self.doSplitTest(
343            ExceptionGroup("j1", [
344                ExceptionGroup("j2", [
345                    ExceptionGroup("j3", [ValueError("V1")]),
346                    ExceptionGroup("j4", [TypeError("T")])])]),
347            TypeError,
348            ExceptionGroup(
349                "j1",
350                [ExceptionGroup("j2", [ExceptionGroup("j4", [TypeError("T")])])]),
351            ExceptionGroup(
352                "j1",
353                [ExceptionGroup("j2", [ExceptionGroup("j3", [ValueError("V1")])])]))
354
355    def test_naked_exception_matched_wrapped1(self):
356        self.doSplitTest(
357            ValueError("V"),
358            ValueError,
359            ExceptionGroup("", [ValueError("V")]),
360            None)
361
362    def test_naked_exception_matched_wrapped2(self):
363        self.doSplitTest(
364            ValueError("V"),
365            Exception,
366            ExceptionGroup("", [ValueError("V")]),
367            None)
368
369    def test_exception_group_except_star_Exception_not_wrapped(self):
370        self.doSplitTest(
371            ExceptionGroup("eg", [ValueError("V")]),
372            Exception,
373            ExceptionGroup("eg", [ValueError("V")]),
374            None)
375
376    def test_plain_exception_not_matched(self):
377        self.doSplitTest(
378            ValueError("V"),
379            TypeError,
380            None,
381            ValueError("V"))
382
383    def test_match__supertype(self):
384        self.doSplitTest(
385            ExceptionGroup("st", [BlockingIOError("io"), TypeError("T")]),
386            OSError,
387            ExceptionGroup("st", [BlockingIOError("io")]),
388            ExceptionGroup("st", [TypeError("T")]))
389
390    def test_multiple_matches_named(self):
391        try:
392            raise ExceptionGroup("mmn", [OSError("os"), BlockingIOError("io")])
393        except* BlockingIOError as e:
394            self.assertExceptionIsLike(e,
395                ExceptionGroup("mmn", [BlockingIOError("io")]))
396        except* OSError as e:
397            self.assertExceptionIsLike(e,
398                ExceptionGroup("mmn", [OSError("os")]))
399        else:
400            self.fail("Exception not raised")
401
402    def test_multiple_matches_unnamed(self):
403        try:
404            raise ExceptionGroup("mmu", [OSError("os"), BlockingIOError("io")])
405        except* BlockingIOError:
406            e = sys.exception()
407            self.assertExceptionIsLike(e,
408                ExceptionGroup("mmu", [BlockingIOError("io")]))
409        except* OSError:
410            e = sys.exception()
411            self.assertExceptionIsLike(e,
412                ExceptionGroup("mmu", [OSError("os")]))
413        else:
414            self.fail("Exception not raised")
415
416    def test_first_match_wins_named(self):
417        try:
418            raise ExceptionGroup("fst", [BlockingIOError("io")])
419        except* OSError as e:
420            self.assertExceptionIsLike(e,
421                ExceptionGroup("fst", [BlockingIOError("io")]))
422        except* BlockingIOError:
423            self.fail("Should have been matched as OSError")
424        else:
425            self.fail("Exception not raised")
426
427    def test_first_match_wins_unnamed(self):
428        try:
429            raise ExceptionGroup("fstu", [BlockingIOError("io")])
430        except* OSError:
431            e = sys.exception()
432            self.assertExceptionIsLike(e,
433                ExceptionGroup("fstu", [BlockingIOError("io")]))
434        except* BlockingIOError:
435            pass
436        else:
437            self.fail("Exception not raised")
438
439    def test_nested_except_stars(self):
440        try:
441            raise ExceptionGroup("n", [BlockingIOError("io")])
442        except* BlockingIOError:
443            try:
444                raise ExceptionGroup("n", [ValueError("io")])
445            except* ValueError:
446                pass
447            else:
448                self.fail("Exception not raised")
449            e = sys.exception()
450            self.assertExceptionIsLike(e,
451                 ExceptionGroup("n", [BlockingIOError("io")]))
452        else:
453            self.fail("Exception not raised")
454
455    def test_nested_in_loop(self):
456        for _ in range(2):
457            try:
458                raise ExceptionGroup("nl", [BlockingIOError("io")])
459            except* BlockingIOError:
460                pass
461            else:
462                self.fail("Exception not raised")
463
464
465class TestExceptStarReraise(ExceptStarTest):
466    def test_reraise_all_named(self):
467        try:
468            try:
469                raise ExceptionGroup(
470                    "eg", [TypeError(1), ValueError(2), OSError(3)])
471            except* TypeError as e:
472                raise
473            except* ValueError as e:
474                raise
475            # OSError not handled
476        except ExceptionGroup as e:
477            exc = e
478
479        self.assertExceptionIsLike(
480            exc,
481            ExceptionGroup("eg", [TypeError(1), ValueError(2), OSError(3)]))
482
483    def test_reraise_all_unnamed(self):
484        try:
485            try:
486                raise ExceptionGroup(
487                    "eg", [TypeError(1), ValueError(2), OSError(3)])
488            except* TypeError:
489                raise
490            except* ValueError:
491                raise
492            # OSError not handled
493        except ExceptionGroup as e:
494            exc = e
495
496        self.assertExceptionIsLike(
497            exc,
498            ExceptionGroup("eg", [TypeError(1), ValueError(2), OSError(3)]))
499
500    def test_reraise_some_handle_all_named(self):
501        try:
502            try:
503                raise ExceptionGroup(
504                    "eg", [TypeError(1), ValueError(2), OSError(3)])
505            except* TypeError as e:
506                raise
507            except* ValueError as e:
508                pass
509            # OSError not handled
510        except ExceptionGroup as e:
511            exc = e
512
513        self.assertExceptionIsLike(
514            exc, ExceptionGroup("eg", [TypeError(1), OSError(3)]))
515
516    def test_reraise_partial_handle_all_unnamed(self):
517        try:
518            try:
519                raise ExceptionGroup(
520                    "eg", [TypeError(1), ValueError(2)])
521            except* TypeError:
522                raise
523            except* ValueError:
524                pass
525        except ExceptionGroup as e:
526            exc = e
527
528        self.assertExceptionIsLike(
529            exc, ExceptionGroup("eg", [TypeError(1)]))
530
531    def test_reraise_partial_handle_some_named(self):
532        try:
533            try:
534                raise ExceptionGroup(
535                    "eg", [TypeError(1), ValueError(2), OSError(3)])
536            except* TypeError as e:
537                raise
538            except* ValueError as e:
539                pass
540            # OSError not handled
541        except ExceptionGroup as e:
542            exc = e
543
544        self.assertExceptionIsLike(
545            exc, ExceptionGroup("eg", [TypeError(1), OSError(3)]))
546
547    def test_reraise_partial_handle_some_unnamed(self):
548        try:
549            try:
550                raise ExceptionGroup(
551                    "eg", [TypeError(1), ValueError(2), OSError(3)])
552            except* TypeError:
553                raise
554            except* ValueError:
555                pass
556        except ExceptionGroup as e:
557            exc = e
558
559        self.assertExceptionIsLike(
560            exc, ExceptionGroup("eg", [TypeError(1), OSError(3)]))
561
562    def test_reraise_plain_exception_named(self):
563        try:
564            try:
565                raise ValueError(42)
566            except* ValueError as e:
567                raise
568        except ExceptionGroup as e:
569            exc = e
570
571        self.assertExceptionIsLike(
572            exc, ExceptionGroup("", [ValueError(42)]))
573
574    def test_reraise_plain_exception_unnamed(self):
575        try:
576            try:
577                raise ValueError(42)
578            except* ValueError:
579                raise
580        except ExceptionGroup as e:
581            exc = e
582
583        self.assertExceptionIsLike(
584            exc, ExceptionGroup("", [ValueError(42)]))
585
586
587class TestExceptStarRaise(ExceptStarTest):
588    def test_raise_named(self):
589        orig = ExceptionGroup("eg", [ValueError(1), OSError(2)])
590        try:
591            try:
592                raise orig
593            except* OSError as e:
594                raise TypeError(3)
595        except ExceptionGroup as e:
596            exc = e
597
598        self.assertExceptionIsLike(
599            exc,
600            ExceptionGroup(
601                "", [TypeError(3), ExceptionGroup("eg", [ValueError(1)])]))
602
603        self.assertExceptionIsLike(
604            exc.exceptions[0].__context__,
605            ExceptionGroup("eg", [OSError(2)]))
606
607        self.assertMetadataNotEqual(orig, exc)
608        self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
609
610    def test_raise_unnamed(self):
611        orig = ExceptionGroup("eg", [ValueError(1), OSError(2)])
612        try:
613            try:
614                raise orig
615            except* OSError:
616                raise TypeError(3)
617        except ExceptionGroup as e:
618            exc = e
619
620        self.assertExceptionIsLike(
621            exc,
622            ExceptionGroup(
623                "", [TypeError(3), ExceptionGroup("eg", [ValueError(1)])]))
624
625        self.assertExceptionIsLike(
626            exc.exceptions[0].__context__,
627            ExceptionGroup("eg", [OSError(2)]))
628
629        self.assertMetadataNotEqual(orig, exc)
630        self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
631
632    def test_raise_handle_all_raise_one_named(self):
633        orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
634        try:
635            try:
636                raise orig
637            except* (TypeError, ValueError) as e:
638                raise SyntaxError(3)
639        except SyntaxError as e:
640            exc = e
641
642        self.assertExceptionIsLike(exc, SyntaxError(3))
643
644        self.assertExceptionIsLike(
645            exc.__context__,
646            ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
647
648        self.assertMetadataNotEqual(orig, exc)
649        self.assertMetadataEqual(orig, exc.__context__)
650
651    def test_raise_handle_all_raise_one_unnamed(self):
652        orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
653        try:
654            try:
655                raise orig
656            except* (TypeError, ValueError) as e:
657                raise SyntaxError(3)
658        except SyntaxError as e:
659            exc = e
660
661        self.assertExceptionIsLike(exc, SyntaxError(3))
662
663        self.assertExceptionIsLike(
664            exc.__context__,
665            ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
666
667        self.assertMetadataNotEqual(orig, exc)
668        self.assertMetadataEqual(orig, exc.__context__)
669
670    def test_raise_handle_all_raise_two_named(self):
671        orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
672        try:
673            try:
674                raise orig
675            except* TypeError as e:
676                raise SyntaxError(3)
677            except* ValueError as e:
678                raise SyntaxError(4)
679        except ExceptionGroup as e:
680            exc = e
681
682        self.assertExceptionIsLike(
683            exc, ExceptionGroup("", [SyntaxError(3), SyntaxError(4)]))
684
685        self.assertExceptionIsLike(
686            exc.exceptions[0].__context__,
687            ExceptionGroup("eg", [TypeError(1)]))
688
689        self.assertExceptionIsLike(
690            exc.exceptions[1].__context__,
691            ExceptionGroup("eg", [ValueError(2)]))
692
693        self.assertMetadataNotEqual(orig, exc)
694        self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
695        self.assertMetadataEqual(orig, exc.exceptions[1].__context__)
696
697    def test_raise_handle_all_raise_two_unnamed(self):
698        orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
699        try:
700            try:
701                raise orig
702            except* TypeError:
703                raise SyntaxError(3)
704            except* ValueError:
705                raise SyntaxError(4)
706        except ExceptionGroup as e:
707            exc = e
708
709        self.assertExceptionIsLike(
710            exc, ExceptionGroup("", [SyntaxError(3), SyntaxError(4)]))
711
712        self.assertExceptionIsLike(
713            exc.exceptions[0].__context__,
714            ExceptionGroup("eg", [TypeError(1)]))
715
716        self.assertExceptionIsLike(
717            exc.exceptions[1].__context__,
718            ExceptionGroup("eg", [ValueError(2)]))
719
720        self.assertMetadataNotEqual(orig, exc)
721        self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
722        self.assertMetadataEqual(orig, exc.exceptions[1].__context__)
723
724
725class TestExceptStarRaiseFrom(ExceptStarTest):
726    def test_raise_named(self):
727        orig = ExceptionGroup("eg", [ValueError(1), OSError(2)])
728        try:
729            try:
730                raise orig
731            except* OSError as e:
732                raise TypeError(3) from e
733        except ExceptionGroup as e:
734            exc = e
735
736        self.assertExceptionIsLike(
737            exc,
738            ExceptionGroup(
739                "", [TypeError(3), ExceptionGroup("eg", [ValueError(1)])]))
740
741        self.assertExceptionIsLike(
742            exc.exceptions[0].__context__,
743            ExceptionGroup("eg", [OSError(2)]))
744
745        self.assertExceptionIsLike(
746            exc.exceptions[0].__cause__,
747            ExceptionGroup("eg", [OSError(2)]))
748
749        self.assertMetadataNotEqual(orig, exc)
750        self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
751        self.assertMetadataEqual(orig, exc.exceptions[0].__cause__)
752        self.assertMetadataNotEqual(orig, exc.exceptions[1].__context__)
753        self.assertMetadataNotEqual(orig, exc.exceptions[1].__cause__)
754
755    def test_raise_unnamed(self):
756        orig = ExceptionGroup("eg", [ValueError(1), OSError(2)])
757        try:
758            try:
759                raise orig
760            except* OSError:
761                e = sys.exception()
762                raise TypeError(3) from e
763        except ExceptionGroup as e:
764            exc = e
765
766        self.assertExceptionIsLike(
767            exc,
768            ExceptionGroup(
769                "", [TypeError(3), ExceptionGroup("eg", [ValueError(1)])]))
770
771        self.assertExceptionIsLike(
772            exc.exceptions[0].__context__,
773            ExceptionGroup("eg", [OSError(2)]))
774
775        self.assertExceptionIsLike(
776            exc.exceptions[0].__cause__,
777            ExceptionGroup("eg", [OSError(2)]))
778
779        self.assertMetadataNotEqual(orig, exc)
780        self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
781        self.assertMetadataEqual(orig, exc.exceptions[0].__cause__)
782        self.assertMetadataNotEqual(orig, exc.exceptions[1].__context__)
783        self.assertMetadataNotEqual(orig, exc.exceptions[1].__cause__)
784
785    def test_raise_handle_all_raise_one_named(self):
786        orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
787        try:
788            try:
789                raise orig
790            except* (TypeError, ValueError) as e:
791                raise SyntaxError(3) from e
792        except SyntaxError as e:
793            exc = e
794
795        self.assertExceptionIsLike(exc, SyntaxError(3))
796
797        self.assertExceptionIsLike(
798            exc.__context__,
799            ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
800
801        self.assertExceptionIsLike(
802            exc.__cause__,
803            ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
804
805        self.assertMetadataNotEqual(orig, exc)
806        self.assertMetadataEqual(orig, exc.__context__)
807        self.assertMetadataEqual(orig, exc.__cause__)
808
809    def test_raise_handle_all_raise_one_unnamed(self):
810        orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
811        try:
812            try:
813                raise orig
814            except* (TypeError, ValueError) as e:
815                e = sys.exception()
816                raise SyntaxError(3) from e
817        except SyntaxError as e:
818            exc = e
819
820        self.assertExceptionIsLike(exc, SyntaxError(3))
821
822        self.assertExceptionIsLike(
823            exc.__context__,
824            ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
825
826        self.assertExceptionIsLike(
827            exc.__cause__,
828            ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
829
830        self.assertMetadataNotEqual(orig, exc)
831        self.assertMetadataEqual(orig, exc.__context__)
832        self.assertMetadataEqual(orig, exc.__cause__)
833
834    def test_raise_handle_all_raise_two_named(self):
835        orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
836        try:
837            try:
838                raise orig
839            except* TypeError as e:
840                raise SyntaxError(3) from e
841            except* ValueError as e:
842                raise SyntaxError(4) from e
843        except ExceptionGroup as e:
844            exc = e
845
846        self.assertExceptionIsLike(
847            exc, ExceptionGroup("", [SyntaxError(3), SyntaxError(4)]))
848
849        self.assertExceptionIsLike(
850            exc.exceptions[0].__context__,
851            ExceptionGroup("eg", [TypeError(1)]))
852
853        self.assertExceptionIsLike(
854            exc.exceptions[0].__cause__,
855            ExceptionGroup("eg", [TypeError(1)]))
856
857        self.assertExceptionIsLike(
858            exc.exceptions[1].__context__,
859            ExceptionGroup("eg", [ValueError(2)]))
860
861        self.assertExceptionIsLike(
862            exc.exceptions[1].__cause__,
863            ExceptionGroup("eg", [ValueError(2)]))
864
865        self.assertMetadataNotEqual(orig, exc)
866        self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
867        self.assertMetadataEqual(orig, exc.exceptions[0].__cause__)
868
869    def test_raise_handle_all_raise_two_unnamed(self):
870        orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
871        try:
872            try:
873                raise orig
874            except* TypeError:
875                e = sys.exception()
876                raise SyntaxError(3) from e
877            except* ValueError:
878                e = sys.exception()
879                raise SyntaxError(4) from e
880        except ExceptionGroup as e:
881            exc = e
882
883        self.assertExceptionIsLike(
884            exc, ExceptionGroup("", [SyntaxError(3), SyntaxError(4)]))
885
886        self.assertExceptionIsLike(
887            exc.exceptions[0].__context__,
888            ExceptionGroup("eg", [TypeError(1)]))
889
890        self.assertExceptionIsLike(
891            exc.exceptions[0].__cause__,
892            ExceptionGroup("eg", [TypeError(1)]))
893
894        self.assertExceptionIsLike(
895            exc.exceptions[1].__context__,
896            ExceptionGroup("eg", [ValueError(2)]))
897
898        self.assertExceptionIsLike(
899            exc.exceptions[1].__cause__,
900            ExceptionGroup("eg", [ValueError(2)]))
901
902        self.assertMetadataNotEqual(orig, exc)
903        self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
904        self.assertMetadataEqual(orig, exc.exceptions[0].__cause__)
905        self.assertMetadataEqual(orig, exc.exceptions[1].__context__)
906        self.assertMetadataEqual(orig, exc.exceptions[1].__cause__)
907
908
909class TestExceptStarExceptionGroupSubclass(ExceptStarTest):
910    def test_except_star_EG_subclass(self):
911        class EG(ExceptionGroup):
912            def __new__(cls, message, excs, code):
913                obj = super().__new__(cls, message, excs)
914                obj.code = code
915                return obj
916
917            def derive(self, excs):
918                return EG(self.message, excs, self.code)
919
920        try:
921            try:
922                try:
923                    try:
924                        raise TypeError(2)
925                    except TypeError as te:
926                        raise EG("nested", [te], 101) from None
927                except EG as nested:
928                    try:
929                        raise ValueError(1)
930                    except ValueError as ve:
931                        raise EG("eg", [ve, nested], 42)
932            except* ValueError as eg:
933                veg = eg
934        except EG as eg:
935            teg = eg
936
937        self.assertIsInstance(veg, EG)
938        self.assertIsInstance(teg, EG)
939        self.assertIsInstance(teg.exceptions[0], EG)
940        self.assertMetadataEqual(veg, teg)
941        self.assertEqual(veg.code, 42)
942        self.assertEqual(teg.code, 42)
943        self.assertEqual(teg.exceptions[0].code, 101)
944
945    def test_falsy_exception_group_subclass(self):
946        class FalsyEG(ExceptionGroup):
947            def __bool__(self):
948                return False
949
950            def derive(self, excs):
951                return FalsyEG(self.message, excs)
952
953        try:
954            try:
955                raise FalsyEG("eg", [TypeError(1), ValueError(2)])
956            except *TypeError as e:
957                tes = e
958                raise
959            except *ValueError as e:
960                ves = e
961                pass
962        except Exception as e:
963            exc = e
964
965        for e in [tes, ves, exc]:
966            self.assertFalse(e)
967            self.assertIsInstance(e, FalsyEG)
968
969        self.assertExceptionIsLike(exc, FalsyEG("eg", [TypeError(1)]))
970        self.assertExceptionIsLike(tes, FalsyEG("eg", [TypeError(1)]))
971        self.assertExceptionIsLike(ves, FalsyEG("eg", [ValueError(2)]))
972
973
974class TestExceptStarCleanup(ExceptStarTest):
975    def test_sys_exception_restored(self):
976        try:
977            try:
978                raise ValueError(42)
979            except:
980                try:
981                    raise TypeError(int)
982                except* Exception:
983                    pass
984                1/0
985        except Exception as e:
986            exc = e
987
988        self.assertExceptionIsLike(exc, ZeroDivisionError('division by zero'))
989        self.assertExceptionIsLike(exc.__context__, ValueError(42))
990        self.assertEqual(sys.exception(), None)
991
992
993class TestExceptStar_WeirdLeafExceptions(ExceptStarTest):
994    # Test that except* works when leaf exceptions are
995    # unhashable or have a bad custom __eq__
996
997    class UnhashableExc(ValueError):
998        __hash__ = None
999
1000    class AlwaysEqualExc(ValueError):
1001        def __eq__(self, other):
1002            return True
1003
1004    class NeverEqualExc(ValueError):
1005        def __eq__(self, other):
1006            return False
1007
1008    class BrokenEqualExc(ValueError):
1009        def __eq__(self, other):
1010            raise RuntimeError()
1011
1012    def setUp(self):
1013        self.bad_types = [self.UnhashableExc,
1014                          self.AlwaysEqualExc,
1015                          self.NeverEqualExc,
1016                          self.BrokenEqualExc]
1017
1018    def except_type(self, eg, type):
1019        match, rest = None, None
1020        try:
1021            try:
1022                raise eg
1023            except* type  as e:
1024                match = e
1025        except Exception as e:
1026            rest = e
1027        return match, rest
1028
1029    def test_catch_unhashable_leaf_exception(self):
1030        for Bad in self.bad_types:
1031            with self.subTest(Bad):
1032                eg = ExceptionGroup("eg", [TypeError(1), Bad(2)])
1033                match, rest = self.except_type(eg, Bad)
1034                self.assertExceptionIsLike(
1035                    match, ExceptionGroup("eg", [Bad(2)]))
1036                self.assertExceptionIsLike(
1037                    rest, ExceptionGroup("eg", [TypeError(1)]))
1038
1039    def test_propagate_unhashable_leaf(self):
1040        for Bad in self.bad_types:
1041            with self.subTest(Bad):
1042                eg = ExceptionGroup("eg", [TypeError(1), Bad(2)])
1043                match, rest = self.except_type(eg, TypeError)
1044                self.assertExceptionIsLike(
1045                    match, ExceptionGroup("eg", [TypeError(1)]))
1046                self.assertExceptionIsLike(
1047                    rest, ExceptionGroup("eg", [Bad(2)]))
1048
1049    def test_catch_nothing_unhashable_leaf(self):
1050        for Bad in self.bad_types:
1051            with self.subTest(Bad):
1052                eg = ExceptionGroup("eg", [TypeError(1), Bad(2)])
1053                match, rest = self.except_type(eg, OSError)
1054                self.assertIsNone(match)
1055                self.assertExceptionIsLike(rest, eg)
1056
1057    def test_catch_everything_unhashable_leaf(self):
1058        for Bad in self.bad_types:
1059            with self.subTest(Bad):
1060                eg = ExceptionGroup("eg", [TypeError(1), Bad(2)])
1061                match, rest = self.except_type(eg, Exception)
1062                self.assertExceptionIsLike(match, eg)
1063                self.assertIsNone(rest)
1064
1065    def test_reraise_unhashable_leaf(self):
1066        for Bad in self.bad_types:
1067            with self.subTest(Bad):
1068                eg = ExceptionGroup(
1069                    "eg", [TypeError(1), Bad(2), ValueError(3)])
1070
1071                try:
1072                    try:
1073                        raise eg
1074                    except* TypeError:
1075                        pass
1076                    except* Bad:
1077                        raise
1078                except Exception as e:
1079                    exc = e
1080
1081                self.assertExceptionIsLike(
1082                    exc, ExceptionGroup("eg", [Bad(2), ValueError(3)]))
1083
1084
1085class TestExceptStar_WeirdExceptionGroupSubclass(ExceptStarTest):
1086    # Test that except* works with exception groups that are
1087    # unhashable or have a bad custom __eq__
1088
1089    class UnhashableEG(ExceptionGroup):
1090        __hash__ = None
1091
1092        def derive(self, excs):
1093            return type(self)(self.message, excs)
1094
1095    class AlwaysEqualEG(ExceptionGroup):
1096        def __eq__(self, other):
1097            return True
1098
1099        def derive(self, excs):
1100            return type(self)(self.message, excs)
1101
1102    class NeverEqualEG(ExceptionGroup):
1103        def __eq__(self, other):
1104            return False
1105
1106        def derive(self, excs):
1107            return type(self)(self.message, excs)
1108
1109    class BrokenEqualEG(ExceptionGroup):
1110        def __eq__(self, other):
1111            raise RuntimeError()
1112
1113        def derive(self, excs):
1114            return type(self)(self.message, excs)
1115
1116    def setUp(self):
1117        self.bad_types = [self.UnhashableEG,
1118                          self.AlwaysEqualEG,
1119                          self.NeverEqualEG,
1120                          self.BrokenEqualEG]
1121
1122    def except_type(self, eg, type):
1123        match, rest = None, None
1124        try:
1125            try:
1126                raise eg
1127            except* type  as e:
1128                match = e
1129        except Exception as e:
1130            rest = e
1131        return match, rest
1132
1133    def test_catch_some_unhashable_exception_group_subclass(self):
1134        for BadEG in self.bad_types:
1135            with self.subTest(BadEG):
1136                eg = BadEG("eg",
1137                           [TypeError(1),
1138                            BadEG("nested", [ValueError(2)])])
1139
1140                match, rest = self.except_type(eg, TypeError)
1141                self.assertExceptionIsLike(match, BadEG("eg", [TypeError(1)]))
1142                self.assertExceptionIsLike(rest,
1143                    BadEG("eg", [BadEG("nested", [ValueError(2)])]))
1144
1145    def test_catch_none_unhashable_exception_group_subclass(self):
1146        for BadEG in self.bad_types:
1147            with self.subTest(BadEG):
1148
1149                eg = BadEG("eg",
1150                           [TypeError(1),
1151                            BadEG("nested", [ValueError(2)])])
1152
1153                match, rest = self.except_type(eg, OSError)
1154                self.assertIsNone(match)
1155                self.assertExceptionIsLike(rest, eg)
1156
1157    def test_catch_all_unhashable_exception_group_subclass(self):
1158        for BadEG in self.bad_types:
1159            with self.subTest(BadEG):
1160
1161                eg = BadEG("eg",
1162                           [TypeError(1),
1163                            BadEG("nested", [ValueError(2)])])
1164
1165                match, rest = self.except_type(eg, Exception)
1166                self.assertExceptionIsLike(match, eg)
1167                self.assertIsNone(rest)
1168
1169    def test_reraise_unhashable_eg(self):
1170        for BadEG in self.bad_types:
1171            with self.subTest(BadEG):
1172
1173                eg = BadEG("eg",
1174                           [TypeError(1), ValueError(2),
1175                            BadEG("nested", [ValueError(3), OSError(4)])])
1176
1177                try:
1178                    try:
1179                        raise eg
1180                    except* ValueError:
1181                        pass
1182                    except* OSError:
1183                        raise
1184                except Exception as e:
1185                    exc = e
1186
1187                self.assertExceptionIsLike(
1188                    exc, BadEG("eg", [TypeError(1),
1189                               BadEG("nested", [OSError(4)])]))
1190
1191
1192if __name__ == '__main__':
1193    unittest.main()
1194