@@ -215,6 +215,155 @@ def __str__(self):
215
215
str_name = '.' .join ([X .__module__ , X .__qualname__ ])
216
216
self .assertEqual (err [0 ], "%s: %s\n " % (str_name , str_value ))
217
217
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
+
218
367
@requires_subprocess ()
219
368
def test_encoded_file (self ):
220
369
# Test that tracebacks are correctly printed for encoded source files:
@@ -381,7 +530,7 @@ def test_signatures(self):
381
530
382
531
self .assertEqual (
383
532
str (inspect .signature (traceback .format_exception_only )),
384
- '(exc, /, value=<implicit>)' )
533
+ '(exc, /, value=<implicit>, *, show_group=False )' )
385
534
386
535
387
536
class PurePythonExceptionFormattingMixin :
0 commit comments