The following code raise a ValueError('I/O operation on closed file.'): --- import socket socket.socket(socket.SOCK_STREAM, socket.AF_INET) s=socket.socket(socket.SOCK_STREAM, socket.AF_INET) f=s.makefile("rb") f.close() print(repr(f)) --- io.BufferedReader.__repr__() reads self.name (self.buffer.name), but self.buffer is closed. io.BufferedReader.__repr__() catchs AttributeError when reading self.name. It should also maybe catch ValueError: attached patch does that. socket.repr(x) returns a string with "[closed]". BufferedReader.repr() should maybe do the same. Note: TextIOWrapper has the same issue.
I find this new behavior a usability regression. Before this change, code (e.g python 2 code ported to python 3) could do: fd = sock.fileno() Without handling errors, since closed socket would raise (good). Now such code need to check the return value (bad): fd = sock.fileno() if fd == -1: fail... This is also not consistent with other objects: >>> f = open("Makefile") >>> f.fileno() 3 >>> f.close() >>> f.fileno() Traceback (most recent call last): File "", line 1, in ValueError: I/O operation on closed file >>> repr(f) "<_io.TextIOWrapper name='Makefile' mode='r' encoding='UTF-8'>" The issue with repr() on closed socket can be mitigated easily inside __repr__, handling closed sockets without affecting code using file descriptors. Can we return the old safe behavior?