diff --git a/Lib/socket.py b/Lib/socket.py index a93cd11248c..ea56a67d555 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -315,12 +315,23 @@ class SocketIO(io.RawIOBase): def readable(self): """True if the SocketIO is open for reading. """ - return self._reading and not self.closed + if self.closed: + raise ValueError("I/O operation on closed socket.") + return self._reading def writable(self): """True if the SocketIO is open for writing. """ - return self._writing and not self.closed + if self.closed: + raise ValueError("I/O operation on closed socket.") + return self._writing + + def seekable(self): + """True if the SocketIO is open for seeking. + """ + if self.closed: + raise ValueError("I/O operation on closed socket.") + return super().seekable() def fileno(self): """Return the file descriptor of the underlying socket. diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index cce0d1b6eb4..e2ed21d222b 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -839,6 +839,17 @@ class GeneralModuleTests(unittest.TestCase): fp.close() self.assertEqual(repr(fp), "<_io.BufferedReader name=-1>") + def test_unusable_closed_socketio(self): + with socket.socket() as sock: + fp = sock.makefile("rb", buffering=0) + self.assertTrue(fp.readable()) + self.assertFalse(fp.writable()) + self.assertFalse(fp.seekable()) + fp.close() + self.assertRaises(ValueError, fp.readable) + self.assertRaises(ValueError, fp.writable) + self.assertRaises(ValueError, fp.seekable) + def testListenBacklog0(self): srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.bind((HOST, 0)) diff --git a/Misc/NEWS b/Misc/NEWS index 24c6b7121d5..29e2c195656 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -120,6 +120,10 @@ Core and Builtins Library ------- +- Issue #15842: the SocketIO.{readable,writable,seekable} methods now + raise ValueError when the file-like object is closed. Patch by Alessandro + Moura. + - Issue #15881: Fixed atexit hook in multiprocessing. Original patch by Chris McDonough.