Fixed issue #4233.
Changed semantic of _fileio.FileIO's close() method on file objects with closefd=False. The file descriptor is still kept open but the file object behaves like a closed file. The FileIO object also got a new readonly attribute closefd. Approved by Barry
This commit is contained in:
parent
b37509b11b
commit
ecc42a2b82
|
@ -213,8 +213,10 @@ I/O Base Classes
|
||||||
|
|
||||||
.. method:: close()
|
.. method:: close()
|
||||||
|
|
||||||
Flush and close this stream. This method has no effect if the file is
|
Flush and close this stream. This method has no effect if the file is
|
||||||
already closed.
|
already closed. Once the file is closed, any operation on the file
|
||||||
|
(e.g. reading or writing) will raise an :exc:`IOError`. The internal
|
||||||
|
file descriptor isn't closed if *closefd* was False.
|
||||||
|
|
||||||
.. attribute:: closed
|
.. attribute:: closed
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,29 @@ class IOTest(unittest.TestCase):
|
||||||
self.assertRaises(ValueError, io.open, support.TESTFN, 'w',
|
self.assertRaises(ValueError, io.open, support.TESTFN, 'w',
|
||||||
closefd=False)
|
closefd=False)
|
||||||
|
|
||||||
|
def testReadClosed(self):
|
||||||
|
with io.open(support.TESTFN, "w") as f:
|
||||||
|
f.write("egg\n")
|
||||||
|
with io.open(support.TESTFN, "r") as f:
|
||||||
|
file = io.open(f.fileno(), "r", closefd=False)
|
||||||
|
self.assertEqual(file.read(), "egg\n")
|
||||||
|
file.seek(0)
|
||||||
|
file.close()
|
||||||
|
self.assertRaises(ValueError, file.read)
|
||||||
|
|
||||||
|
def test_no_closefd_with_filename(self):
|
||||||
|
# can't use closefd in combination with a file name
|
||||||
|
self.assertRaises(ValueError, io.open, support.TESTFN, "r", closefd=False)
|
||||||
|
|
||||||
|
def test_closefd_attr(self):
|
||||||
|
with io.open(support.TESTFN, "wb") as f:
|
||||||
|
f.write(b"egg\n")
|
||||||
|
with io.open(support.TESTFN, "r") as f:
|
||||||
|
self.assertEqual(f.buffer.raw.closefd, True)
|
||||||
|
file = io.open(f.fileno(), "r", closefd=False)
|
||||||
|
self.assertEqual(file.buffer.raw.closefd, False)
|
||||||
|
|
||||||
|
|
||||||
class MemorySeekTestMixin:
|
class MemorySeekTestMixin:
|
||||||
|
|
||||||
def testInit(self):
|
def testInit(self):
|
||||||
|
@ -1237,15 +1260,6 @@ class MiscIOTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assert_(issubclass(obj, io.IOBase))
|
self.assert_(issubclass(obj, io.IOBase))
|
||||||
|
|
||||||
def test_fileio_warnings(self):
|
|
||||||
with support.check_warnings() as w:
|
|
||||||
self.assertEqual(w.warnings, [])
|
|
||||||
self.assertRaises(TypeError, io.FileIO, [])
|
|
||||||
self.assertEqual(w.warnings, [])
|
|
||||||
self.assertRaises(ValueError, io.FileIO, "/some/invalid/name", "rt")
|
|
||||||
self.assertEqual(w.warnings, [])
|
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(IOTest, BytesIOTest, StringIOTest,
|
support.run_unittest(IOTest, BytesIOTest, StringIOTest,
|
||||||
BufferedReaderTest, BufferedWriterTest,
|
BufferedReaderTest, BufferedWriterTest,
|
||||||
|
|
|
@ -15,6 +15,11 @@ What's New in Python 3.0 beta 5
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #4233: Changed semantic of ``_fileio.FileIO``'s ``close()``
|
||||||
|
method on file objects with closefd=False. The file descriptor is still
|
||||||
|
kept open but the file object behaves like a closed file. The ``FileIO``
|
||||||
|
object also got a new readonly attribute ``closefd``.
|
||||||
|
|
||||||
- Issue #3626: On cygwin, starting python with a non-existent script name
|
- Issue #3626: On cygwin, starting python with a non-existent script name
|
||||||
would not display anything if the file name is only 1 character long.
|
would not display anything if the file name is only 1 character long.
|
||||||
|
|
||||||
|
|
|
@ -61,10 +61,7 @@ static PyObject *
|
||||||
fileio_close(PyFileIOObject *self)
|
fileio_close(PyFileIOObject *self)
|
||||||
{
|
{
|
||||||
if (!self->closefd) {
|
if (!self->closefd) {
|
||||||
if (PyErr_WarnEx(PyExc_RuntimeWarning,
|
self->fd = -1;
|
||||||
"Trying to close unclosable fd!", 3) < 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
errno = internal_close(self);
|
errno = internal_close(self);
|
||||||
|
@ -820,6 +817,12 @@ get_closed(PyFileIOObject *self, void *closure)
|
||||||
return PyBool_FromLong((long)(self->fd < 0));
|
return PyBool_FromLong((long)(self->fd < 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
get_closefd(PyFileIOObject *self, void *closure)
|
||||||
|
{
|
||||||
|
return PyBool_FromLong((long)(self->closefd));
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
get_mode(PyFileIOObject *self, void *closure)
|
get_mode(PyFileIOObject *self, void *closure)
|
||||||
{
|
{
|
||||||
|
@ -828,6 +831,8 @@ get_mode(PyFileIOObject *self, void *closure)
|
||||||
|
|
||||||
static PyGetSetDef fileio_getsetlist[] = {
|
static PyGetSetDef fileio_getsetlist[] = {
|
||||||
{"closed", (getter)get_closed, NULL, "True if the file is closed"},
|
{"closed", (getter)get_closed, NULL, "True if the file is closed"},
|
||||||
|
{"closefd", (getter)get_closefd, NULL,
|
||||||
|
"True if the file descriptor will be closed"},
|
||||||
{"mode", (getter)get_mode, NULL, "String giving the file mode"},
|
{"mode", (getter)get_mode, NULL, "String giving the file mode"},
|
||||||
{0},
|
{0},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue