diff --git a/Lib/socket.py b/Lib/socket.py --- a/Lib/socket.py +++ b/Lib/socket.py @@ -263,17 +263,17 @@ class socket(_socket.socket): self._check_sendfile_params(file, offset, count) sockno = self.fileno() try: fileno = file.fileno() except (AttributeError, io.UnsupportedOperation) as err: raise _GiveupOnSendfile(err) # not a regular file try: fsize = os.fstat(fileno).st_size - except OSError: + except OSError as err: raise _GiveupOnSendfile(err) # not a regular file if not fsize: return 0 # empty file blocksize = fsize if not count else count timeout = self.gettimeout() if timeout == 0: raise ValueError("non-blocking sockets are not supported") diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1480,16 +1480,37 @@ class GeneralModuleTests(unittest.TestCa # type and populates the socket object. # # On Windows this trick won't work, so the test is skipped. fd, _ = tempfile.mkstemp() with socket.socket(family=42424, type=13331, fileno=fd) as s: self.assertEqual(s.family, 42424) self.assertEqual(s.type, 13331) + @unittest.skipUnless(hasattr(os, 'sendfile'), 'test needs os.sendfile()') + def test__sendfile_use_sendfile(self): + class File: + def __init__(self, fd): + self.fd = fd + + def fileno(self): + return self.fd + tests = [ + (os.open(os.curdir, os.O_RDONLY), socket._GiveupOnSendfile), + (2**1000, OverflowError), + (None, TypeError), + ] + for fd, exc in tests: + with self.subTest(fd=fd, exc=exc.__name__): + with socket.socket() as sock: + if exc == socket._GiveupOnSendfile: + os.close(fd) + self.assertRaises(exc, sock._sendfile_use_sendfile, File(fd)) + + @unittest.skipUnless(HAVE_SOCKET_CAN, 'SocketCan required for this test.') class BasicCANTest(unittest.TestCase): def testCrucialConstants(self): socket.AF_CAN socket.PF_CAN socket.CAN_RAW