@@ -1214,6 +1214,29 @@ def test_negative_32b_binput(self):
12141214 dumped = b'\x80 \x03 X\x01 \x00 \x00 \x00 ar\xff \xff \xff \xff .'
12151215 self .assertRaises (ValueError , self .loads , dumped )
12161216
1217+ def _check_pickling_with_opcode (self , obj , opcode , proto ):
1218+ pickled = self .dumps (obj , proto )
1219+ self .assertTrue (opcode_in_pickle (opcode , pickled ))
1220+ unpickled = self .loads (pickled )
1221+ self .assertEqual (obj , unpickled )
1222+
1223+ def test_appends_on_non_lists (self ):
1224+ # Issue #17720
1225+ obj = REX_six ([1 , 2 , 3 ])
1226+ for proto in protocols :
1227+ if proto == 0 :
1228+ self ._check_pickling_with_opcode (obj , pickle .APPEND , proto )
1229+ else :
1230+ self ._check_pickling_with_opcode (obj , pickle .APPENDS , proto )
1231+
1232+ def test_setitems_on_non_dicts (self ):
1233+ obj = REX_seven ({1 : - 1 , 2 : - 2 , 3 : - 3 })
1234+ for proto in protocols :
1235+ if proto == 0 :
1236+ self ._check_pickling_with_opcode (obj , pickle .SETITEM , proto )
1237+ else :
1238+ self ._check_pickling_with_opcode (obj , pickle .SETITEMS , proto )
1239+
12171240
12181241class BigmemPickleTests (unittest .TestCase ):
12191242
@@ -1299,18 +1322,18 @@ def test_huge_str_64b(self, size):
12991322# Test classes for reduce_ex
13001323
13011324class REX_one (object ):
1325+ """No __reduce_ex__ here, but inheriting it from object"""
13021326 _reduce_called = 0
13031327 def __reduce__ (self ):
13041328 self ._reduce_called = 1
13051329 return REX_one , ()
1306- # No __reduce_ex__ here, but inheriting it from object
13071330
13081331class REX_two (object ):
1332+ """No __reduce__ here, but inheriting it from object"""
13091333 _proto = None
13101334 def __reduce_ex__ (self , proto ):
13111335 self ._proto = proto
13121336 return REX_two , ()
1313- # No __reduce__ here, but inheriting it from object
13141337
13151338class REX_three (object ):
13161339 _proto = None
@@ -1321,18 +1344,45 @@ def __reduce__(self):
13211344 raise TestFailed ("This __reduce__ shouldn't be called" )
13221345
13231346class REX_four (object ):
1347+ """Calling base class method should succeed"""
13241348 _proto = None
13251349 def __reduce_ex__ (self , proto ):
13261350 self ._proto = proto
13271351 return object .__reduce_ex__ (self , proto )
1328- # Calling base class method should succeed
13291352
13301353class REX_five (object ):
1354+ """This one used to fail with infinite recursion"""
13311355 _reduce_called = 0
13321356 def __reduce__ (self ):
13331357 self ._reduce_called = 1
13341358 return object .__reduce__ (self )
1335- # This one used to fail with infinite recursion
1359+
1360+ class REX_six (object ):
1361+ """This class is used to check the 4th argument (list iterator) of the reduce
1362+ protocol.
1363+ """
1364+ def __init__ (self , items = None ):
1365+ self .items = items if items is not None else []
1366+ def __eq__ (self , other ):
1367+ return type (self ) is type (other ) and self .items == self .items
1368+ def append (self , item ):
1369+ self .items .append (item )
1370+ def __reduce__ (self ):
1371+ return type (self ), (), None , iter (self .items ), None
1372+
1373+ class REX_seven (object ):
1374+ """This class is used to check the 5th argument (dict iterator) of the reduce
1375+ protocol.
1376+ """
1377+ def __init__ (self , table = None ):
1378+ self .table = table if table is not None else {}
1379+ def __eq__ (self , other ):
1380+ return type (self ) is type (other ) and self .table == self .table
1381+ def __setitem__ (self , key , value ):
1382+ self .table [key ] = value
1383+ def __reduce__ (self ):
1384+ return type (self ), (), None , None , iter (self .table .items ())
1385+
13361386
13371387# Test classes for newobj
13381388
0 commit comments