@@ -923,6 +923,148 @@ def __del__(self):
923923 pass
924924 self .assertEqual (e , (None , None , None ))
925925
926+ def test_raise_does_not_create_context_chain_cycle (self ):
927+ class A (Exception ):
928+ pass
929+ class B (Exception ):
930+ pass
931+ class C (Exception ):
932+ pass
933+
934+ # Create a context chain:
935+ # C -> B -> A
936+ # Then raise A in context of C.
937+ try :
938+ try :
939+ raise A
940+ except A as a_ :
941+ a = a_
942+ try :
943+ raise B
944+ except B as b_ :
945+ b = b_
946+ try :
947+ raise C
948+ except C as c_ :
949+ c = c_
950+ self .assertIsInstance (a , A )
951+ self .assertIsInstance (b , B )
952+ self .assertIsInstance (c , C )
953+ self .assertIsNone (a .__context__ )
954+ self .assertIs (b .__context__ , a )
955+ self .assertIs (c .__context__ , b )
956+ raise a
957+ except A as e :
958+ exc = e
959+
960+ # Expect A -> C -> B, without cycle
961+ self .assertIs (exc , a )
962+ self .assertIs (a .__context__ , c )
963+ self .assertIs (c .__context__ , b )
964+ self .assertIsNone (b .__context__ )
965+
966+ def test_no_hang_on_context_chain_cycle1 (self ):
967+ # See issue 25782. Cycle in context chain.
968+
969+ def cycle ():
970+ try :
971+ raise ValueError (1 )
972+ except ValueError as ex :
973+ ex .__context__ = ex
974+ raise TypeError (2 )
975+
976+ try :
977+ cycle ()
978+ except Exception as e :
979+ exc = e
980+
981+ self .assertIsInstance (exc , TypeError )
982+ self .assertIsInstance (exc .__context__ , ValueError )
983+ self .assertIs (exc .__context__ .__context__ , exc .__context__ )
984+
985+ def test_no_hang_on_context_chain_cycle2 (self ):
986+ # See issue 25782. Cycle at head of context chain.
987+
988+ class A (Exception ):
989+ pass
990+ class B (Exception ):
991+ pass
992+ class C (Exception ):
993+ pass
994+
995+ # Context cycle:
996+ # +-----------+
997+ # V |
998+ # C --> B --> A
999+ with self .assertRaises (C ) as cm :
1000+ try :
1001+ raise A ()
1002+ except A as _a :
1003+ a = _a
1004+ try :
1005+ raise B ()
1006+ except B as _b :
1007+ b = _b
1008+ try :
1009+ raise C ()
1010+ except C as _c :
1011+ c = _c
1012+ a .__context__ = c
1013+ raise c
1014+
1015+ self .assertIs (cm .exception , c )
1016+ # Verify the expected context chain cycle
1017+ self .assertIs (c .__context__ , b )
1018+ self .assertIs (b .__context__ , a )
1019+ self .assertIs (a .__context__ , c )
1020+
1021+ def test_no_hang_on_context_chain_cycle3 (self ):
1022+ # See issue 25782. Longer context chain with cycle.
1023+
1024+ class A (Exception ):
1025+ pass
1026+ class B (Exception ):
1027+ pass
1028+ class C (Exception ):
1029+ pass
1030+ class D (Exception ):
1031+ pass
1032+ class E (Exception ):
1033+ pass
1034+
1035+ # Context cycle:
1036+ # +-----------+
1037+ # V |
1038+ # E --> D --> C --> B --> A
1039+ with self .assertRaises (E ) as cm :
1040+ try :
1041+ raise A ()
1042+ except A as _a :
1043+ a = _a
1044+ try :
1045+ raise B ()
1046+ except B as _b :
1047+ b = _b
1048+ try :
1049+ raise C ()
1050+ except C as _c :
1051+ c = _c
1052+ a .__context__ = c
1053+ try :
1054+ raise D ()
1055+ except D as _d :
1056+ d = _d
1057+ e = E ()
1058+ raise e
1059+
1060+ self .assertIs (cm .exception , e )
1061+ # Verify the expected context chain cycle
1062+ self .assertIs (e .__context__ , d )
1063+ self .assertIs (d .__context__ , c )
1064+ self .assertIs (c .__context__ , b )
1065+ self .assertIs (b .__context__ , a )
1066+ self .assertIs (a .__context__ , c )
1067+
9261068 def test_unicode_change_attributes (self ):
9271069 # See issue 7309. This was a crasher.
9281070
0 commit comments