From 7464e87a6511d3626b04c9833a262a77b1f21e23 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Fri, 19 Jan 2018 20:04:29 +0200 Subject: bpo-32410: Make SendfileNotAvailableError exception public (#5243) --- Doc/library/asyncio-eventloop.rst | 14 +++++++++++++- Lib/asyncio/base_events.py | 17 ++++++----------- Lib/asyncio/events.py | 10 +++++++++- Lib/asyncio/unix_events.py | 8 ++++---- Lib/test/test_asyncio/test_base_events.py | 5 +++-- Lib/test/test_asyncio/test_unix_events.py | 13 +++++++------ 6 files changed, 42 insertions(+), 25 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index e63180b..6cee171 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -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 @@ -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 ------------------- diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index b6a9384..00c84a8 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -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): @@ -659,17 +655,16 @@ class BaseEventLoop(events.AbstractEventLoop): 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") diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index b06721f..d5365dc 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -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', @@ -20,6 +20,14 @@ import threading 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.""" diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index f40ef12..028a0ca 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -313,16 +313,16 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop): 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 @@ -365,7 +365,7 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop): # 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) diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index 085124f..fc3b810 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -14,6 +14,7 @@ from unittest import mock 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 @@ -1860,7 +1861,7 @@ class BaseLoopSendfileTests(test_utils.TestCase): 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)) @@ -1871,7 +1872,7 @@ class BaseLoopSendfileTests(test_utils.TestCase): 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)) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index 4e2b76b..8646bf7 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -23,6 +23,7 @@ if sys.platform == 'win32': 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 @@ -517,7 +518,7 @@ class SelectorEventLoopUnixSockSendfileTests(test_utils.TestCase): 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)) @@ -526,7 +527,7 @@ class SelectorEventLoopUnixSockSendfileTests(test_utils.TestCase): 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)) @@ -535,7 +536,7 @@ class SelectorEventLoopUnixSockSendfileTests(test_utils.TestCase): 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)) @@ -545,7 +546,7 @@ class SelectorEventLoopUnixSockSendfileTests(test_utils.TestCase): 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)) @@ -631,7 +632,7 @@ class SelectorEventLoopUnixSockSendfileTests(test_utils.TestCase): 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): @@ -656,7 +657,7 @@ class SelectorEventLoopUnixSockSendfileTests(test_utils.TestCase): 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, -- cgit v0.12