Skip to content

Commit 8cd1dba

Browse files
bpo-41052: Fix pickling heap types implemented in C with protocols 0 and 1 (GH-22870)
1 parent 473db47 commit 8cd1dba

File tree

9 files changed

+27
-167
lines changed

9 files changed

+27
-167
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
@@ -1969,6 +1969,17 @@ def test_newobj_proxies(self):
19691969
self.assertEqual(B(x), B(y), detail)
19701970
self.assertEqual(x.__dict__, y.__dict__, detail)
19711971

1972+
def test_newobj_overridden_new(self):
1973+
# Test that Python class with C implemented __new__ is pickleable
1974+
for proto in protocols:
1975+
x = MyIntWithNew2(1)
1976+
x.foo = 42
1977+
s = self.dumps(x, proto)
1978+
y = self.loads(s)
1979+
self.assertIs(type(y), MyIntWithNew2)
1980+
self.assertEqual(int(y), 1)
1981+
self.assertEqual(y.foo, 42)
1982+
19721983
def test_newobj_not_class(self):
19731984
# Issue 24552
19741985
global SimpleNewObj
@@ -3089,6 +3100,13 @@ class MyFrozenSet(frozenset):
30893100
MyStr, MyUnicode,
30903101
MyTuple, MyList, MyDict, MySet, MyFrozenSet]
30913102

3103+
class MyIntWithNew(int):
3104+
def __new__(cls, value):
3105+
raise AssertionError
3106+
3107+
class MyIntWithNew2(MyIntWithNew):
3108+
__new__ = int.__new__
3109+
30923110

30933111
class SlotList(MyList):
30943112
__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/_bz2module.c

-32
Original file line numberDiff line numberDiff line change
@@ -272,21 +272,6 @@ _bz2_BZ2Compressor_flush_impl(BZ2Compressor *self)
272272
return result;
273273
}
274274

275-
/*[clinic input]
276-
_bz2.BZ2Compressor.__reduce__
277-
278-
[clinic start generated code]*/
279-
280-
static PyObject *
281-
_bz2_BZ2Compressor___reduce___impl(BZ2Compressor *self)
282-
/*[clinic end generated code: output=d13db66ae043e141 input=e09bccef0e6731b2]*/
283-
{
284-
PyErr_Format(PyExc_TypeError,
285-
"cannot pickle %s object",
286-
Py_TYPE(self)->tp_name);
287-
return NULL;
288-
}
289-
290275
static void*
291276
BZ2_Malloc(void* ctx, int items, int size)
292277
{
@@ -399,7 +384,6 @@ BZ2Compressor_traverse(BZ2Compressor *self, visitproc visit, void *arg)
399384
static PyMethodDef BZ2Compressor_methods[] = {
400385
_BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF
401386
_BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF
402-
_BZ2_BZ2COMPRESSOR___REDUCE___METHODDEF
403387
{NULL}
404388
};
405389

@@ -642,21 +626,6 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data,
642626
return result;
643627
}
644628

645-
/*[clinic input]
646-
_bz2.BZ2Decompressor.__reduce__
647-
648-
[clinic start generated code]*/
649-
650-
static PyObject *
651-
_bz2_BZ2Decompressor___reduce___impl(BZ2Decompressor *self)
652-
/*[clinic end generated code: output=f6a40650813f482e input=8db9175a609fdd43]*/
653-
{
654-
PyErr_Format(PyExc_TypeError,
655-
"cannot pickle %s object",
656-
Py_TYPE(self)->tp_name);
657-
return NULL;
658-
}
659-
660629
/* Argument Clinic is not used since the Argument Clinic always want to
661630
check the type which would be wrong here */
662631
static int
@@ -746,7 +715,6 @@ BZ2Decompressor_traverse(BZ2Decompressor *self, visitproc visit, void *arg)
746715

747716
static PyMethodDef BZ2Decompressor_methods[] = {
748717
_BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF
749-
_BZ2_BZ2DECOMPRESSOR___REDUCE___METHODDEF
750718
{NULL}
751719
};
752720

Modules/_lzmamodule.c

-30
Original file line numberDiff line numberDiff line change
@@ -825,24 +825,9 @@ Compressor_dealloc(Compressor *self)
825825
Py_DECREF(tp);
826826
}
827827

828-
/*[clinic input]
829-
_lzma.LZMACompressor.__reduce__
830-
[clinic start generated code]*/
831-
832-
static PyObject *
833-
_lzma_LZMACompressor___reduce___impl(Compressor *self)
834-
/*[clinic end generated code: output=b49a0538d1cad752 input=6be52aba16b513c1]*/
835-
{
836-
PyErr_Format(PyExc_TypeError,
837-
"cannot pickle %s object",
838-
Py_TYPE(self)->tp_name);
839-
return NULL;
840-
}
841-
842828
static PyMethodDef Compressor_methods[] = {
843829
_LZMA_LZMACOMPRESSOR_COMPRESS_METHODDEF
844830
_LZMA_LZMACOMPRESSOR_FLUSH_METHODDEF
845-
_LZMA_LZMACOMPRESSOR___REDUCE___METHODDEF
846831
{NULL}
847832
};
848833

@@ -1309,23 +1294,8 @@ Decompressor_traverse(Decompressor *self, visitproc visit, void *arg)
13091294
return 0;
13101295
}
13111296

1312-
/*[clinic input]
1313-
_lzma.LZMADecompressor.__reduce__
1314-
[clinic start generated code]*/
1315-
1316-
static PyObject *
1317-
_lzma_LZMADecompressor___reduce___impl(Decompressor *self)
1318-
/*[clinic end generated code: output=2611fff0104a9c30 input=b9882e030aecd9a5]*/
1319-
{
1320-
PyErr_Format(PyExc_TypeError,
1321-
"cannot pickle %s object",
1322-
Py_TYPE(self)->tp_name);
1323-
return NULL;
1324-
}
1325-
13261297
static PyMethodDef Decompressor_methods[] = {
13271298
_LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF
1328-
_LZMA_LZMADECOMPRESSOR___REDUCE___METHODDEF
13291299
{NULL}
13301300
};
13311301

Modules/_randommodule.c

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

538538

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

Modules/clinic/_bz2module.c.h

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

Modules/clinic/_lzmamodule.c.h

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

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)