@@ -111,8 +111,11 @@ def test_caret(self):
111
111
def test_nocaret (self ):
112
112
exc = SyntaxError ("error" , ("x.py" , 23 , None , "bad syntax" ))
113
113
err = traceback .format_exception_only (SyntaxError , exc )
114
- self .assertEqual (len (err ), 3 )
115
- self .assertEqual (err [1 ].strip (), "bad syntax" )
114
+ self .assertEqual (err , [
115
+ ' File "x.py", line 23\n ' ,
116
+ ' bad syntax\n ' ,
117
+ 'SyntaxError: error\n ' ,
118
+ ])
116
119
117
120
def test_no_caret_with_no_debug_ranges_flag (self ):
118
121
# Make sure that if `-X no_debug_ranges` is used, there are no carets
@@ -364,6 +367,232 @@ def f():
364
367
' ValueError: 0\n ' ,
365
368
])
366
369
370
+ def test_format_exception_group_width_limit (self ):
371
+ eg = ExceptionGroup ('A' , [ValueError (i ) for i in range (100 )])
372
+ err = traceback .format_exception_only (eg , show_group = True )
373
+ self .assertEqual (err , [
374
+ 'ExceptionGroup: A (100 sub-exceptions)\n ' ,
375
+ ' ValueError: 0\n ' ,
376
+ ' ValueError: 1\n ' ,
377
+ ' ValueError: 2\n ' ,
378
+ ' ValueError: 3\n ' ,
379
+ ' ValueError: 4\n ' ,
380
+ ' ValueError: 5\n ' ,
381
+ ' ValueError: 6\n ' ,
382
+ ' ValueError: 7\n ' ,
383
+ ' ValueError: 8\n ' ,
384
+ ' ValueError: 9\n ' ,
385
+ ' ValueError: 10\n ' ,
386
+ ' ValueError: 11\n ' ,
387
+ ' ValueError: 12\n ' ,
388
+ ' ValueError: 13\n ' ,
389
+ ' ValueError: 14\n ' ,
390
+ ' and 85 more exceptions\n ' ,
391
+ ])
392
+
393
+ def test_format_exception_group_width_limit_n_plus_1 (self ):
394
+ # bigger than `TracebackException.max_group_width`
395
+ eg = ExceptionGroup ('A' , [ValueError (i ) for i in range (16 )])
396
+ err = traceback .format_exception_only (eg , show_group = True )
397
+ self .assertEqual (err , [
398
+ 'ExceptionGroup: A (16 sub-exceptions)\n ' ,
399
+ ' ValueError: 0\n ' ,
400
+ ' ValueError: 1\n ' ,
401
+ ' ValueError: 2\n ' ,
402
+ ' ValueError: 3\n ' ,
403
+ ' ValueError: 4\n ' ,
404
+ ' ValueError: 5\n ' ,
405
+ ' ValueError: 6\n ' ,
406
+ ' ValueError: 7\n ' ,
407
+ ' ValueError: 8\n ' ,
408
+ ' ValueError: 9\n ' ,
409
+ ' ValueError: 10\n ' ,
410
+ ' ValueError: 11\n ' ,
411
+ ' ValueError: 12\n ' ,
412
+ ' ValueError: 13\n ' ,
413
+ ' ValueError: 14\n ' ,
414
+ ' and 1 more exception\n ' ,
415
+ ])
416
+
417
+ def test_format_exception_group_width_limit_of_syntax_errors (self ):
418
+ eg = ExceptionGroup ('A' , [
419
+ SyntaxError (i , ("x.py" , 23 , None , "bad syntax" ))
420
+ for i in range (16 )
421
+ ])
422
+ err = traceback .format_exception_only (eg , show_group = True )
423
+ self .assertEqual (err , [
424
+ 'ExceptionGroup: A (16 sub-exceptions)\n ' ,
425
+ ' File "x.py", line 23\n ' ,
426
+ ' bad syntax\n ' ,
427
+ ' SyntaxError: <no detail available>\n ' ,
428
+ ' File "x.py", line 23\n ' ,
429
+ ' bad syntax\n ' ,
430
+ ' SyntaxError: 1\n ' ,
431
+ ' File "x.py", line 23\n ' ,
432
+ ' bad syntax\n ' ,
433
+ ' SyntaxError: 2\n ' ,
434
+ ' File "x.py", line 23\n ' ,
435
+ ' bad syntax\n ' ,
436
+ ' SyntaxError: 3\n ' ,
437
+ ' File "x.py", line 23\n ' ,
438
+ ' bad syntax\n ' ,
439
+ ' SyntaxError: 4\n ' ,
440
+ ' File "x.py", line 23\n ' ,
441
+ ' bad syntax\n ' ,
442
+ ' SyntaxError: 5\n ' ,
443
+ ' File "x.py", line 23\n ' ,
444
+ ' bad syntax\n ' ,
445
+ ' SyntaxError: 6\n ' ,
446
+ ' File "x.py", line 23\n ' ,
447
+ ' bad syntax\n ' ,
448
+ ' SyntaxError: 7\n ' ,
449
+ ' File "x.py", line 23\n ' ,
450
+ ' bad syntax\n ' ,
451
+ ' SyntaxError: 8\n ' ,
452
+ ' File "x.py", line 23\n ' ,
453
+ ' bad syntax\n ' ,
454
+ ' SyntaxError: 9\n ' ,
455
+ ' File "x.py", line 23\n ' ,
456
+ ' bad syntax\n ' ,
457
+ ' SyntaxError: 10\n ' ,
458
+ ' File "x.py", line 23\n ' ,
459
+ ' bad syntax\n ' ,
460
+ ' SyntaxError: 11\n ' ,
461
+ ' File "x.py", line 23\n ' ,
462
+ ' bad syntax\n ' ,
463
+ ' SyntaxError: 12\n ' ,
464
+ ' File "x.py", line 23\n ' ,
465
+ ' bad syntax\n ' ,
466
+ ' SyntaxError: 13\n ' ,
467
+ ' File "x.py", line 23\n ' ,
468
+ ' bad syntax\n ' ,
469
+ ' SyntaxError: 14\n ' ,
470
+ ' and 1 more exception\n ' ,
471
+ ])
472
+
473
+ def test_format_exception_group_no_width_limit (self ):
474
+ eg = ExceptionGroup ('A' , [ValueError (i ) for i in range (17 )])
475
+ err = traceback .format_exception_only (eg , show_group = True , limit_group = False )
476
+ self .assertEqual (err , [
477
+ 'ExceptionGroup: A (17 sub-exceptions)\n ' ,
478
+ ' ValueError: 0\n ' ,
479
+ ' ValueError: 1\n ' ,
480
+ ' ValueError: 2\n ' ,
481
+ ' ValueError: 3\n ' ,
482
+ ' ValueError: 4\n ' ,
483
+ ' ValueError: 5\n ' ,
484
+ ' ValueError: 6\n ' ,
485
+ ' ValueError: 7\n ' ,
486
+ ' ValueError: 8\n ' ,
487
+ ' ValueError: 9\n ' ,
488
+ ' ValueError: 10\n ' ,
489
+ ' ValueError: 11\n ' ,
490
+ ' ValueError: 12\n ' ,
491
+ ' ValueError: 13\n ' ,
492
+ ' ValueError: 14\n ' ,
493
+ ' ValueError: 15\n ' ,
494
+ ' ValueError: 16\n ' ,
495
+ ])
496
+
497
+ def test_format_nested_exception_group_nesting_limit (self ):
498
+ exc = TypeError ('bad type' )
499
+ for i in range (11 ): # bigger than `TracebackException.max_group_depth`
500
+ exc = ExceptionGroup (f'eg{ i } ' , [ValueError (i ), exc , ValueError (- i )])
501
+ err = traceback .format_exception_only (exc , show_group = True )
502
+ self .assertEqual (err , [
503
+ 'ExceptionGroup: eg10 (3 sub-exceptions)\n ' ,
504
+ ' ValueError: 10\n ' ,
505
+ ' ExceptionGroup: eg9 (3 sub-exceptions)\n ' ,
506
+ ' ValueError: 9\n ' ,
507
+ ' ExceptionGroup: eg8 (3 sub-exceptions)\n ' ,
508
+ ' ValueError: 8\n ' ,
509
+ ' ExceptionGroup: eg7 (3 sub-exceptions)\n ' ,
510
+ ' ValueError: 7\n ' ,
511
+ ' ExceptionGroup: eg6 (3 sub-exceptions)\n ' ,
512
+ ' ValueError: 6\n ' ,
513
+ ' ExceptionGroup: eg5 (3 sub-exceptions)\n ' ,
514
+ ' ValueError: 5\n ' ,
515
+ ' ExceptionGroup: eg4 (3 sub-exceptions)\n ' ,
516
+ ' ValueError: 4\n ' ,
517
+ ' ExceptionGroup: eg3 (3 sub-exceptions)\n ' ,
518
+ ' ValueError: 3\n ' ,
519
+ ' ExceptionGroup: eg2 (3 sub-exceptions)\n ' ,
520
+ ' ValueError: 2\n ' ,
521
+ ' ExceptionGroup: eg1 (3 sub-exceptions)\n ' ,
522
+ ' ValueError: 1\n ' ,
523
+ ' ... (max_group_depth is 10)\n ' ,
524
+ ' ValueError: -1\n ' ,
525
+ ' ValueError: -2\n ' ,
526
+ ' ValueError: -3\n ' ,
527
+ ' ValueError: -4\n ' ,
528
+ ' ValueError: -5\n ' ,
529
+ ' ValueError: -6\n ' ,
530
+ ' ValueError: -7\n ' ,
531
+ ' ValueError: -8\n ' ,
532
+ ' ValueError: -9\n ' ,
533
+ ' ValueError: -10\n ' ,
534
+ ])
535
+
536
+ def test_format_nested_exception_group_nesting_no_limit (self ):
537
+ exc = TypeError ('bad type' )
538
+ for i in range (11 ):
539
+ exc = ExceptionGroup (f'eg{ i } ' , [ValueError (i ), exc , ValueError (- i )])
540
+ err = traceback .format_exception_only (exc , show_group = True , limit_group = False )
541
+ self .assertEqual (err , [
542
+ 'ExceptionGroup: eg10 (3 sub-exceptions)\n ' ,
543
+ ' ValueError: 10\n ' ,
544
+ ' ExceptionGroup: eg9 (3 sub-exceptions)\n ' ,
545
+ ' ValueError: 9\n ' ,
546
+ ' ExceptionGroup: eg8 (3 sub-exceptions)\n ' ,
547
+ ' ValueError: 8\n ' ,
548
+ ' ExceptionGroup: eg7 (3 sub-exceptions)\n ' ,
549
+ ' ValueError: 7\n ' ,
550
+ ' ExceptionGroup: eg6 (3 sub-exceptions)\n ' ,
551
+ ' ValueError: 6\n ' ,
552
+ ' ExceptionGroup: eg5 (3 sub-exceptions)\n ' ,
553
+ ' ValueError: 5\n ' ,
554
+ ' ExceptionGroup: eg4 (3 sub-exceptions)\n ' ,
555
+ ' ValueError: 4\n ' ,
556
+ ' ExceptionGroup: eg3 (3 sub-exceptions)\n ' ,
557
+ ' ValueError: 3\n ' ,
558
+ ' ExceptionGroup: eg2 (3 sub-exceptions)\n ' ,
559
+ ' ValueError: 2\n ' ,
560
+ ' ExceptionGroup: eg1 (3 sub-exceptions)\n ' ,
561
+ ' ValueError: 1\n ' ,
562
+ ' ExceptionGroup: eg0 (3 sub-exceptions)\n ' ,
563
+ ' ValueError: 0\n ' ,
564
+ ' TypeError: bad type\n ' ,
565
+ ' ValueError: 0\n ' ,
566
+ ' ValueError: -1\n ' ,
567
+ ' ValueError: -2\n ' ,
568
+ ' ValueError: -3\n ' ,
569
+ ' ValueError: -4\n ' ,
570
+ ' ValueError: -5\n ' ,
571
+ ' ValueError: -6\n ' ,
572
+ ' ValueError: -7\n ' ,
573
+ ' ValueError: -8\n ' ,
574
+ ' ValueError: -9\n ' ,
575
+ ' ValueError: -10\n ' ,
576
+ ])
577
+
578
+ def test_format_exception_group_no_width_limit_reursion_error (self ):
579
+ rec_limit = 100
580
+ exc = TypeError ('bad type' )
581
+ for i in range (rec_limit + 1 ):
582
+ exc = ExceptionGroup (f'eg{ i } ' , [ValueError (i ), exc , ValueError (- i )])
583
+
584
+ with support .infinite_recursion (rec_limit ):
585
+ # Does not raise:
586
+ traceback .format_exception_only (
587
+ exc , show_group = True , limit_group = True ,
588
+ )
589
+
590
+ # Raises:
591
+ with self .assertRaises (RecursionError ):
592
+ traceback .format_exception_only (
593
+ exc , show_group = True , limit_group = False ,
594
+ )
595
+
367
596
@requires_subprocess ()
368
597
def test_encoded_file (self ):
369
598
# Test that tracebacks are correctly printed for encoded source files:
@@ -494,6 +723,18 @@ def test_format_exception_only_exc(self):
494
723
output = traceback .format_exception_only (Exception ("projector" ))
495
724
self .assertEqual (output , ["Exception: projector\n " ])
496
725
726
+ def test_format_exception_only_exc_limit_group_false (self ):
727
+ # Extra kwargs do not affect regular exceptions:
728
+ output = traceback .format_exception_only (
729
+ Exception ("projector" ), limit_group = True ,
730
+ )
731
+ self .assertEqual (output , ["Exception: projector\n " ])
732
+
733
+ output = traceback .format_exception_only (
734
+ Exception ("projector" ), show_group = True , limit_group = True ,
735
+ )
736
+ self .assertEqual (output , ["Exception: projector\n " ])
737
+
497
738
def test_exception_is_None (self ):
498
739
NONE_EXC_STRING = 'NoneType: None\n '
499
740
excfile = StringIO ()
@@ -530,7 +771,7 @@ def test_signatures(self):
530
771
531
772
self .assertEqual (
532
773
str (inspect .signature (traceback .format_exception_only )),
533
- '(exc, /, value=<implicit>, *, show_group=False)' )
774
+ '(exc, /, value=<implicit>, *, show_group=False, limit_group=True )' )
534
775
535
776
536
777
class PurePythonExceptionFormattingMixin :
0 commit comments