Skip to content

Commit 0aaecb3

Browse files
[3.9] bpo-41052: Fix pickling heap types implemented in C with protocols 0 and 1 (GH-22870). (GH-22963)
(cherry picked from commit 8cd1dba)
1 parent af891a9 commit 0aaecb3

File tree

5 files changed

+25
-35
lines changed

5 files changed

+25
-35
lines changed

Lib/copyreg.py

+4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def _reconstructor(cls, base, state):
4848
return obj
4949

5050
_HEAPTYPE = 1<<9
51+
_new_type = type(int.__new__)
5152

5253
# Python code for object.__reduce_ex__ for protocols 0 and 1
5354

@@ -57,6 +58,9 @@ def _reduce_ex(self, proto):
5758
for base in cls.__mro__:
5859
if hasattr(base, '__flags__') and not base.__flags__ & _HEAPTYPE:
5960
break
61+
new = base.__new__
62+
if isinstance(new, _new_type) and new.__self__ is base:
63+
break
6064
else:
6165
base = object # not really reachable
6266
if base is object:

Lib/test/pickletester.py

+18
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,17 @@ def test_newobj_proxies(self):
19651965
self.assertEqual(B(x), B(y), detail)
19661966
self.assertEqual(x.__dict__, y.__dict__, detail)
19671967

1968+
def test_newobj_overridden_new(self):
1969+
# Test that Python class with C implemented __new__ is pickleable
1970+
for proto in protocols:
1971+
x = MyIntWithNew2(1)
1972+
x.foo = 42
1973+
s = self.dumps(x, proto)
1974+
y = self.loads(s)
1975+
self.assertIs(type(y), MyIntWithNew2)
1976+
self.assertEqual(int(y), 1)
1977+
self.assertEqual(y.foo, 42)
1978+
19681979
def test_newobj_not_class(self):
19691980
# Issue 24552
19701981
global SimpleNewObj
@@ -3085,6 +3096,13 @@ class MyFrozenSet(frozenset):
30853096
MyStr, MyUnicode,
30863097
MyTuple, MyList, MyDict, MySet, MyFrozenSet]
30873098

3099+
class MyIntWithNew(int):
3100+
def __new__(cls, value):
3101+
raise AssertionError
3102+
3103+
class MyIntWithNew2(MyIntWithNew):
3104+
__new__ = int.__new__
3105+
30883106

30893107
class SlotList(MyList):
30903108
__slots__ = ["foo"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Pickling heap types implemented in C with protocols 0 and 1 raises now an
2+
error instead of producing incorrect data.

Modules/_randommodule.c

-17
Original file line numberDiff line numberDiff line change
@@ -537,29 +537,12 @@ random_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
537537
}
538538

539539

540-
/*[clinic input]
541-
542-
_random.Random.__reduce__
543-
544-
[clinic start generated code]*/
545-
546-
static PyObject *
547-
_random_Random___reduce___impl(RandomObject *self)
548-
/*[clinic end generated code: output=ddea0dcdb60ffd6d input=bd38ec35fd157e0f]*/
549-
{
550-
PyErr_Format(PyExc_TypeError,
551-
"cannot pickle %s object",
552-
Py_TYPE(self)->tp_name);
553-
return NULL;
554-
}
555-
556540
static PyMethodDef random_methods[] = {
557541
_RANDOM_RANDOM_RANDOM_METHODDEF
558542
_RANDOM_RANDOM_SEED_METHODDEF
559543
_RANDOM_RANDOM_GETSTATE_METHODDEF
560544
_RANDOM_RANDOM_SETSTATE_METHODDEF
561545
_RANDOM_RANDOM_GETRANDBITS_METHODDEF
562-
_RANDOM_RANDOM___REDUCE___METHODDEF
563546
{NULL, NULL} /* sentinel */
564547
};
565548

Modules/clinic/_randommodule.c.h

+1-18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)