@@ -953,6 +953,148 @@ def __del__(self):
953
953
pass
954
954
self .assertEqual (e , (None , None , None ))
955
955
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
+
956
1098
def test_unicode_change_attributes (self ):
957
1099
# See issue 7309. This was a crasher.
958
1100
0 commit comments