33import _pytest
44import py
55import pytest
6- from _pytest ._code .code import FormattedExcinfo , ReprExceptionInfo
6+ from _pytest ._code .code import (FormattedExcinfo , ReprExceptionInfo ,
7+ ExceptionChainRepr )
78
89queue = py .builtin ._tryimport ('queue' , 'Queue' )
910
@@ -404,6 +405,8 @@ def test_repr_source_not_existing(self):
404405 excinfo = _pytest ._code .ExceptionInfo ()
405406 repr = pr .repr_excinfo (excinfo )
406407 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 ] == "> ???"
407410
408411 def test_repr_many_line_source_not_existing (self ):
409412 pr = FormattedExcinfo ()
@@ -417,6 +420,8 @@ def test_repr_many_line_source_not_existing(self):
417420 excinfo = _pytest ._code .ExceptionInfo ()
418421 repr = pr .repr_excinfo (excinfo )
419422 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 ] == "> ???"
420425
421426 def test_repr_source_failing_fullsource (self ):
422427 pr = FormattedExcinfo ()
@@ -449,6 +454,7 @@ class Traceback(_pytest._code.Traceback):
449454
450455 class FakeExcinfo (_pytest ._code .ExceptionInfo ):
451456 typename = "Foo"
457+ value = Exception ()
452458 def __init__ (self ):
453459 pass
454460
@@ -466,10 +472,15 @@ class FakeRawTB(object):
466472 fail = IOError () # noqa
467473 repr = pr .repr_excinfo (excinfo )
468474 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+
469478
470479 fail = py .error .ENOENT # noqa
471480 repr = pr .repr_excinfo (excinfo )
472481 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 ] == "> ???"
473484
474485
475486 def test_repr_local (self ):
@@ -656,6 +667,9 @@ def entry():
656667 repr = p .repr_excinfo (excinfo )
657668 assert repr .reprtraceback
658669 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 )
659673 assert repr .reprcrash .path .endswith ("mod.py" )
660674 assert repr .reprcrash .message == "ValueError: 0"
661675
@@ -746,8 +760,13 @@ def entry():
746760 for style in ("short" , "long" , "no" ):
747761 for showlocals in (True , False ):
748762 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 )
750765 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
751770
752771 def test_reprexcinfo_unicode (self ):
753772 from _pytest ._code .code import TerminalRepr
@@ -928,3 +947,70 @@ def i():
928947 assert tw .lines [14 ] == "E ValueError"
929948 assert tw .lines [15 ] == ""
930949 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