Skip to content

bpo-32410: Make SendfileNotAvailableError public #5243

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion Doc/library/asyncio-eventloop.rst
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ Low-level socket operations
the file when the platform does not support the sendfile syscall
(e.g. Windows or SSL socket on Unix).

Raise :exc:`RuntimeError` if the system does not support
Raise :exc:`SendfileNotAvailableError` if the system does not support
*sendfile* syscall and *fallback* is ``False``.

.. versionadded:: 3.7
Expand Down Expand Up @@ -980,6 +980,18 @@ Handle
.. versionadded:: 3.7


SendfileNotAvailableError
-------------------------


.. exception:: SendfileNotAvailableError

Sendfile syscall is not available, subclass of :exc:`RuntimeError`.

Raised if the OS does not support senfile syscall for
given socket or file type.


Event loop examples
-------------------

Expand Down
17 changes: 6 additions & 11 deletions Lib/asyncio/base_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,6 @@ def _run_until_complete_cb(fut):
futures._get_loop(fut).stop()


class _SendfileNotAvailable(RuntimeError):
pass


class Server(events.AbstractServer):

def __init__(self, loop, sockets):
Expand Down Expand Up @@ -659,17 +655,16 @@ async def sock_sendfile(self, sock, file, offset=0, count=None,
try:
return await self._sock_sendfile_native(sock, file,
offset, count)
except _SendfileNotAvailable as exc:
if fallback:
return await self._sock_sendfile_fallback(sock, file,
offset, count)
else:
raise RuntimeError(exc.args[0]) from None
except events.SendfileNotAvailableError as exc:
if not fallback:
raise
return await self._sock_sendfile_fallback(sock, file,
offset, count)

async def _sock_sendfile_native(self, sock, file, offset, count):
# NB: sendfile syscall is not supported for SSL sockets and
# non-mmap files even if sendfile is supported by OS
raise _SendfileNotAvailable(
raise events.SendfileNotAvailableError(
f"syscall sendfile is not available for socket {sock!r} "
"and file {file!r} combination")

Expand Down
10 changes: 9 additions & 1 deletion Lib/asyncio/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
__all__ = (
'AbstractEventLoopPolicy',
'AbstractEventLoop', 'AbstractServer',
'Handle', 'TimerHandle',
'Handle', 'TimerHandle', 'SendfileNotAvailableError',
'get_event_loop_policy', 'set_event_loop_policy',
'get_event_loop', 'set_event_loop', 'new_event_loop',
'get_child_watcher', 'set_child_watcher',
Expand All @@ -20,6 +20,14 @@
from . import format_helpers


class SendfileNotAvailableError(RuntimeError):
"""Sendfile syscall is not available.

Raised if OS does not support senfile syscall for given socket or
file type.
"""


class Handle:
"""Object returned by callback registration methods."""

Expand Down
8 changes: 4 additions & 4 deletions Lib/asyncio/unix_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,16 +313,16 @@ async def _sock_sendfile_native(self, sock, file, offset, count):
try:
os.sendfile
except AttributeError as exc:
raise base_events._SendfileNotAvailable(
raise events.SendfileNotAvailableError(
"os.sendfile() is not available")
try:
fileno = file.fileno()
except (AttributeError, io.UnsupportedOperation) as err:
raise base_events._SendfileNotAvailable("not a regular file")
raise events.SendfileNotAvailableError("not a regular file")
try:
fsize = os.fstat(fileno).st_size
except OSError as err:
raise base_events._SendfileNotAvailable("not a regular file")
raise events.SendfileNotAvailableError("not a regular file")
blocksize = count if count else fsize
if not blocksize:
return 0 # empty file
Expand Down Expand Up @@ -365,7 +365,7 @@ def _sock_sendfile_native_impl(self, fut, registered_fd, sock, fileno,
# one being 'file' is not a regular mmap(2)-like
# file, in which case we'll fall back on using
# plain send().
err = base_events._SendfileNotAvailable(
err = events.SendfileNotAvailableError(
"os.sendfile call failed")
self._sock_sendfile_update_filepos(fileno, offset, total_sent)
fut.set_exception(err)
Expand Down
5 changes: 3 additions & 2 deletions Lib/test/test_asyncio/test_base_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import asyncio
from asyncio import base_events
from asyncio import constants
from asyncio import events
from test.test_asyncio import utils as test_utils
from test import support
from test.support.script_helper import assert_python_ok
Expand Down Expand Up @@ -1860,7 +1861,7 @@ def cleanup():
def test__sock_sendfile_native_failure(self):
sock, proto = self.prepare()

with self.assertRaisesRegex(base_events._SendfileNotAvailable,
with self.assertRaisesRegex(events.SendfileNotAvailableError,
"sendfile is not available"):
self.run_loop(self.loop._sock_sendfile_native(sock, self.file,
0, None))
Expand All @@ -1871,7 +1872,7 @@ def test__sock_sendfile_native_failure(self):
def test_sock_sendfile_no_fallback(self):
sock, proto = self.prepare()

with self.assertRaisesRegex(RuntimeError,
with self.assertRaisesRegex(events.SendfileNotAvailableError,
"sendfile is not available"):
self.run_loop(self.loop.sock_sendfile(sock, self.file,
fallback=False))
Expand Down
13 changes: 7 additions & 6 deletions Lib/test/test_asyncio/test_unix_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import asyncio
from asyncio import log
from asyncio import base_events
from asyncio import events
from asyncio import unix_events
from test.test_asyncio import utils as test_utils

Expand Down Expand Up @@ -517,7 +518,7 @@ def test_with_offset_and_count(self):
def test_sendfile_not_available(self):
sock, proto = self.prepare()
with mock.patch('asyncio.unix_events.os', spec=[]):
with self.assertRaisesRegex(base_events._SendfileNotAvailable,
with self.assertRaisesRegex(events.SendfileNotAvailableError,
"os[.]sendfile[(][)] is not available"):
self.run_loop(self.loop._sock_sendfile_native(sock, self.file,
0, None))
Expand All @@ -526,7 +527,7 @@ def test_sendfile_not_available(self):
def test_sendfile_not_a_file(self):
sock, proto = self.prepare()
f = object()
with self.assertRaisesRegex(base_events._SendfileNotAvailable,
with self.assertRaisesRegex(events.SendfileNotAvailableError,
"not a regular file"):
self.run_loop(self.loop._sock_sendfile_native(sock, f,
0, None))
Expand All @@ -535,7 +536,7 @@ def test_sendfile_not_a_file(self):
def test_sendfile_iobuffer(self):
sock, proto = self.prepare()
f = io.BytesIO()
with self.assertRaisesRegex(base_events._SendfileNotAvailable,
with self.assertRaisesRegex(events.SendfileNotAvailableError,
"not a regular file"):
self.run_loop(self.loop._sock_sendfile_native(sock, f,
0, None))
Expand All @@ -545,7 +546,7 @@ def test_sendfile_not_regular_file(self):
sock, proto = self.prepare()
f = mock.Mock()
f.fileno.return_value = -1
with self.assertRaisesRegex(base_events._SendfileNotAvailable,
with self.assertRaisesRegex(events.SendfileNotAvailableError,
"not a regular file"):
self.run_loop(self.loop._sock_sendfile_native(sock, f,
0, None))
Expand Down Expand Up @@ -631,7 +632,7 @@ def test_os_error_first_call(self):
with self.assertRaises(KeyError):
self.loop._selector.get_key(sock)
exc = fut.exception()
self.assertIsInstance(exc, base_events._SendfileNotAvailable)
self.assertIsInstance(exc, events.SendfileNotAvailableError)
self.assertEqual(0, self.file.tell())

def test_os_error_next_call(self):
Expand All @@ -656,7 +657,7 @@ def test_exception(self):

fileno = self.file.fileno()
fut = self.loop.create_future()
err = RuntimeError()
err = events.SendfileNotAvailableError()
with mock.patch('os.sendfile', side_effect=err):
self.loop._sock_sendfile_native_impl(fut, sock.fileno(),
sock, fileno,
Expand Down