2828from  . import  pretty 
2929from  ._loop  import  loop_first_last , loop_last 
3030from  .columns  import  Columns 
31- from  .console  import  Console , ConsoleOptions , ConsoleRenderable , RenderResult , group 
31+ from  .console  import  (
32+     Console ,
33+     ConsoleOptions ,
34+     ConsoleRenderable ,
35+     Group ,
36+     RenderResult ,
37+     group ,
38+ )
3239from  .constrain  import  Constrain 
3340from  .highlighter  import  RegexHighlighter , ReprHighlighter 
3441from  .panel  import  Panel 
@@ -128,26 +135,25 @@ def excepthook(
128135        value : BaseException ,
129136        traceback : Optional [TracebackType ],
130137    ) ->  None :
131-         traceback_console .print (
132-             Traceback .from_exception (
133-                 type_ ,
134-                 value ,
135-                 traceback ,
136-                 width = width ,
137-                 code_width = code_width ,
138-                 extra_lines = extra_lines ,
139-                 theme = theme ,
140-                 word_wrap = word_wrap ,
141-                 show_locals = show_locals ,
142-                 locals_max_length = locals_max_length ,
143-                 locals_max_string = locals_max_string ,
144-                 locals_hide_dunder = locals_hide_dunder ,
145-                 locals_hide_sunder = bool (locals_hide_sunder ),
146-                 indent_guides = indent_guides ,
147-                 suppress = suppress ,
148-                 max_frames = max_frames ,
149-             )
138+         exception_traceback  =  Traceback .from_exception (
139+             type_ ,
140+             value ,
141+             traceback ,
142+             width = width ,
143+             code_width = code_width ,
144+             extra_lines = extra_lines ,
145+             theme = theme ,
146+             word_wrap = word_wrap ,
147+             show_locals = show_locals ,
148+             locals_max_length = locals_max_length ,
149+             locals_max_string = locals_max_string ,
150+             locals_hide_dunder = locals_hide_dunder ,
151+             locals_hide_sunder = bool (locals_hide_sunder ),
152+             indent_guides = indent_guides ,
153+             suppress = suppress ,
154+             max_frames = max_frames ,
150155        )
156+         traceback_console .print (exception_traceback )
151157
152158    def  ipy_excepthook_closure (ip : Any ) ->  None :  # pragma: no cover 
153159        tb_data  =  {}  # store information about showtraceback call 
@@ -230,6 +236,8 @@ class Stack:
230236    is_cause : bool  =  False 
231237    frames : List [Frame ] =  field (default_factory = list )
232238    notes : List [str ] =  field (default_factory = list )
239+     is_group : bool  =  False 
240+     exceptions : List ["Trace" ] =  field (default_factory = list )
233241
234242
235243@dataclass  
@@ -450,6 +458,22 @@ def safe_str(_object: Any) -> str:
450458                notes = notes ,
451459            )
452460
461+             if  sys .version_info  >=  (3 , 11 ):
462+                 if  isinstance (exc_value , (BaseExceptionGroup , ExceptionGroup )):
463+                     stack .is_group  =  True 
464+                     for  exception  in  exc_value .exceptions :
465+                         stack .exceptions .append (
466+                             Traceback .extract (
467+                                 type (exception ),
468+                                 exception ,
469+                                 exception .__traceback__ ,
470+                                 show_locals = show_locals ,
471+                                 locals_max_length = locals_max_length ,
472+                                 locals_hide_dunder = locals_hide_dunder ,
473+                                 locals_hide_sunder = locals_hide_sunder ,
474+                             )
475+                         )
476+ 
453477            if  isinstance (exc_value , SyntaxError ):
454478                stack .syntax_error  =  _SyntaxError (
455479                    offset = exc_value .offset  or  0 ,
@@ -558,6 +582,7 @@ def get_locals(
558582            break   # pragma: no cover 
559583
560584        trace  =  Trace (stacks = stacks )
585+ 
561586        return  trace 
562587
563588    def  __rich_console__ (
@@ -590,7 +615,9 @@ def __rich_console__(
590615        )
591616
592617        highlighter  =  ReprHighlighter ()
593-         for  last , stack  in  loop_last (reversed (self .trace .stacks )):
618+ 
619+         @group () 
620+         def  render_stack (stack : Stack , last : bool ) ->  RenderResult :
594621            if  stack .frames :
595622                stack_renderable : ConsoleRenderable  =  Panel (
596623                    self ._render_stack (stack ),
@@ -632,6 +659,21 @@ def __rich_console__(
632659            for  note  in  stack .notes :
633660                yield  Text .assemble (("[NOTE] " , "traceback.note" ), highlighter (note ))
634661
662+             if  stack .is_group :
663+                 for  group_no , group_exception  in  enumerate (stack .exceptions , 1 ):
664+                     grouped_exceptions : List [Group ] =  []
665+                     for  group_last , group_stack  in  loop_last (group_exception .stacks ):
666+                         grouped_exceptions .append (render_stack (group_stack , group_last ))
667+                     yield  "" 
668+                     yield  Constrain (
669+                         Panel (
670+                             Group (* grouped_exceptions ),
671+                             title = f"Sub-exception #{ group_no }  ,
672+                             border_style = "traceback.group.border" ,
673+                         ),
674+                         self .width ,
675+                     )
676+ 
635677            if  not  last :
636678                if  stack .is_cause :
637679                    yield  Text .from_markup (
@@ -642,6 +684,9 @@ def __rich_console__(
642684                        "\n [i]During handling of the above exception, another exception occurred:\n " ,
643685                    )
644686
687+         for  last , stack  in  loop_last (reversed (self .trace .stacks )):
688+             yield  render_stack (stack , last )
689+ 
645690    @group () 
646691    def  _render_syntax_error (self , syntax_error : _SyntaxError ) ->  RenderResult :
647692        highlighter  =  ReprHighlighter ()
0 commit comments