Implemented Python 3.12 support

This commit is contained in:
Vladimir Magamedov 2023-10-28 17:35:13 +03:00
parent 9bca0866fa
commit 308b353ab4
6 changed files with 42 additions and 5 deletions

View File

@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v3

View File

@ -625,6 +625,7 @@ class Server(_GC):
self._config = config.__for_server__()
self._server: Optional[asyncio.AbstractServer] = None
self._server_closed_fut: Optional[asyncio.Future[None]] = None
self._handlers: Set[Handler] = set()
self.__dispatch__ = _DispatchServerEvents()
@ -703,7 +704,6 @@ class Server(_GC):
self._protocol_factory, path, sock=sock, backlog=backlog,
ssl=ssl
)
else:
# FIXME: Not all union combinations were tried because there are
# too many unions
@ -715,15 +715,18 @@ class Server(_GC):
backlog=backlog, ssl=ssl,
reuse_address=reuse_address, reuse_port=reuse_port
)
self._server_closed_fut = self._loop.create_future()
def close(self) -> None:
"""Stops accepting new connections, cancels all currently running
requests. Request handlers are able to handle `CancelledError` and
exit properly.
"""
if self._server is None:
if self._server is None or self._server_closed_fut is None:
raise RuntimeError('Server is not started')
self._server.close()
if not self._server_closed_fut.done():
self._server_closed_fut.set_result(None)
for handler in self._handlers:
handler.close()
@ -731,8 +734,9 @@ class Server(_GC):
"""Coroutine to wait until all existing request handlers will exit
properly.
"""
if self._server is None:
if self._server is None or self._server_closed_fut is None:
raise RuntimeError('Server is not started')
await self._server_closed_fut
await self._server.wait_closed()
if self._handlers:
await asyncio.wait({

View File

@ -106,6 +106,7 @@ class ChannelFor:
status_details_codec=self._status_details_codec,
)
self._server._server = _Server()
self._server._server_closed_fut = self._server._loop.create_future()
self._server_protocol = self._server._protocol_factory()
self._channel = Channel(

View File

@ -52,6 +52,8 @@ asyncio_mode = auto
filterwarnings =
error
ignore:.*pkg_resources.*:DeprecationWarning
ignore:.*google.*:DeprecationWarning
ignore:.*utcfromtimestamp.*:DeprecationWarning
ignore::ResourceWarning
[coverage:run]

View File

@ -167,6 +167,6 @@ class ClientServer:
return handler, stub
async def __aexit__(self, *exc_info):
self.channel.close()
self.server.close()
await self.server.wait_closed()
self.channel.close()

30
tests/test_server.py Normal file
View File

@ -0,0 +1,30 @@
import asyncio
import pytest
from grpclib.server import Server
async def serve_forever(server):
await server.start('127.0.0.1')
await server.wait_closed()
@pytest.mark.asyncio
async def test_wait_closed(loop: asyncio.AbstractEventLoop):
server = Server([])
task = loop.create_task(serve_forever(server))
done, pending = await asyncio.wait([task], timeout=0.1)
assert pending and not done
server.close()
done, pending = await asyncio.wait([task], timeout=0.1)
assert done and not pending
@pytest.mark.asyncio
async def test_close_twice():
server = Server([])
await server.start('127.0.0.1')
server.close()
server.close()
await server.wait_closed()