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
@@ -385,6 +386,8 @@ def test_repr_source_not_existing(self):
385
386
excinfo = _pytest ._code .ExceptionInfo ()
386
387
repr = pr .repr_excinfo (excinfo )
387
388
assert repr .reprtraceback .reprentries [1 ].lines [0 ] == "> ???"
389
+ if py .std .sys .version_info [0 ] >= 3 :
390
+ assert repr .chain [0 ][0 ].reprentries [1 ].lines [0 ] == "> ???"
388
391
389
392
def test_repr_many_line_source_not_existing (self ):
390
393
pr = FormattedExcinfo ()
@@ -398,6 +401,8 @@ def test_repr_many_line_source_not_existing(self):
398
401
excinfo = _pytest ._code .ExceptionInfo ()
399
402
repr = pr .repr_excinfo (excinfo )
400
403
assert repr .reprtraceback .reprentries [1 ].lines [0 ] == "> ???"
404
+ if py .std .sys .version_info [0 ] >= 3 :
405
+ assert repr .chain [0 ][0 ].reprentries [1 ].lines [0 ] == "> ???"
401
406
402
407
def test_repr_source_failing_fullsource (self ):
403
408
pr = FormattedExcinfo ()
@@ -430,6 +435,7 @@ class Traceback(_pytest._code.Traceback):
430
435
431
436
class FakeExcinfo (_pytest ._code .ExceptionInfo ):
432
437
typename = "Foo"
438
+ value = Exception ()
433
439
def __init__ (self ):
434
440
pass
435
441
@@ -447,10 +453,15 @@ class FakeRawTB(object):
447
453
fail = IOError () # noqa
448
454
repr = pr .repr_excinfo (excinfo )
449
455
assert repr .reprtraceback .reprentries [0 ].lines [0 ] == "> ???"
456
+ if py .std .sys .version_info [0 ] >= 3 :
457
+ assert repr .chain [0 ][0 ].reprentries [0 ].lines [0 ] == "> ???"
458
+
450
459
451
460
fail = py .error .ENOENT # noqa
452
461
repr = pr .repr_excinfo (excinfo )
453
462
assert repr .reprtraceback .reprentries [0 ].lines [0 ] == "> ???"
463
+ if py .std .sys .version_info [0 ] >= 3 :
464
+ assert repr .chain [0 ][0 ].reprentries [0 ].lines [0 ] == "> ???"
454
465
455
466
456
467
def test_repr_local (self ):
@@ -637,6 +648,9 @@ def entry():
637
648
repr = p .repr_excinfo (excinfo )
638
649
assert repr .reprtraceback
639
650
assert len (repr .reprtraceback .reprentries ) == len (reprtb .reprentries )
651
+ if py .std .sys .version_info [0 ] >= 3 :
652
+ assert repr .chain [0 ][0 ]
653
+ assert len (repr .chain [0 ][0 ].reprentries ) == len (reprtb .reprentries )
640
654
assert repr .reprcrash .path .endswith ("mod.py" )
641
655
assert repr .reprcrash .message == "ValueError: 0"
642
656
@@ -727,8 +741,13 @@ def entry():
727
741
for style in ("short" , "long" , "no" ):
728
742
for showlocals in (True , False ):
729
743
repr = excinfo .getrepr (style = style , showlocals = showlocals )
730
- assert isinstance (repr , ReprExceptionInfo )
744
+ if py .std .sys .version_info [0 ] < 3 :
745
+ assert isinstance (repr , ReprExceptionInfo )
731
746
assert repr .reprtraceback .style == style
747
+ if py .std .sys .version_info [0 ] >= 3 :
748
+ assert isinstance (repr , ExceptionChainRepr )
749
+ for repr in repr .chain :
750
+ assert repr [0 ].style == style
732
751
733
752
def test_reprexcinfo_unicode (self ):
734
753
from _pytest ._code .code import TerminalRepr
@@ -909,3 +928,70 @@ def i():
909
928
assert tw .lines [14 ] == "E ValueError"
910
929
assert tw .lines [15 ] == ""
911
930
assert tw .lines [16 ].endswith ("mod.py:9: ValueError" )
931
+
932
+ @pytest .mark .skipif ("sys.version_info[0] < 3" )
933
+ def test_exc_chain_repr (self , importasmod ):
934
+ mod = importasmod ("""
935
+ class Err(Exception):
936
+ pass
937
+ def f():
938
+ try:
939
+ g()
940
+ except Exception as e:
941
+ raise Err() from e
942
+ finally:
943
+ h()
944
+ def g():
945
+ raise ValueError()
946
+
947
+ def h():
948
+ raise AttributeError()
949
+ """ )
950
+ excinfo = pytest .raises (AttributeError , mod .f )
951
+ r = excinfo .getrepr (style = "long" )
952
+ tw = TWMock ()
953
+ r .toterminal (tw )
954
+ for line in tw .lines : print (line )
955
+ assert tw .lines [0 ] == ""
956
+ assert tw .lines [1 ] == " def f():"
957
+ assert tw .lines [2 ] == " try:"
958
+ assert tw .lines [3 ] == "> g()"
959
+ assert tw .lines [4 ] == ""
960
+ assert tw .lines [5 ].endswith ("mod.py:6: " )
961
+ assert tw .lines [6 ] == ("_ " , None )
962
+ assert tw .lines [7 ] == ""
963
+ assert tw .lines [8 ] == " def g():"
964
+ assert tw .lines [9 ] == "> raise ValueError()"
965
+ assert tw .lines [10 ] == "E ValueError"
966
+ assert tw .lines [11 ] == ""
967
+ assert tw .lines [12 ].endswith ("mod.py:12: ValueError" )
968
+ assert tw .lines [13 ] == ""
969
+ assert tw .lines [14 ] == "The above exception was the direct cause of the following exception:"
970
+ assert tw .lines [15 ] == ""
971
+ assert tw .lines [16 ] == " def f():"
972
+ assert tw .lines [17 ] == " try:"
973
+ assert tw .lines [18 ] == " g()"
974
+ assert tw .lines [19 ] == " except Exception as e:"
975
+ assert tw .lines [20 ] == "> raise Err() from e"
976
+ assert tw .lines [21 ] == "E test_exc_chain_repr0.mod.Err"
977
+ assert tw .lines [22 ] == ""
978
+ assert tw .lines [23 ].endswith ("mod.py:8: Err" )
979
+ assert tw .lines [24 ] == ""
980
+ assert tw .lines [25 ] == "During handling of the above exception, another exception occurred:"
981
+ assert tw .lines [26 ] == ""
982
+ assert tw .lines [27 ] == " def f():"
983
+ assert tw .lines [28 ] == " try:"
984
+ assert tw .lines [29 ] == " g()"
985
+ assert tw .lines [30 ] == " except Exception as e:"
986
+ assert tw .lines [31 ] == " raise Err() from e"
987
+ assert tw .lines [32 ] == " finally:"
988
+ assert tw .lines [33 ] == "> h()"
989
+ assert tw .lines [34 ] == ""
990
+ assert tw .lines [35 ].endswith ("mod.py:10: " )
991
+ assert tw .lines [36 ] == ('_ ' , None )
992
+ assert tw .lines [37 ] == ""
993
+ assert tw .lines [38 ] == " def h():"
994
+ assert tw .lines [39 ] == "> raise AttributeError()"
995
+ assert tw .lines [40 ] == "E AttributeError"
996
+ assert tw .lines [41 ] == ""
997
+ assert tw .lines [42 ].endswith ("mod.py:15: AttributeError" )
0 commit comments