@@ -215,6 +215,155 @@ def __str__(self):
215215 str_name = '.' .join ([X .__module__ , X .__qualname__ ])
216216 self .assertEqual (err [0 ], "%s: %s\n " % (str_name , str_value ))
217217
218+ def test_format_exception_group_without_show_group (self ):
219+ eg = ExceptionGroup ('A' , [ValueError ('B' )])
220+ err = traceback .format_exception_only (eg )
221+ self .assertEqual (err , ['ExceptionGroup: A (1 sub-exception)\n ' ])
222+
223+ def test_format_exception_group (self ):
224+ eg = ExceptionGroup ('A' , [ValueError ('B' )])
225+ err = traceback .format_exception_only (eg , show_group = True )
226+ self .assertEqual (err , [
227+ 'ExceptionGroup: A (1 sub-exception)\n ' ,
228+ ' ValueError: B\n ' ,
229+ ])
230+
231+ def test_format_base_exception_group (self ):
232+ eg = BaseExceptionGroup ('A' , [BaseException ('B' )])
233+ err = traceback .format_exception_only (eg , show_group = True )
234+ self .assertEqual (err , [
235+ 'BaseExceptionGroup: A (1 sub-exception)\n ' ,
236+ ' BaseException: B\n ' ,
237+ ])
238+
239+ def test_format_exception_group_with_note (self ):
240+ exc = ValueError ('B' )
241+ exc .add_note ('Note' )
242+ eg = ExceptionGroup ('A' , [exc ])
243+ err = traceback .format_exception_only (eg , show_group = True )
244+ self .assertEqual (err , [
245+ 'ExceptionGroup: A (1 sub-exception)\n ' ,
246+ ' ValueError: B\n ' ,
247+ ' Note\n ' ,
248+ ])
249+
250+ def test_format_exception_group_explicit_class (self ):
251+ eg = ExceptionGroup ('A' , [ValueError ('B' )])
252+ err = traceback .format_exception_only (ExceptionGroup , eg , show_group = True )
253+ self .assertEqual (err , [
254+ 'ExceptionGroup: A (1 sub-exception)\n ' ,
255+ ' ValueError: B\n ' ,
256+ ])
257+
258+ def test_format_exception_group_multiple_exceptions (self ):
259+ eg = ExceptionGroup ('A' , [ValueError ('B' ), TypeError ('C' )])
260+ err = traceback .format_exception_only (eg , show_group = True )
261+ self .assertEqual (err , [
262+ 'ExceptionGroup: A (2 sub-exceptions)\n ' ,
263+ ' ValueError: B\n ' ,
264+ ' TypeError: C\n ' ,
265+ ])
266+
267+ def test_format_exception_group_multiline_messages (self ):
268+ eg = ExceptionGroup ('A\n 1' , [ValueError ('B\n 2' )])
269+ err = traceback .format_exception_only (eg , show_group = True )
270+ self .assertEqual (err , [
271+ 'ExceptionGroup: A\n 1 (1 sub-exception)\n ' ,
272+ ' ValueError: B\n ' ,
273+ ' 2\n ' ,
274+ ])
275+
276+ def test_format_exception_group_multiline2_messages (self ):
277+ exc = ValueError ('B\n \n 2\n ' )
278+ exc .add_note ('\n C\n \n 3' )
279+ eg = ExceptionGroup ('A\n \n 1\n ' , [exc , IndexError ('D' )])
280+ err = traceback .format_exception_only (eg , show_group = True )
281+ self .assertEqual (err , [
282+ 'ExceptionGroup: A\n \n 1\n (2 sub-exceptions)\n ' ,
283+ ' ValueError: B\n ' ,
284+ ' \n ' ,
285+ ' 2\n ' ,
286+ ' \n ' ,
287+ ' \n ' , # first char of `note`
288+ ' C\n ' ,
289+ ' \n ' ,
290+ ' 3\n ' , # note ends
291+ ' IndexError: D\n ' ,
292+ ])
293+
294+ def test_format_exception_group_syntax_error (self ):
295+ exc = SyntaxError ("error" , ("x.py" , 23 , None , "bad syntax" ))
296+ eg = ExceptionGroup ('A\n 1' , [exc ])
297+ err = traceback .format_exception_only (eg , show_group = True )
298+ self .assertEqual (err , [
299+ 'ExceptionGroup: A\n 1 (1 sub-exception)\n ' ,
300+ ' File "x.py", line 23\n ' ,
301+ ' bad syntax\n ' ,
302+ ' SyntaxError: error\n ' ,
303+ ])
304+
305+ def test_format_exception_group_nested_with_notes (self ):
306+ exc = IndexError ('D' )
307+ exc .add_note ('Note\n multiline' )
308+ eg = ExceptionGroup ('A' , [
309+ ValueError ('B' ),
310+ ExceptionGroup ('C' , [exc , LookupError ('E' )]),
311+ TypeError ('F' ),
312+ ])
313+ err = traceback .format_exception_only (eg , show_group = True )
314+ self .assertEqual (err , [
315+ 'ExceptionGroup: A (3 sub-exceptions)\n ' ,
316+ ' ValueError: B\n ' ,
317+ ' ExceptionGroup: C (2 sub-exceptions)\n ' ,
318+ ' IndexError: D\n ' ,
319+ ' Note\n ' ,
320+ ' multiline\n ' ,
321+ ' LookupError: E\n ' ,
322+ ' TypeError: F\n ' ,
323+ ])
324+
325+ def test_format_exception_group_with_tracebacks (self ):
326+ def f ():
327+ try :
328+ 1 / 0
329+ except ZeroDivisionError as e :
330+ return e
331+
332+ def g ():
333+ try :
334+ raise TypeError ('g' )
335+ except TypeError as e :
336+ return e
337+
338+ eg = ExceptionGroup ('A' , [
339+ f (),
340+ ExceptionGroup ('B' , [g ()]),
341+ ])
342+ err = traceback .format_exception_only (eg , show_group = True )
343+ self .assertEqual (err , [
344+ 'ExceptionGroup: A (2 sub-exceptions)\n ' ,
345+ ' ZeroDivisionError: division by zero\n ' ,
346+ ' ExceptionGroup: B (1 sub-exception)\n ' ,
347+ ' TypeError: g\n ' ,
348+ ])
349+
350+ def test_format_exception_group_with_cause (self ):
351+ def f ():
352+ try :
353+ try :
354+ 1 / 0
355+ except ZeroDivisionError :
356+ raise ValueError (0 )
357+ except Exception as e :
358+ return e
359+
360+ eg = ExceptionGroup ('A' , [f ()])
361+ err = traceback .format_exception_only (eg , show_group = True )
362+ self .assertEqual (err , [
363+ 'ExceptionGroup: A (1 sub-exception)\n ' ,
364+ ' ValueError: 0\n ' ,
365+ ])
366+
218367 @requires_subprocess ()
219368 def test_encoded_file (self ):
220369 # Test that tracebacks are correctly printed for encoded source files:
@@ -381,7 +530,7 @@ def test_signatures(self):
381530
382531 self .assertEqual (
383532 str (inspect .signature (traceback .format_exception_only )),
384- '(exc, /, value=<implicit>)' )
533+ '(exc, /, value=<implicit>, *, show_group=False )' )
385534
386535
387536class PurePythonExceptionFormattingMixin :
0 commit comments