https://github.com/python/cpython/commit/973e2d3e29d4994bf01683e607d2a448d3d49f4f
commit: 973e2d3e29d4994bf01683e607d2a448d3d49f4f
branch: 3.13
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2025-05-04T16:04:09Z
summary:
[3.13] gh-122559: Synchronize C and Python implementation of the io module
about pickling (GH-122628) (GH-133381)
In the C implementation, remove __reduce__ and __reduce_ex__ methods
that always raise TypeError and restore __getstate__ methods that always
raise TypeErrori.
This restores fine details of the pre-3.12 behavior and unifies
both implementations.
(cherry picked from commit e9253ebf74433de5ae6d7f1bce693a3a1173b3b1)
files:
A Misc/NEWS.d/next/Library/2024-08-02-20-01-36.gh-issue-122559.2JlJr3.rst
M Lib/test/test_io.py
M Modules/_io/bufferedio.c
M Modules/_io/fileio.c
M Modules/_io/textio.c
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 112495512e192c..4f06fd9db0322f 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -1349,6 +1349,28 @@ def test_readonly_attributes(self):
with self.assertRaises(AttributeError):
buf.raw = x
+ def test_pickling_subclass(self):
+ global MyBufferedIO
+ class MyBufferedIO(self.tp):
+ def __init__(self, raw, tag):
+ super().__init__(raw)
+ self.tag = tag
+ def __getstate__(self):
+ return self.tag, self.raw.getvalue()
+ def __setstate__(slf, state):
+ tag, value = state
+ slf.__init__(self.BytesIO(value), tag)
+
+ raw = self.BytesIO(b'data')
+ buf = MyBufferedIO(raw, tag='ham')
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(protocol=proto):
+ pickled = pickle.dumps(buf, proto)
+ newbuf = pickle.loads(pickled)
+ self.assertEqual(newbuf.raw.getvalue(), b'data')
+ self.assertEqual(newbuf.tag, 'ham')
+ del MyBufferedIO
+
class SizeofTest:
@@ -3932,6 +3954,28 @@ def test_issue35928(self):
f.write(res)
self.assertEqual(res + f.readline(), 'foo\nbar\n')
+ def test_pickling_subclass(self):
+ global MyTextIO
+ class MyTextIO(self.TextIOWrapper):
+ def __init__(self, raw, tag):
+ super().__init__(raw)
+ self.tag = tag
+ def __getstate__(self):
+ return self.tag, self.buffer.getvalue()
+ def __setstate__(slf, state):
+ tag, value = state
+ slf.__init__(self.BytesIO(value), tag)
+
+ raw = self.BytesIO(b'data')
+ txt = MyTextIO(raw, 'ham')
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(protocol=proto):
+ pickled = pickle.dumps(txt, proto)
+ newtxt = pickle.loads(pickled)
+ self.assertEqual(newtxt.buffer.getvalue(), b'data')
+ self.assertEqual(newtxt.tag, 'ham')
+ del MyTextIO
+
class MemviewBytesIO(io.BytesIO):
'''A BytesIO object whose read method returns memoryviews
diff --git
a/Misc/NEWS.d/next/Library/2024-08-02-20-01-36.gh-issue-122559.2JlJr3.rst
b/Misc/NEWS.d/next/Library/2024-08-02-20-01-36.gh-issue-122559.2JlJr3.rst
new file mode 100644
index 00000000000000..4ef9daa1bac26f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-08-02-20-01-36.gh-issue-122559.2JlJr3.rst
@@ -0,0 +1,6 @@
+Remove :meth:`!__reduce__` and :meth:`!__reduce_ex__` methods that always
+raise :exc:`TypeError` in the C implementation of :class:`io.FileIO`,
+:class:`io.BufferedReader`, :class:`io.BufferedWriter` and
+:class:`io.BufferedRandom` and replace them with default
+:meth:`!__getstate__` methods that raise :exc:`!TypeError`.
+This restores fine details of behavior of Python 3.11 and older versions.
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index e45323c93a17ef..050878c6da6ec3 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -2530,8 +2530,7 @@ static PyMethodDef bufferedreader_methods[] = {
_IO__BUFFERED_TRUNCATE_METHODDEF
_IO__BUFFERED___SIZEOF___METHODDEF
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL}
};
@@ -2590,8 +2589,7 @@ static PyMethodDef bufferedwriter_methods[] = {
_IO__BUFFERED_TELL_METHODDEF
_IO__BUFFERED___SIZEOF___METHODDEF
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL}
};
@@ -2708,8 +2706,7 @@ static PyMethodDef bufferedrandom_methods[] = {
_IO_BUFFEREDWRITER_WRITE_METHODDEF
_IO__BUFFERED___SIZEOF___METHODDEF
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL}
};
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index b5129ffcbffdcf..545eb4acf9b10e 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -1178,8 +1178,7 @@ static PyMethodDef fileio_methods[] = {
_IO_FILEIO_FILENO_METHODDEF
_IO_FILEIO_ISATTY_METHODDEF
{"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index c162d8106ec1fd..e10689d05a8400 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -3350,8 +3350,7 @@ static PyMethodDef textiowrapper_methods[] = {
_IO_TEXTIOWRAPPER_TELL_METHODDEF
_IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF
- {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
- {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
+ {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
{NULL, NULL}
};
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]