From 26c437403ad6aedb3e9488a773e2a04b061c5dee Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sun, 30 May 2021 20:25:17 +0200 Subject: [PATCH 1/8] =?UTF-8?q?=F0=9F=9A=A8=20Cover=20server.py=20on=20myp?= =?UTF-8?q?y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup.cfg | 3 ++- uvicorn/server.py | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/setup.cfg b/setup.cfg index 325e4cee8..b73ca2744 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,7 +23,8 @@ files = uvicorn/supervisors/watchgodreload.py, uvicorn/logging.py, uvicorn/middleware/asgi2.py, - uvicorn/_handlers + uvicorn/_handlers, + uvicorn/server.py [mypy-tests.*] diff --git a/uvicorn/server.py b/uvicorn/server.py index e4c9e2278..cf6f655c2 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -8,10 +8,12 @@ import threading import time from email.utils import formatdate -from typing import List +from typing import List, Optional, Set, Tuple import click +from uvicorn.config import Config + from ._handlers.http import handle_http HANDLED_SIGNALS = ( @@ -27,15 +29,15 @@ class ServerState: Shared servers state that is available between all protocol instances. """ - def __init__(self): + def __init__(self) -> None: self.total_requests = 0 - self.connections = set() + self.connections: Set[asyncio.Protocol] = set() self.tasks = set() - self.default_headers = [] + self.default_headers: List[Tuple[bytes, bytes]] = [] class Server: - def __init__(self, config): + def __init__(self, config: Config) -> None: self.config = config self.server_state = ServerState() @@ -44,7 +46,7 @@ def __init__(self, config): self.force_exit = False self.last_notified = 0 - def run(self, sockets=None): + def run(self, sockets: Optional[List[socket.socket]] = None) -> None: self.config.setup_event_loop() loop = asyncio.get_event_loop() loop.run_until_complete(self.serve(sockets=sockets)) @@ -207,7 +209,7 @@ def _log_started_message(self, listeners: List[socket.SocketType]) -> None: extra={"color_message": color_message}, ) - async def main_loop(self): + async def main_loop(self) -> None: counter = 0 should_exit = await self.on_tick(counter) while not should_exit: @@ -216,7 +218,7 @@ async def main_loop(self): await asyncio.sleep(0.1) should_exit = await self.on_tick(counter) - async def on_tick(self, counter) -> bool: + async def on_tick(self, counter: int) -> bool: # Update the default headers, once per second. if counter % 10 == 0: current_time = time.time() @@ -238,7 +240,7 @@ async def on_tick(self, counter) -> bool: return self.server_state.total_requests >= self.config.limit_max_requests return False - async def shutdown(self, sockets=None): + async def shutdown(self, sockets: Optional[List[socket.socket]] = None) -> None: logger.info("Shutting down") # Stop accepting new connections. @@ -287,7 +289,7 @@ def install_signal_handlers(self) -> None: for sig in HANDLED_SIGNALS: signal.signal(sig, self.handle_exit) - def handle_exit(self, sig, frame): + def handle_exit(self, sig, frame) -> None: if self.should_exit: self.force_exit = True else: From 228e22182fb53af917dcb1c6c826b47d9d38cf8f Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Tue, 1 Jun 2021 05:45:35 +0200 Subject: [PATCH 2/8] fix all --- uvicorn/server.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/uvicorn/server.py b/uvicorn/server.py index cf6f655c2..300e7b45e 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -8,11 +8,16 @@ import threading import time from email.utils import formatdate -from typing import List, Optional, Set, Tuple +from types import FrameType +from typing import List, Optional, Set, Tuple, Union import click from uvicorn.config import Config +from uvicorn.protocols.http.h11_impl import H11Protocol +from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol +from uvicorn.protocols.websockets.websockets_impl import WebSocketProtocol +from uvicorn.protocols.websockets.wsproto_impl import WSProtocol from ._handlers.http import handle_http @@ -23,6 +28,8 @@ logger = logging.getLogger("uvicorn.error") +Protocols = Union[H11Protocol, HttpToolsProtocol, WSProtocol, WebSocketProtocol] + class ServerState: """ @@ -31,8 +38,8 @@ class ServerState: def __init__(self) -> None: self.total_requests = 0 - self.connections: Set[asyncio.Protocol] = set() - self.tasks = set() + self.connections: Set[Protocols] = set() + self.tasks: Set[asyncio.Task] = set() self.default_headers: List[Tuple[bytes, bytes]] = [] @@ -44,14 +51,14 @@ def __init__(self, config: Config) -> None: self.started = False self.should_exit = False self.force_exit = False - self.last_notified = 0 + self.last_notified = 0.0 def run(self, sockets: Optional[List[socket.socket]] = None) -> None: self.config.setup_event_loop() loop = asyncio.get_event_loop() loop.run_until_complete(self.serve(sockets=sockets)) - async def serve(self, sockets=None): + async def serve(self, sockets: Optional[List[socket.socket]] = None) -> None: process_id = os.getpid() config = self.config @@ -289,7 +296,8 @@ def install_signal_handlers(self) -> None: for sig in HANDLED_SIGNALS: signal.signal(sig, self.handle_exit) - def handle_exit(self, sig, frame) -> None: + def handle_exit(self, sig: signal.Signals, frame: FrameType) -> None: + if self.should_exit: self.force_exit = True else: From e676443379061c58b132bbf72339d9bc7a4e33a8 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Tue, 1 Jun 2021 06:04:36 +0200 Subject: [PATCH 3/8] fix windows issue --- uvicorn/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uvicorn/server.py b/uvicorn/server.py index 300e7b45e..1d5f08aa1 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -139,7 +139,7 @@ def _share_socket(sock: socket.SocketType) -> socket.SocketType: uds_perms = 0o666 if os.path.exists(config.uds): uds_perms = os.stat(config.uds).st_mode - server = await asyncio.start_unix_server( + server = await asyncio.start_unix_server( # type: ignore handler, path=config.uds, ssl=config.ssl, backlog=config.backlog ) os.chmod(config.uds, uds_perms) From a9eeabfdd55ea4e01c149ba98e9286f5a4793b44 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Wed, 9 Jun 2021 19:11:35 +0200 Subject: [PATCH 4/8] remove ignore --- uvicorn/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uvicorn/server.py b/uvicorn/server.py index 1d5f08aa1..300e7b45e 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -139,7 +139,7 @@ def _share_socket(sock: socket.SocketType) -> socket.SocketType: uds_perms = 0o666 if os.path.exists(config.uds): uds_perms = os.stat(config.uds).st_mode - server = await asyncio.start_unix_server( # type: ignore + server = await asyncio.start_unix_server( handler, path=config.uds, ssl=config.ssl, backlog=config.backlog ) os.chmod(config.uds, uds_perms) From 648dea6636aeccf6a2c1d662e3ec72e755d8855b Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Wed, 9 Jun 2021 19:15:15 +0200 Subject: [PATCH 5/8] add assert to satisfy mypy --- uvicorn/server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/uvicorn/server.py b/uvicorn/server.py index 300e7b45e..83bbd599b 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -139,6 +139,7 @@ def _share_socket(sock: socket.SocketType) -> socket.SocketType: uds_perms = 0o666 if os.path.exists(config.uds): uds_perms = os.stat(config.uds).st_mode + assert sys.platform != "win32" # mypy server = await asyncio.start_unix_server( handler, path=config.uds, ssl=config.ssl, backlog=config.backlog ) From b2b14708ba74e613003397da51456a54ee8aeb71 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Wed, 9 Jun 2021 19:24:36 +0200 Subject: [PATCH 6/8] improve assertion --- uvicorn/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uvicorn/server.py b/uvicorn/server.py index 83bbd599b..90bc6cab5 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -139,7 +139,7 @@ def _share_socket(sock: socket.SocketType) -> socket.SocketType: uds_perms = 0o666 if os.path.exists(config.uds): uds_perms = os.stat(config.uds).st_mode - assert sys.platform != "win32" # mypy + assert hasattr(asyncio, "start_unix_server") # mypy server = await asyncio.start_unix_server( handler, path=config.uds, ssl=config.ssl, backlog=config.backlog ) From 3c87d7d881b3367de8f84f753b50e0fb151a52c4 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sat, 26 Jun 2021 14:17:34 +0200 Subject: [PATCH 7/8] merge master --- uvicorn/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uvicorn/config.py b/uvicorn/config.py index 2846d104e..98430e867 100644 --- a/uvicorn/config.py +++ b/uvicorn/config.py @@ -7,7 +7,7 @@ import socket import ssl import sys -from typing import Callable, Dict, List, Optional, Tuple, Type, Union +from typing import Awaitable, Callable, Dict, List, Optional, Tuple, Type, Union from uvicorn.logging import TRACE_LOG_LEVEL @@ -169,7 +169,7 @@ def __init__( backlog: int = 2048, timeout_keep_alive: int = 5, timeout_notify: int = 30, - callback_notify: Callable[..., None] = None, + callback_notify: Callable[..., Awaitable[None]] = None, ssl_keyfile: Optional[str] = None, ssl_certfile: Optional[Union[str, os.PathLike]] = None, ssl_keyfile_password: Optional[str] = None, @@ -219,7 +219,7 @@ def __init__( self.ssl_ca_certs = ssl_ca_certs self.ssl_ciphers = ssl_ciphers self.headers: List[List[str]] = headers or [] - self.encoded_headers: Optional[List[Tuple[bytes, bytes]]] = None + self.encoded_headers: List[Tuple[bytes, bytes]] = [] self.factory = factory self.loaded = False From d8fa7d541d554acc9eba6732612b2f5310ac9ef4 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sun, 27 Jun 2021 09:33:32 +0200 Subject: [PATCH 8/8] wrap start_unix_server --- uvicorn/server.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/uvicorn/server.py b/uvicorn/server.py index 9ac565b08..e8de6512d 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -9,17 +9,24 @@ import time from email.utils import formatdate from types import FrameType -from typing import List, Optional, Set, Tuple, Union +from typing import Any, List, Optional, Set, Tuple, Union import click +from uvicorn._handlers.http import handle_http from uvicorn.config import Config from uvicorn.protocols.http.h11_impl import H11Protocol from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol from uvicorn.protocols.websockets.websockets_impl import WebSocketProtocol from uvicorn.protocols.websockets.wsproto_impl import WSProtocol -from ._handlers.http import handle_http +if sys.platform != "win32": + from asyncio import start_unix_server as _start_unix_server +else: + + async def _start_unix_server(*args: Any, **kwargs: Any) -> Any: + raise NotImplementedError("Cannot start a unix server on win32") + HANDLED_SIGNALS = ( signal.SIGINT, # Unix signal 2. Sent by Ctrl+C. @@ -135,8 +142,7 @@ def _share_socket(sock: socket.SocketType) -> socket.SocketType: uds_perms = 0o666 if os.path.exists(config.uds): uds_perms = os.stat(config.uds).st_mode - assert hasattr(asyncio, "start_unix_server") # mypy - server = await asyncio.start_unix_server( + server = await _start_unix_server( handler, path=config.uds, ssl=config.ssl, backlog=config.backlog ) os.chmod(config.uds, uds_perms)