Skip to content

Commit 6af8059

Browse files
committed
misc fixes
1 parent c2322ee commit 6af8059

File tree

5 files changed

+31
-18
lines changed

5 files changed

+31
-18
lines changed

src/idom/server/any.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def run(
2727
host: str = "127.0.0.1",
2828
port: int | None = None,
2929
open_browser: bool = True,
30-
implementation: ServerImplementation = sys.modules[__name__],
30+
implementation: ServerImplementation[Any] = sys.modules[__name__],
3131
) -> None:
3232
"""Run a component with a development server"""
3333

@@ -40,7 +40,7 @@ def run(
4040
app = implementation.create_development_app()
4141
implementation.configure(app, component)
4242

43-
coros: list[Awaitable] = []
43+
coros: list[Awaitable[Any]] = []
4444

4545
host = host
4646
port = port or find_available_port(host)
@@ -56,7 +56,7 @@ async def _open_browser_after_server() -> None:
5656

5757
coros.append(_open_browser_after_server())
5858

59-
asyncio.get_event_loop().run_forever(asyncio.gather(*coros))
59+
asyncio.get_event_loop().run_until_complete(asyncio.gather(*coros))
6060

6161

6262
def configure(app: Any, component: RootComponentConstructor) -> None:
@@ -78,7 +78,7 @@ async def serve_development_app(
7878
)
7979

8080

81-
def _get_any_implementation() -> ServerImplementation:
81+
def _get_any_implementation() -> ServerImplementation[Any]:
8282
"""Get the first available server implementation"""
8383
global _DEFAULT_IMPLEMENTATION
8484

@@ -94,10 +94,10 @@ def _get_any_implementation() -> ServerImplementation:
9494
return implementation
9595

9696

97-
_DEFAULT_IMPLEMENTATION: ServerImplementation | None = None
97+
_DEFAULT_IMPLEMENTATION: ServerImplementation[Any] | None = None
9898

9999

100-
def all_implementations() -> Iterator[ServerImplementation]:
100+
def all_implementations() -> Iterator[ServerImplementation[Any]]:
101101
"""Yield all available server implementations"""
102102
for name in SUPPORTED_PACKAGES:
103103
try:

src/idom/server/tornado.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from typing import Any, List, Optional, Tuple, Type, Union
1010
from urllib.parse import urljoin
1111

12+
from tornado.httpserver import HTTPServer
1213
from tornado.platform.asyncio import AsyncIOMainLoop
1314
from tornado.web import Application, RedirectHandler, RequestHandler, StaticFileHandler
1415
from tornado.websocket import WebSocketHandler
@@ -19,7 +20,7 @@
1920
from idom.core.serve import VdomJsonPatch, serve_json_patch
2021
from idom.core.types import ComponentConstructor
2122

22-
from .utils import CLIENT_BUILD_DIR, threaded, wait_on_event
23+
from .utils import CLIENT_BUILD_DIR
2324

2425

2526
def configure(
@@ -52,11 +53,23 @@ def create_development_app() -> Application:
5253
async def serve_development_app(
5354
app: Application, host: str, port: int, started: asyncio.Event
5455
) -> None:
55-
loop = AsyncIOMainLoop()
56-
loop.install()
57-
app.listen(port, host)
58-
loop.add_callback(lambda: loop.asyncio_loop.call_soon_threadsafe(started.set))
59-
await loop.run_in_executor(ThreadPoolExecutor())
56+
# setup up tornado to use asyncio
57+
AsyncIOMainLoop().install()
58+
59+
server = HTTPServer(app)
60+
server.listen(port, host)
61+
62+
# at this point the server is accepting connection
63+
started.set()
64+
65+
try:
66+
# block forever - tornado has already set up its own background tasks
67+
await asyncio.get_event_loop().create_future()
68+
finally:
69+
# stop accepting new connections
70+
server.stop()
71+
# wait for existing connections to complete
72+
await server.close_all_connections()
6073

6174

6275
class Options(TypedDict, total=False):

src/idom/server/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
@runtime_checkable
13-
class ServerImplementation(Protocol):
13+
class ServerImplementation(Protocol[_App]):
1414
"""Common interface for IDOM's builti-in server implementations"""
1515

1616
def configure(self, app: _App, component: RootComponentConstructor) -> None:

src/idom/testing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ class ServerMountPoint:
7272
"""A context manager for imperatively mounting views to a render server when testing"""
7373

7474
_log_handler: "_LogRecordCaptor"
75-
_server_future: asyncio.Task
75+
_server_future: asyncio.Task[Any]
7676

7777
def __init__(
7878
self,
79-
server_implementation: ServerImplementation = any_server,
79+
server_implementation: ServerImplementation[Any] = any_server,
8080
host: str = "127.0.0.1",
8181
port: Optional[int] = None,
8282
) -> None:

src/idom/widgets.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def __call__(self, value: str) -> _CastTo:
107107
...
108108

109109

110-
MountFunc = Callable[[ComponentConstructor], None]
110+
MountFunc = Callable[["ComponentConstructor | None"], None]
111111

112112

113113
def hotswap(update_on_change: bool = False) -> Tuple[MountFunc, ComponentConstructor]:
@@ -162,8 +162,8 @@ def add_callback() -> Callable[[], None]:
162162

163163
return constructor()
164164

165-
def swap(constructor: Callable[[], Any]) -> None:
166-
constructor_ref.current = constructor
165+
def swap(constructor: Callable[[], Any] | None) -> None:
166+
constructor = constructor_ref.current = constructor or (lambda: None)
167167

168168
for set_constructor in set_constructor_callbacks:
169169
set_constructor(constructor)

0 commit comments

Comments
 (0)