mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	[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 e9253ebf74)
			
			
This commit is contained in:
		
							parent
							
								
									3c9d1778ef
								
							
						
					
					
						commit
						973e2d3e29
					
				
					 5 changed files with 55 additions and 10 deletions
				
			
		| 
						 | 
					@ -1349,6 +1349,28 @@ def test_readonly_attributes(self):
 | 
				
			||||||
        with self.assertRaises(AttributeError):
 | 
					        with self.assertRaises(AttributeError):
 | 
				
			||||||
            buf.raw = x
 | 
					            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:
 | 
					class SizeofTest:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3932,6 +3954,28 @@ def test_issue35928(self):
 | 
				
			||||||
        f.write(res)
 | 
					        f.write(res)
 | 
				
			||||||
        self.assertEqual(res + f.readline(), 'foo\nbar\n')
 | 
					        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):
 | 
					class MemviewBytesIO(io.BytesIO):
 | 
				
			||||||
    '''A BytesIO object whose read method returns memoryviews
 | 
					    '''A BytesIO object whose read method returns memoryviews
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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.
 | 
				
			||||||
| 
						 | 
					@ -2530,8 +2530,7 @@ static PyMethodDef bufferedreader_methods[] = {
 | 
				
			||||||
    _IO__BUFFERED_TRUNCATE_METHODDEF
 | 
					    _IO__BUFFERED_TRUNCATE_METHODDEF
 | 
				
			||||||
    _IO__BUFFERED___SIZEOF___METHODDEF
 | 
					    _IO__BUFFERED___SIZEOF___METHODDEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
					    {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
				
			||||||
    {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
 | 
					 | 
				
			||||||
    {NULL, NULL}
 | 
					    {NULL, NULL}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2590,8 +2589,7 @@ static PyMethodDef bufferedwriter_methods[] = {
 | 
				
			||||||
    _IO__BUFFERED_TELL_METHODDEF
 | 
					    _IO__BUFFERED_TELL_METHODDEF
 | 
				
			||||||
    _IO__BUFFERED___SIZEOF___METHODDEF
 | 
					    _IO__BUFFERED___SIZEOF___METHODDEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
					    {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
				
			||||||
    {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
 | 
					 | 
				
			||||||
    {NULL, NULL}
 | 
					    {NULL, NULL}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2708,8 +2706,7 @@ static PyMethodDef bufferedrandom_methods[] = {
 | 
				
			||||||
    _IO_BUFFEREDWRITER_WRITE_METHODDEF
 | 
					    _IO_BUFFEREDWRITER_WRITE_METHODDEF
 | 
				
			||||||
    _IO__BUFFERED___SIZEOF___METHODDEF
 | 
					    _IO__BUFFERED___SIZEOF___METHODDEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
					    {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
				
			||||||
    {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
 | 
					 | 
				
			||||||
    {NULL, NULL}
 | 
					    {NULL, NULL}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1178,8 +1178,7 @@ static PyMethodDef fileio_methods[] = {
 | 
				
			||||||
    _IO_FILEIO_FILENO_METHODDEF
 | 
					    _IO_FILEIO_FILENO_METHODDEF
 | 
				
			||||||
    _IO_FILEIO_ISATTY_METHODDEF
 | 
					    _IO_FILEIO_ISATTY_METHODDEF
 | 
				
			||||||
    {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
 | 
					    {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
 | 
				
			||||||
    {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
					    {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
				
			||||||
    {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
 | 
					 | 
				
			||||||
    {NULL,           NULL}             /* sentinel */
 | 
					    {NULL,           NULL}             /* sentinel */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3350,8 +3350,7 @@ static PyMethodDef textiowrapper_methods[] = {
 | 
				
			||||||
    _IO_TEXTIOWRAPPER_TELL_METHODDEF
 | 
					    _IO_TEXTIOWRAPPER_TELL_METHODDEF
 | 
				
			||||||
    _IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF
 | 
					    _IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
					    {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS},
 | 
				
			||||||
    {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
 | 
					 | 
				
			||||||
    {NULL, NULL}
 | 
					    {NULL, NULL}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue