Skip to content

Commit 926170a

Browse files
committed
Remove special case for file-like objects without a readinto().
1 parent 5639f3c commit 926170a

2 files changed

Lines changed: 12 additions & 58 deletions

File tree

Lib/test/pickletester.py

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,6 @@ def tell(self):
7373
raise io.UnsupportedOperation
7474

7575

76-
class TrivialReadableIO:
77-
"""
78-
A readable file object that doesn't support readinto().
79-
"""
80-
def __init__(self, *args, **kwargs):
81-
self._bio = io.BytesIO(*args, **kwargs)
82-
83-
def read(self, n):
84-
return self._bio.read(n)
85-
86-
def readline(self, n=None):
87-
return self._bio.readline(n)
88-
89-
def getvalue(self):
90-
return self._bio.getvalue()
91-
92-
9376
# We can't very well test the extension registry without putting known stuff
9477
# in it, but we have to be careful to restore its original state. Code
9578
# should do this:
@@ -3399,22 +3382,6 @@ def test_unpickling_buffering_readline(self):
33993382
unpickler = self.unpickler_class(f)
34003383
self.assertEqual(unpickler.load(), data)
34013384

3402-
def test_unpickling_trivial_io(self):
3403-
# Check unpickling with an io class that doesn't have readinto()
3404-
sizes = [1, 16, 1000, 2**10]
3405-
data = [(b"x" * size, bytearray(b"x") * size) for size in sizes]
3406-
for proto in protocols:
3407-
with self.subTest(proto=proto):
3408-
bio = io.BytesIO()
3409-
pickler = self.pickler_class(bio, protocol=proto)
3410-
pickler.dump(data)
3411-
N = 5
3412-
f = TrivialReadableIO(bio.getvalue() * N)
3413-
unpickler = self.unpickler_class(f)
3414-
for i in range(N):
3415-
self.assertEqual(unpickler.load(), data)
3416-
self.assertRaises(EOFError, unpickler.load)
3417-
34183385

34193386
# Tests for dispatch_table attribute
34203387

Modules/_pickle.c

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,8 +1356,6 @@ _Unpickler_ReadInto(UnpicklerObject *self, char *buf, Py_ssize_t n)
13561356
{
13571357
assert(n != READ_WHOLE_LINE);
13581358

1359-
/* XXX add tests from ogrisel's use case */
1360-
13611359
/* Read from available buffer data, if any */
13621360
Py_ssize_t in_buffer = self->input_len - self->next_read_idx;
13631361
if (in_buffer > 0) {
@@ -1373,30 +1371,21 @@ _Unpickler_ReadInto(UnpicklerObject *self, char *buf, Py_ssize_t n)
13731371
}
13741372

13751373
/* Read from file */
1374+
if (!self->readinto)
1375+
return bad_readline();
13761376
if (_Unpickler_SkipConsumed(self) < 0)
13771377
return -1;
13781378

1379-
Py_ssize_t read_size;
1380-
1381-
if (self->readinto == NULL) {
1382-
/* Call read() and memcpy */
1383-
/* XXX do we want this fallback? pickle.py doesn't have it */
1384-
char *s;
1385-
read_size = _Unpickler_ReadImpl(self, &s, n);
1386-
if (read_size < 0) {
1387-
return -1;
1388-
}
1389-
assert(read_size == n);
1390-
memcpy(buf, s, n);
1391-
return n;
1392-
}
1393-
13941379
/* Call readinto() into user buffer */
13951380
PyObject *buf_obj = PyMemoryView_FromMemory(buf, n, PyBUF_WRITE);
1396-
if (buf_obj == NULL)
1381+
if (buf_obj == NULL) {
13971382
return -1;
1383+
}
13981384
PyObject *read_size_obj = _Pickle_FastCall(self->readinto, buf_obj);
1399-
read_size = PyLong_AsSsize_t(read_size_obj);
1385+
if (read_size_obj == NULL) {
1386+
return -1;
1387+
}
1388+
Py_ssize_t read_size = PyLong_AsSsize_t(read_size_obj);
14001389
Py_DECREF(read_size_obj);
14011390

14021391
if (read_size < 0) {
@@ -1614,19 +1603,17 @@ _Unpickler_SetInputStream(UnpicklerObject *self, PyObject *file)
16141603
_Py_IDENTIFIER(readinto);
16151604
_Py_IDENTIFIER(readline);
16161605

1617-
/* Both 'peek' and 'readline' are optional, for compatibility */
16181606
if (_PyObject_LookupAttrId(file, &PyId_peek, &self->peek) < 0) {
16191607
return -1;
16201608
}
1621-
if (_PyObject_LookupAttrId(file, &PyId_readinto, &self->readinto) < 0) {
1622-
return -1;
1623-
}
16241609
(void)_PyObject_LookupAttrId(file, &PyId_read, &self->read);
1610+
(void)_PyObject_LookupAttrId(file, &PyId_readinto, &self->readinto);
16251611
(void)_PyObject_LookupAttrId(file, &PyId_readline, &self->readline);
1626-
if (self->readline == NULL || self->read == NULL) {
1612+
if (!self->readline || !self->readinto || !self->read) {
16271613
if (!PyErr_Occurred()) {
16281614
PyErr_SetString(PyExc_TypeError,
1629-
"file must have 'read' and 'readline' attributes");
1615+
"file must have 'read', 'readinto' and "
1616+
"'readline' attributes");
16301617
}
16311618
Py_CLEAR(self->read);
16321619
Py_CLEAR(self->readinto);

0 commit comments

Comments
 (0)