3
3
import _pytest
4
4
import py
5
5
import pytest
6
- from _pytest ._code .code import FormattedExcinfo , ReprExceptionInfo
6
+ from _pytest ._code .code import (FormattedExcinfo , ReprExceptionInfo ,
7
+ ExceptionChainRepr )
7
8
8
9
queue = py .builtin ._tryimport ('queue' , 'Queue' )
9
10
@@ -404,6 +405,8 @@ def test_repr_source_not_existing(self):
404
405
excinfo = _pytest ._code .ExceptionInfo ()
405
406
repr = pr .repr_excinfo (excinfo )
406
407
assert repr .reprtraceback .reprentries [1 ].lines [0 ] == "> ???"
408
+ if py .std .sys .version_info [0 ] >= 3 :
409
+ assert repr .chain [0 ][0 ].reprentries [1 ].lines [0 ] == "> ???"
407
410
408
411
def test_repr_many_line_source_not_existing (self ):
409
412
pr = FormattedExcinfo ()
@@ -417,6 +420,8 @@ def test_repr_many_line_source_not_existing(self):
417
420
excinfo = _pytest ._code .ExceptionInfo ()
418
421
repr = pr .repr_excinfo (excinfo )
419
422
assert repr .reprtraceback .reprentries [1 ].lines [0 ] == "> ???"
423
+ if py .std .sys .version_info [0 ] >= 3 :
424
+ assert repr .chain [0 ][0 ].reprentries [1 ].lines [0 ] == "> ???"
420
425
421
426
def test_repr_source_failing_fullsource (self ):
422
427
pr = FormattedExcinfo ()
@@ -449,6 +454,7 @@ class Traceback(_pytest._code.Traceback):
449
454
450
455
class FakeExcinfo (_pytest ._code .ExceptionInfo ):
451
456
typename = "Foo"
457
+ value = Exception ()
452
458
def __init__ (self ):
453
459
pass
454
460
@@ -466,10 +472,15 @@ class FakeRawTB(object):
466
472
fail = IOError () # noqa
467
473
repr = pr .repr_excinfo (excinfo )
468
474
assert repr .reprtraceback .reprentries [0 ].lines [0 ] == "> ???"
475
+ if py .std .sys .version_info [0 ] >= 3 :
476
+ assert repr .chain [0 ][0 ].reprentries [0 ].lines [0 ] == "> ???"
477
+
469
478
470
479
fail = py .error .ENOENT # noqa
471
480
repr = pr .repr_excinfo (excinfo )
472
481
assert repr .reprtraceback .reprentries [0 ].lines [0 ] == "> ???"
482
+ if py .std .sys .version_info [0 ] >= 3 :
483
+ assert repr .chain [0 ][0 ].reprentries [0 ].lines [0 ] == "> ???"
473
484
474
485
475
486
def test_repr_local (self ):
@@ -656,6 +667,9 @@ def entry():
656
667
repr = p .repr_excinfo (excinfo )
657
668
assert repr .reprtraceback
658
669
assert len (repr .reprtraceback .reprentries ) == len (reprtb .reprentries )
670
+ if py .std .sys .version_info [0 ] >= 3 :
671
+ assert repr .chain [0 ][0 ]
672
+ assert len (repr .chain [0 ][0 ].reprentries ) == len (reprtb .reprentries )
659
673
assert repr .reprcrash .path .endswith ("mod.py" )
660
674
assert repr .reprcrash .message == "ValueError: 0"
661
675
@@ -746,8 +760,13 @@ def entry():
746
760
for style in ("short" , "long" , "no" ):
747
761
for showlocals in (True , False ):
748
762
repr = excinfo .getrepr (style = style , showlocals = showlocals )
749
- assert isinstance (repr , ReprExceptionInfo )
763
+ if py .std .sys .version_info [0 ] < 3 :
764
+ assert isinstance (repr , ReprExceptionInfo )
750
765
assert repr .reprtraceback .style == style
766
+ if py .std .sys .version_info [0 ] >= 3 :
767
+ assert isinstance (repr , ExceptionChainRepr )
768
+ for repr in repr .chain :
769
+ assert repr [0 ].style == style
751
770
752
771
def test_reprexcinfo_unicode (self ):
753
772
from _pytest ._code .code import TerminalRepr
@@ -928,3 +947,70 @@ def i():
928
947
assert tw .lines [14 ] == "E ValueError"
929
948
assert tw .lines [15 ] == ""
930
949
assert tw .lines [16 ].endswith ("mod.py:9: ValueError" )
950
+
951
+ @pytest .mark .skipif ("sys.version_info[0] < 3" )
952
+ def test_exc_chain_repr (self , importasmod ):
953
+ mod = importasmod ("""
954
+ class Err(Exception):
955
+ pass
956
+ def f():
957
+ try:
958
+ g()
959
+ except Exception as e:
960
+ raise Err() from e
961
+ finally:
962
+ h()
963
+ def g():
964
+ raise ValueError()
965
+
966
+ def h():
967
+ raise AttributeError()
968
+ """ )
969
+ excinfo = pytest .raises (AttributeError , mod .f )
970
+ r = excinfo .getrepr (style = "long" )
971
+ tw = TWMock ()
972
+ r .toterminal (tw )
973
+ for line in tw .lines : print (line )
974
+ assert tw .lines [0 ] == ""
975
+ assert tw .lines [1 ] == " def f():"
976
+ assert tw .lines [2 ] == " try:"
977
+ assert tw .lines [3 ] == "> g()"
978
+ assert tw .lines [4 ] == ""
979
+ assert tw .lines [5 ].endswith ("mod.py:6: " )
980
+ assert tw .lines [6 ] == ("_ " , None )
981
+ assert tw .lines [7 ] == ""
982
+ assert tw .lines [8 ] == " def g():"
983
+ assert tw .lines [9 ] == "> raise ValueError()"
984
+ assert tw .lines [10 ] == "E ValueError"
985
+ assert tw .lines [11 ] == ""
986
+ assert tw .lines [12 ].endswith ("mod.py:12: ValueError" )
987
+ assert tw .lines [13 ] == ""
988
+ assert tw .lines [14 ] == "The above exception was the direct cause of the following exception:"
989
+ assert tw .lines [15 ] == ""
990
+ assert tw .lines [16 ] == " def f():"
991
+ assert tw .lines [17 ] == " try:"
992
+ assert tw .lines [18 ] == " g()"
993
+ assert tw .lines [19 ] == " except Exception as e:"
994
+ assert tw .lines [20 ] == "> raise Err() from e"
995
+ assert tw .lines [21 ] == "E test_exc_chain_repr0.mod.Err"
996
+ assert tw .lines [22 ] == ""
997
+ assert tw .lines [23 ].endswith ("mod.py:8: Err" )
998
+ assert tw .lines [24 ] == ""
999
+ assert tw .lines [25 ] == "During handling of the above exception, another exception occurred:"
1000
+ assert tw .lines [26 ] == ""
1001
+ assert tw .lines [27 ] == " def f():"
1002
+ assert tw .lines [28 ] == " try:"
1003
+ assert tw .lines [29 ] == " g()"
1004
+ assert tw .lines [30 ] == " except Exception as e:"
1005
+ assert tw .lines [31 ] == " raise Err() from e"
1006
+ assert tw .lines [32 ] == " finally:"
1007
+ assert tw .lines [33 ] == "> h()"
1008
+ assert tw .lines [34 ] == ""
1009
+ assert tw .lines [35 ].endswith ("mod.py:10: " )
1010
+ assert tw .lines [36 ] == ('_ ' , None )
1011
+ assert tw .lines [37 ] == ""
1012
+ assert tw .lines [38 ] == " def h():"
1013
+ assert tw .lines [39 ] == "> raise AttributeError()"
1014
+ assert tw .lines [40 ] == "E AttributeError"
1015
+ assert tw .lines [41 ] == ""
1016
+ assert tw .lines [42 ].endswith ("mod.py:15: AttributeError" )
0 commit comments