@@ -953,6 +953,148 @@ def __del__(self):
953953 pass
954954 self .assertEqual (e , (None , None , None ))
955955
956+ def test_raise_does_not_create_context_chain_cycle (self ):
957+ class A (Exception ):
958+ pass
959+ class B (Exception ):
960+ pass
961+ class C (Exception ):
962+ pass
963+
964+ # Create a context chain:
965+ # C -> B -> A
966+ # Then raise A in context of C.
967+ try :
968+ try :
969+ raise A
970+ except A as a_ :
971+ a = a_
972+ try :
973+ raise B
974+ except B as b_ :
975+ b = b_
976+ try :
977+ raise C
978+ except C as c_ :
979+ c = c_
980+ self .assertIsInstance (a , A )
981+ self .assertIsInstance (b , B )
982+ self .assertIsInstance (c , C )
983+ self .assertIsNone (a .__context__ )
984+ self .assertIs (b .__context__ , a )
985+ self .assertIs (c .__context__ , b )
986+ raise a
987+ except A as e :
988+ exc = e
989+
990+ # Expect A -> C -> B, without cycle
991+ self .assertIs (exc , a )
992+ self .assertIs (a .__context__ , c )
993+ self .assertIs (c .__context__ , b )
994+ self .assertIsNone (b .__context__ )
995+
996+ def test_no_hang_on_context_chain_cycle1 (self ):
997+ # See issue 25782. Cycle in context chain.
998+
999+ def cycle ():
1000+ try :
1001+ raise ValueError (1 )
1002+ except ValueError as ex :
1003+ ex .__context__ = ex
1004+ raise TypeError (2 )
1005+
1006+ try :
1007+ cycle ()
1008+ except Exception as e :
1009+ exc = e
1010+
1011+ self .assertIsInstance (exc , TypeError )
1012+ self .assertIsInstance (exc .__context__ , ValueError )
1013+ self .assertIs (exc .__context__ .__context__ , exc .__context__ )
1014+
1015+ def test_no_hang_on_context_chain_cycle2 (self ):
1016+ # See issue 25782. Cycle at head of context chain.
1017+
1018+ class A (Exception ):
1019+ pass
1020+ class B (Exception ):
1021+ pass
1022+ class C (Exception ):
1023+ pass
1024+
1025+ # Context cycle:
1026+ # +-----------+
1027+ # V |
1028+ # C --> B --> A
1029+ with self .assertRaises (C ) as cm :
1030+ try :
1031+ raise A ()
1032+ except A as _a :
1033+ a = _a
1034+ try :
1035+ raise B ()
1036+ except B as _b :
1037+ b = _b
1038+ try :
1039+ raise C ()
1040+ except C as _c :
1041+ c = _c
1042+ a .__context__ = c
1043+ raise c
1044+
1045+ self .assertIs (cm .exception , c )
1046+ # Verify the expected context chain cycle
1047+ self .assertIs (c .__context__ , b )
1048+ self .assertIs (b .__context__ , a )
1049+ self .assertIs (a .__context__ , c )
1050+
1051+ def test_no_hang_on_context_chain_cycle3 (self ):
1052+ # See issue 25782. Longer context chain with cycle.
1053+
1054+ class A (Exception ):
1055+ pass
1056+ class B (Exception ):
1057+ pass
1058+ class C (Exception ):
1059+ pass
1060+ class D (Exception ):
1061+ pass
1062+ class E (Exception ):
1063+ pass
1064+
1065+ # Context cycle:
1066+ # +-----------+
1067+ # V |
1068+ # E --> D --> C --> B --> A
1069+ with self .assertRaises (E ) as cm :
1070+ try :
1071+ raise A ()
1072+ except A as _a :
1073+ a = _a
1074+ try :
1075+ raise B ()
1076+ except B as _b :
1077+ b = _b
1078+ try :
1079+ raise C ()
1080+ except C as _c :
1081+ c = _c
1082+ a .__context__ = c
1083+ try :
1084+ raise D ()
1085+ except D as _d :
1086+ d = _d
1087+ e = E ()
1088+ raise e
1089+
1090+ self .assertIs (cm .exception , e )
1091+ # Verify the expected context chain cycle
1092+ self .assertIs (e .__context__ , d )
1093+ self .assertIs (d .__context__ , c )
1094+ self .assertIs (c .__context__ , b )
1095+ self .assertIs (b .__context__ , a )
1096+ self .assertIs (a .__context__ , c )
1097+
9561098 def test_unicode_change_attributes (self ):
9571099 # See issue 7309. This was a crasher.
9581100
0 commit comments