[3.9] bpo-41052: Fix pickling heap types implemented in C with protocols 0 and 1 (GH-22870). (GH-22963)
(cherry picked from commit 8cd1dbae32d9303caac3a473d3332f17bc98c921)
diff --git a/Lib/copyreg.py b/Lib/copyreg.py
index dfc463c..7ab8c12 100644
--- a/Lib/copyreg.py
+++ b/Lib/copyreg.py
@@ -48,6 +48,7 @@
return obj
_HEAPTYPE = 1<<9
+_new_type = type(int.__new__)
# Python code for object.__reduce_ex__ for protocols 0 and 1
@@ -57,6 +58,9 @@
for base in cls.__mro__:
if hasattr(base, '__flags__') and not base.__flags__ & _HEAPTYPE:
break
+ new = base.__new__
+ if isinstance(new, _new_type) and new.__self__ is base:
+ break
else:
base = object # not really reachable
if base is object:
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index 94d42c4..3d54617 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -1965,6 +1965,17 @@
self.assertEqual(B(x), B(y), detail)
self.assertEqual(x.__dict__, y.__dict__, detail)
+ def test_newobj_overridden_new(self):
+ # Test that Python class with C implemented __new__ is pickleable
+ for proto in protocols:
+ x = MyIntWithNew2(1)
+ x.foo = 42
+ s = self.dumps(x, proto)
+ y = self.loads(s)
+ self.assertIs(type(y), MyIntWithNew2)
+ self.assertEqual(int(y), 1)
+ self.assertEqual(y.foo, 42)
+
def test_newobj_not_class(self):
# Issue 24552
global SimpleNewObj
@@ -3085,6 +3096,13 @@
MyStr, MyUnicode,
MyTuple, MyList, MyDict, MySet, MyFrozenSet]
+class MyIntWithNew(int):
+ def __new__(cls, value):
+ raise AssertionError
+
+class MyIntWithNew2(MyIntWithNew):
+ __new__ = int.__new__
+
class SlotList(MyList):
__slots__ = ["foo"]