mirror of
https://github.com/python/cpython.git
synced 2025-07-29 14:15:07 +00:00
accept None as the same as having passed no argument in file types #7349
This is for consistency with imitation file objects like StringIO and BytesIO. This commit also adds a few tests, where they were lacking for concerned methods.
This commit is contained in:
parent
e304852e21
commit
ddd392cbb9
9 changed files with 77 additions and 29 deletions
|
@ -71,6 +71,15 @@ class AutoFileTests(unittest.TestCase):
|
||||||
n = self.f.readinto(a)
|
n = self.f.readinto(a)
|
||||||
self.assertEquals(array(b'b', [1, 2]), a[:n])
|
self.assertEquals(array(b'b', [1, 2]), a[:n])
|
||||||
|
|
||||||
|
def test_none_args(self):
|
||||||
|
self.f.write(b"hi\nbye\nabc")
|
||||||
|
self.f.close()
|
||||||
|
self.f = _FileIO(TESTFN, 'r')
|
||||||
|
self.assertEqual(self.f.read(None), b"hi\nbye\nabc")
|
||||||
|
self.f.seek(0)
|
||||||
|
self.assertEqual(self.f.readline(None), b"hi\n")
|
||||||
|
self.assertEqual(self.f.readlines(None), [b"bye\n", b"abc"])
|
||||||
|
|
||||||
def testRepr(self):
|
def testRepr(self):
|
||||||
self.assertEquals(repr(self.f), "<_io.FileIO name=%r mode='%s'>"
|
self.assertEquals(repr(self.f), "<_io.FileIO name=%r mode='%s'>"
|
||||||
% (self.f.name, self.f.mode))
|
% (self.f.name, self.f.mode))
|
||||||
|
|
|
@ -341,7 +341,7 @@ class IOTest(unittest.TestCase):
|
||||||
self.assertEqual(f.readline(2), b"xy")
|
self.assertEqual(f.readline(2), b"xy")
|
||||||
self.assertEqual(f.readline(4), b"zzy\n")
|
self.assertEqual(f.readline(4), b"zzy\n")
|
||||||
self.assertEqual(f.readline(), b"foo\x00bar\n")
|
self.assertEqual(f.readline(), b"foo\x00bar\n")
|
||||||
self.assertEqual(f.readline(), b"another line")
|
self.assertEqual(f.readline(None), b"another line")
|
||||||
self.assertRaises(TypeError, f.readline, 5.3)
|
self.assertRaises(TypeError, f.readline, 5.3)
|
||||||
with self.open(support.TESTFN, "r") as f:
|
with self.open(support.TESTFN, "r") as f:
|
||||||
self.assertRaises(TypeError, f.readline, 5.3)
|
self.assertRaises(TypeError, f.readline, 5.3)
|
||||||
|
@ -654,9 +654,10 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
|
||||||
self.assertEquals(b"abc", bufio.read())
|
self.assertEquals(b"abc", bufio.read())
|
||||||
|
|
||||||
def test_read(self):
|
def test_read(self):
|
||||||
rawio = self.MockRawIO((b"abc", b"d", b"efg"))
|
for arg in (None, 7):
|
||||||
bufio = self.tp(rawio)
|
rawio = self.MockRawIO((b"abc", b"d", b"efg"))
|
||||||
self.assertEquals(b"abcdef", bufio.read(6))
|
bufio = self.tp(rawio)
|
||||||
|
self.assertEquals(b"abcdefg", bufio.read(arg))
|
||||||
# Invalid args
|
# Invalid args
|
||||||
self.assertRaises(ValueError, bufio.read, -2)
|
self.assertRaises(ValueError, bufio.read, -2)
|
||||||
|
|
||||||
|
@ -673,6 +674,7 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
|
||||||
self.assertEquals(b"efg", bufio.read1(100))
|
self.assertEquals(b"efg", bufio.read1(100))
|
||||||
self.assertEquals(rawio._reads, 3)
|
self.assertEquals(rawio._reads, 3)
|
||||||
self.assertEquals(b"", bufio.read1(100))
|
self.assertEquals(b"", bufio.read1(100))
|
||||||
|
self.assertEquals(rawio._reads, 4)
|
||||||
# Invalid args
|
# Invalid args
|
||||||
self.assertRaises(ValueError, bufio.read1, -1)
|
self.assertRaises(ValueError, bufio.read1, -1)
|
||||||
|
|
||||||
|
@ -691,6 +693,14 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
|
||||||
self.assertEquals(bufio.readinto(b), 0)
|
self.assertEquals(bufio.readinto(b), 0)
|
||||||
self.assertEquals(b, b"gf")
|
self.assertEquals(b, b"gf")
|
||||||
|
|
||||||
|
def test_readlines(self):
|
||||||
|
def bufio():
|
||||||
|
rawio = self.MockRawIO((b"abc\n", b"d\n", b"ef"))
|
||||||
|
return self.tp(rawio)
|
||||||
|
self.assertEquals(bufio().readlines(), [b"abc\n", b"d\n", b"ef"])
|
||||||
|
self.assertEquals(bufio().readlines(5), [b"abc\n", b"d\n"])
|
||||||
|
self.assertEquals(bufio().readlines(None), [b"abc\n", b"d\n", b"ef"])
|
||||||
|
|
||||||
def test_buffering(self):
|
def test_buffering(self):
|
||||||
data = b"abcdefghi"
|
data = b"abcdefghi"
|
||||||
dlen = len(data)
|
dlen = len(data)
|
||||||
|
@ -1131,6 +1141,14 @@ class BufferedRWPairTest(unittest.TestCase):
|
||||||
self.assertEqual(pair.read(3), b"abc")
|
self.assertEqual(pair.read(3), b"abc")
|
||||||
self.assertEqual(pair.read(1), b"d")
|
self.assertEqual(pair.read(1), b"d")
|
||||||
self.assertEqual(pair.read(), b"ef")
|
self.assertEqual(pair.read(), b"ef")
|
||||||
|
pair = self.tp(self.BytesIO(b"abc"), self.MockRawIO())
|
||||||
|
self.assertEqual(pair.read(None), b"abc")
|
||||||
|
|
||||||
|
def test_readlines(self):
|
||||||
|
pair = lambda: self.tp(self.BytesIO(b"abc\ndef\nh"), self.MockRawIO())
|
||||||
|
self.assertEqual(pair().readlines(), [b"abc\n", b"def\n", b"h"])
|
||||||
|
self.assertEqual(pair().readlines(), [b"abc\n", b"def\n", b"h"])
|
||||||
|
self.assertEqual(pair().readlines(5), [b"abc\n", b"def\n"])
|
||||||
|
|
||||||
def test_read1(self):
|
def test_read1(self):
|
||||||
# .read1() is delegated to the underlying reader object, so this test
|
# .read1() is delegated to the underlying reader object, so this test
|
||||||
|
@ -1781,6 +1799,8 @@ class TextIOWrapperTest(unittest.TestCase):
|
||||||
self.assertEquals(f.read(), "abc")
|
self.assertEquals(f.read(), "abc")
|
||||||
cookie = f.tell()
|
cookie = f.tell()
|
||||||
self.assertEquals(f.seek(0), 0)
|
self.assertEquals(f.seek(0), 0)
|
||||||
|
self.assertEquals(f.read(None), "abc")
|
||||||
|
f.seek(0)
|
||||||
self.assertEquals(f.read(2), "ab")
|
self.assertEquals(f.read(2), "ab")
|
||||||
self.assertEquals(f.read(1), "c")
|
self.assertEquals(f.read(1), "c")
|
||||||
self.assertEquals(f.read(1), "")
|
self.assertEquals(f.read(1), "")
|
||||||
|
@ -1951,6 +1971,14 @@ class TextIOWrapperTest(unittest.TestCase):
|
||||||
reads += c
|
reads += c
|
||||||
self.assertEquals(reads, "AA\nBB")
|
self.assertEquals(reads, "AA\nBB")
|
||||||
|
|
||||||
|
def test_readlines(self):
|
||||||
|
txt = self.TextIOWrapper(self.BytesIO(b"AA\nBB\nCC"))
|
||||||
|
self.assertEqual(txt.readlines(), ["AA\n", "BB\n", "CC"])
|
||||||
|
txt.seek(0)
|
||||||
|
self.assertEqual(txt.readlines(None), ["AA\n", "BB\n", "CC"])
|
||||||
|
txt.seek(0)
|
||||||
|
self.assertEqual(txt.readlines(5), ["AA\n", "BB\n"])
|
||||||
|
|
||||||
# read in amounts equal to TextIOWrapper._CHUNK_SIZE which is 128.
|
# read in amounts equal to TextIOWrapper._CHUNK_SIZE which is 128.
|
||||||
def test_read_by_chunk(self):
|
def test_read_by_chunk(self):
|
||||||
# make sure "\r\n" straddles 128 char boundary.
|
# make sure "\r\n" straddles 128 char boundary.
|
||||||
|
|
|
@ -20,6 +20,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #7349: Make methods of file objects in the io module accept None as an
|
||||||
|
argument where file-like objects (ie StringIO and BytesIO) accept them to mean
|
||||||
|
the same as passing no argument.
|
||||||
|
|
||||||
- Issue #7348: StringIO.StringIO.readline(-1) now acts as if it got no argument
|
- Issue #7348: StringIO.StringIO.readline(-1) now acts as if it got no argument
|
||||||
like other file objects.
|
like other file objects.
|
||||||
|
|
||||||
|
|
|
@ -573,6 +573,29 @@ PyNumber_AsOff_t(PyObject *item, PyObject *err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Basically the "n" format code with the ability to turn None into -1. */
|
||||||
|
int
|
||||||
|
_PyIO_ConvertSsize_t(PyObject *obj, void *result) {
|
||||||
|
Py_ssize_t limit;
|
||||||
|
if (obj == Py_None) {
|
||||||
|
limit = -1;
|
||||||
|
}
|
||||||
|
else if (PyNumber_Check(obj)) {
|
||||||
|
limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError);
|
||||||
|
if (limit == -1 && PyErr_Occurred())
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"integer argument expected, got '%.200s'",
|
||||||
|
Py_TYPE(obj)->tp_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*((Py_ssize_t *)result) = limit;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Module definition
|
* Module definition
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -19,6 +19,9 @@ extern PyTypeObject PyBufferedRandom_Type;
|
||||||
extern PyTypeObject PyTextIOWrapper_Type;
|
extern PyTypeObject PyTextIOWrapper_Type;
|
||||||
extern PyTypeObject PyIncrementalNewlineDecoder_Type;
|
extern PyTypeObject PyIncrementalNewlineDecoder_Type;
|
||||||
|
|
||||||
|
|
||||||
|
extern int _PyIO_ConvertSsize_t(PyObject *, void *);
|
||||||
|
|
||||||
/* These functions are used as METH_NOARGS methods, are normally called
|
/* These functions are used as METH_NOARGS methods, are normally called
|
||||||
* with args=NULL, and return a new reference.
|
* with args=NULL, and return a new reference.
|
||||||
* BUT when args=Py_True is passed, they return a borrowed reference.
|
* BUT when args=Py_True is passed, they return a borrowed reference.
|
||||||
|
|
|
@ -720,7 +720,7 @@ buffered_read(buffered *self, PyObject *args)
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
|
|
||||||
CHECK_INITIALIZED(self)
|
CHECK_INITIALIZED(self)
|
||||||
if (!PyArg_ParseTuple(args, "|n:read", &n)) {
|
if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (n < -1) {
|
if (n < -1) {
|
||||||
|
@ -950,25 +950,11 @@ end_unlocked:
|
||||||
static PyObject *
|
static PyObject *
|
||||||
buffered_readline(buffered *self, PyObject *args)
|
buffered_readline(buffered *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *limitobj = NULL;
|
|
||||||
Py_ssize_t limit = -1;
|
Py_ssize_t limit = -1;
|
||||||
|
|
||||||
CHECK_INITIALIZED(self)
|
CHECK_INITIALIZED(self)
|
||||||
|
if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit))
|
||||||
if (!PyArg_ParseTuple(args, "|O:readline", &limitobj)) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
if (limitobj) {
|
|
||||||
if (!PyNumber_Check(limitobj)) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"integer argument expected, got '%.200s'",
|
|
||||||
Py_TYPE(limitobj)->tp_name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
limit = PyNumber_AsSsize_t(limitobj, PyExc_OverflowError);
|
|
||||||
if (limit == -1 && PyErr_Occurred())
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return _buffered_readline(self, limit);
|
return _buffered_readline(self, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -599,7 +599,7 @@ fileio_read(fileio *self, PyObject *args)
|
||||||
if (!self->readable)
|
if (!self->readable)
|
||||||
return err_mode("reading");
|
return err_mode("reading");
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|n", &size))
|
if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
|
|
|
@ -455,7 +455,7 @@ iobase_readline(PyObject *self, PyObject *args)
|
||||||
PyObject *buffer, *result;
|
PyObject *buffer, *result;
|
||||||
Py_ssize_t old_size = -1;
|
Py_ssize_t old_size = -1;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|n:readline", &limit)) {
|
if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,14 +579,9 @@ iobase_readlines(PyObject *self, PyObject *args)
|
||||||
Py_ssize_t hint = -1, length = 0;
|
Py_ssize_t hint = -1, length = 0;
|
||||||
PyObject *hintobj = Py_None, *result;
|
PyObject *hintobj = Py_None, *result;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|O:readlines", &hintobj)) {
|
if (!PyArg_ParseTuple(args, "|O&:readlines", &_PyIO_ConvertSsize_t, &hint)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (hintobj != Py_None) {
|
|
||||||
hint = PyNumber_AsSsize_t(hintobj, PyExc_ValueError);
|
|
||||||
if (hint == -1 && PyErr_Occurred())
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = PyList_New(0);
|
result = PyList_New(0);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
|
|
|
@ -1455,7 +1455,7 @@ textiowrapper_read(textio *self, PyObject *args)
|
||||||
|
|
||||||
CHECK_INITIALIZED(self);
|
CHECK_INITIALIZED(self);
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|n:read", &n))
|
if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
CHECK_CLOSED(self);
|
CHECK_CLOSED(self);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue