mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
Issue #22783: Pickling now uses the NEWOBJ opcode instead of the NEWOBJ_EX
opcode if possible.
This commit is contained in:
parent
01bdd9a980
commit
707b5ccde5
5 changed files with 150 additions and 141 deletions
|
@ -1153,16 +1153,62 @@ class AbstractPickleTests(unittest.TestCase):
|
|||
self.assertGreaterEqual(num_additems, 2)
|
||||
|
||||
def test_simple_newobj(self):
|
||||
x = object.__new__(SimpleNewObj) # avoid __init__
|
||||
x = SimpleNewObj.__new__(SimpleNewObj, 0xface) # avoid __init__
|
||||
x.abc = 666
|
||||
for proto in protocols:
|
||||
s = self.dumps(x, proto)
|
||||
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s),
|
||||
2 <= proto < 4)
|
||||
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ_EX, s),
|
||||
proto >= 4)
|
||||
y = self.loads(s) # will raise TypeError if __init__ called
|
||||
self.assert_is_copy(x, y)
|
||||
with self.subTest(proto=proto):
|
||||
s = self.dumps(x, proto)
|
||||
if proto < 1:
|
||||
self.assertIn(b'\nL64206', s) # LONG
|
||||
else:
|
||||
self.assertIn(b'M\xce\xfa', s) # BININT2
|
||||
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s),
|
||||
2 <= proto)
|
||||
self.assertFalse(opcode_in_pickle(pickle.NEWOBJ_EX, s))
|
||||
y = self.loads(s) # will raise TypeError if __init__ called
|
||||
self.assert_is_copy(x, y)
|
||||
|
||||
def test_complex_newobj(self):
|
||||
x = ComplexNewObj.__new__(ComplexNewObj, 0xface) # avoid __init__
|
||||
x.abc = 666
|
||||
for proto in protocols:
|
||||
with self.subTest(proto=proto):
|
||||
s = self.dumps(x, proto)
|
||||
if proto < 1:
|
||||
self.assertIn(b'\nL64206', s) # LONG
|
||||
elif proto < 2:
|
||||
self.assertIn(b'M\xce\xfa', s) # BININT2
|
||||
elif proto < 4:
|
||||
self.assertIn(b'X\x04\x00\x00\x00FACE', s) # BINUNICODE
|
||||
else:
|
||||
self.assertIn(b'\x8c\x04FACE', s) # SHORT_BINUNICODE
|
||||
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s),
|
||||
2 <= proto)
|
||||
self.assertFalse(opcode_in_pickle(pickle.NEWOBJ_EX, s))
|
||||
y = self.loads(s) # will raise TypeError if __init__ called
|
||||
self.assert_is_copy(x, y)
|
||||
|
||||
def test_complex_newobj_ex(self):
|
||||
x = ComplexNewObjEx.__new__(ComplexNewObjEx, 0xface) # avoid __init__
|
||||
x.abc = 666
|
||||
for proto in protocols:
|
||||
with self.subTest(proto=proto):
|
||||
if 2 <= proto < 4:
|
||||
self.assertRaises(ValueError, self.dumps, x, proto)
|
||||
continue
|
||||
s = self.dumps(x, proto)
|
||||
if proto < 1:
|
||||
self.assertIn(b'\nL64206', s) # LONG
|
||||
elif proto < 2:
|
||||
self.assertIn(b'M\xce\xfa', s) # BININT2
|
||||
else:
|
||||
assert proto >= 4
|
||||
self.assertIn(b'\x8c\x04FACE', s) # SHORT_BINUNICODE
|
||||
self.assertFalse(opcode_in_pickle(pickle.NEWOBJ, s))
|
||||
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ_EX, s),
|
||||
4 <= proto)
|
||||
y = self.loads(s) # will raise TypeError if __init__ called
|
||||
self.assert_is_copy(x, y)
|
||||
|
||||
def test_newobj_list_slots(self):
|
||||
x = SlotList([1, 2, 3])
|
||||
|
@ -1891,12 +1937,20 @@ myclasses = [MyInt, MyFloat,
|
|||
class SlotList(MyList):
|
||||
__slots__ = ["foo"]
|
||||
|
||||
class SimpleNewObj(object):
|
||||
def __init__(self, a, b, c):
|
||||
class SimpleNewObj(int):
|
||||
def __init__(self, *args, **kwargs):
|
||||
# raise an error, to make sure this isn't called
|
||||
raise TypeError("SimpleNewObj.__init__() didn't expect to get called")
|
||||
def __eq__(self, other):
|
||||
return self.__dict__ == other.__dict__
|
||||
return int(self) == int(other) and self.__dict__ == other.__dict__
|
||||
|
||||
class ComplexNewObj(SimpleNewObj):
|
||||
def __getnewargs__(self):
|
||||
return ('%X' % self, 16)
|
||||
|
||||
class ComplexNewObjEx(SimpleNewObj):
|
||||
def __getnewargs_ex__(self):
|
||||
return ('%X' % self,), {'base': 16}
|
||||
|
||||
class BadGetattr:
|
||||
def __getattr__(self, key):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue