| 
5 | 5 | from collections.abc import Awaitable, Sequence  | 
6 | 6 | from dataclasses import dataclass  | 
7 | 7 | from pathlib import Path, PurePosixPath  | 
8 |  | -from typing import Any, cast  | 
9 |  | - | 
10 |  | -import uvicorn  | 
11 |  | -from asgiref.typing import ASGIApplication  | 
 | 8 | +from typing import TYPE_CHECKING, Any, cast  | 
12 | 9 | 
 
  | 
13 | 10 | from reactpy import __file__ as _reactpy_file_path  | 
14 | 11 | from reactpy import html  | 
15 | 12 | from reactpy.config import REACTPY_WEB_MODULES_DIR  | 
16 | 13 | from reactpy.core.types import VdomDict  | 
17 | 14 | from reactpy.utils import vdom_to_html  | 
18 | 15 | 
 
  | 
 | 16 | +if TYPE_CHECKING:  | 
 | 17 | +    from asgiref.typing import ASGIApplication  | 
 | 18 | + | 
19 | 19 | PATH_PREFIX = PurePosixPath("/_reactpy")  | 
20 | 20 | MODULES_PATH = PATH_PREFIX / "modules"  | 
21 | 21 | ASSETS_PATH = PATH_PREFIX / "assets"  | 
22 | 22 | STREAM_PATH = PATH_PREFIX / "stream"  | 
23 | 23 | 
 
  | 
24 | 24 | CLIENT_BUILD_DIR = Path(_reactpy_file_path).parent / "_static" / "app" / "dist"  | 
25 | 25 | 
 
  | 
26 |  | - | 
27 |  | -async def serve_development_asgi(  | 
28 |  | -    app: ASGIApplication | Any,  | 
29 |  | -    host: str,  | 
30 |  | -    port: int,  | 
31 |  | -    started: asyncio.Event | None,  | 
32 |  | -) -> None:  | 
33 |  | -    """Run a development server for an ASGI application"""  | 
34 |  | -    server = uvicorn.Server(  | 
35 |  | -        uvicorn.Config(  | 
36 |  | -            app,  | 
37 |  | -            host=host,  | 
38 |  | -            port=port,  | 
39 |  | -            loop="asyncio",  | 
40 |  | -            reload=True,  | 
 | 26 | +try:  | 
 | 27 | +    import uvicorn  | 
 | 28 | +except ImportError:  # nocov  | 
 | 29 | +    pass  | 
 | 30 | +else:  | 
 | 31 | + | 
 | 32 | +    async def serve_development_asgi(  | 
 | 33 | +        app: ASGIApplication | Any,  | 
 | 34 | +        host: str,  | 
 | 35 | +        port: int,  | 
 | 36 | +        started: asyncio.Event | None,  | 
 | 37 | +    ) -> None:  | 
 | 38 | +        """Run a development server for an ASGI application"""  | 
 | 39 | +        server = uvicorn.Server(  | 
 | 40 | +            uvicorn.Config(  | 
 | 41 | +                app,  | 
 | 42 | +                host=host,  | 
 | 43 | +                port=port,  | 
 | 44 | +                loop="asyncio",  | 
 | 45 | +                reload=True,  | 
 | 46 | +            )  | 
41 | 47 |         )  | 
42 |  | -    )  | 
43 |  | -    server.config.setup_event_loop()  | 
44 |  | -    coros: list[Awaitable[Any]] = [server.serve()]  | 
45 |  | - | 
46 |  | -    # If a started event is provided, then use it signal based on `server.started`  | 
47 |  | -    if started:  | 
48 |  | -        coros.append(_check_if_started(server, started))  | 
49 |  | - | 
50 |  | -    try:  | 
51 |  | -        await asyncio.gather(*coros)  | 
52 |  | -    finally:  | 
53 |  | -        # Since we aren't using the uvicorn's `run()` API, we can't guarantee uvicorn's  | 
54 |  | -        # order of operations. So we need to make sure `shutdown()` always has an initialized  | 
55 |  | -        # list of `self.servers` to use.  | 
56 |  | -        if not hasattr(server, "servers"):  # nocov  | 
57 |  | -            server.servers = []  | 
58 |  | -        await asyncio.wait_for(server.shutdown(), timeout=3)  | 
 | 48 | +        server.config.setup_event_loop()  | 
 | 49 | +        coros: list[Awaitable[Any]] = [server.serve()]  | 
 | 50 | + | 
 | 51 | +        # If a started event is provided, then use it signal based on `server.started`  | 
 | 52 | +        if started:  | 
 | 53 | +            coros.append(_check_if_started(server, started))  | 
 | 54 | + | 
 | 55 | +        try:  | 
 | 56 | +            await asyncio.gather(*coros)  | 
 | 57 | +        finally:  | 
 | 58 | +            # Since we aren't using the uvicorn's `run()` API, we can't guarantee uvicorn's  | 
 | 59 | +            # order of operations. So we need to make sure `shutdown()` always has an initialized  | 
 | 60 | +            # list of `self.servers` to use.  | 
 | 61 | +            if not hasattr(server, "servers"):  # nocov  | 
 | 62 | +                server.servers = []  | 
 | 63 | +            await asyncio.wait_for(server.shutdown(), timeout=3)  | 
59 | 64 | 
 
  | 
60 | 65 | 
 
  | 
61 | 66 | async def _check_if_started(server: uvicorn.Server, started: asyncio.Event) -> None:  | 
 | 
0 commit comments