Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avoid importing backend-specific dependencies #1006

Merged
merged 1 commit into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies = [
[tool.hatch.envs.default.scripts]
publish = "invoke publish {args}"
docs = "invoke docs {args}"
check = ["lint-py", "lint-js", "test-py", "test-js", "test-docs"]

lint-py = "invoke lint-py {args}"
lint-js = "invoke lint-js {args}"
Expand Down
77 changes: 41 additions & 36 deletions src/py/reactpy/reactpy/backend/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,62 @@
from collections.abc import Awaitable, Sequence
from dataclasses import dataclass
from pathlib import Path, PurePosixPath
from typing import Any, cast

import uvicorn
from asgiref.typing import ASGIApplication
from typing import TYPE_CHECKING, Any, cast

from reactpy import __file__ as _reactpy_file_path
from reactpy import html
from reactpy.config import REACTPY_WEB_MODULES_DIR
from reactpy.core.types import VdomDict
from reactpy.utils import vdom_to_html

if TYPE_CHECKING:
from asgiref.typing import ASGIApplication

PATH_PREFIX = PurePosixPath("/_reactpy")
MODULES_PATH = PATH_PREFIX / "modules"
ASSETS_PATH = PATH_PREFIX / "assets"
STREAM_PATH = PATH_PREFIX / "stream"

CLIENT_BUILD_DIR = Path(_reactpy_file_path).parent / "_static" / "app" / "dist"


async def serve_development_asgi(
app: ASGIApplication | Any,
host: str,
port: int,
started: asyncio.Event | None,
) -> None:
"""Run a development server for an ASGI application"""
server = uvicorn.Server(
uvicorn.Config(
app,
host=host,
port=port,
loop="asyncio",
reload=True,
try:
import uvicorn
except ImportError: # nocov
pass
else:

async def serve_development_asgi(
app: ASGIApplication | Any,
host: str,
port: int,
started: asyncio.Event | None,
) -> None:
"""Run a development server for an ASGI application"""
server = uvicorn.Server(
uvicorn.Config(
app,
host=host,
port=port,
loop="asyncio",
reload=True,
)
)
)
server.config.setup_event_loop()
coros: list[Awaitable[Any]] = [server.serve()]

# If a started event is provided, then use it signal based on `server.started`
if started:
coros.append(_check_if_started(server, started))

try:
await asyncio.gather(*coros)
finally:
# Since we aren't using the uvicorn's `run()` API, we can't guarantee uvicorn's
# order of operations. So we need to make sure `shutdown()` always has an initialized
# list of `self.servers` to use.
if not hasattr(server, "servers"): # nocov
server.servers = []
await asyncio.wait_for(server.shutdown(), timeout=3)
server.config.setup_event_loop()
coros: list[Awaitable[Any]] = [server.serve()]

# If a started event is provided, then use it signal based on `server.started`
if started:
coros.append(_check_if_started(server, started))

try:
await asyncio.gather(*coros)
finally:
# Since we aren't using the uvicorn's `run()` API, we can't guarantee uvicorn's
# order of operations. So we need to make sure `shutdown()` always has an initialized
# list of `self.servers` to use.
if not hasattr(server, "servers"): # nocov
server.servers = []
await asyncio.wait_for(server.shutdown(), timeout=3)


async def _check_if_started(server: uvicorn.Server, started: asyncio.Event) -> None:
Expand Down