Skip to content

Commit

Permalink
Fix idom.run uvicorn self.servers exception (#943)
Browse files Browse the repository at this point in the history
  • Loading branch information
Archmonger committed Apr 5, 2023
1 parent b15b43d commit 8caf973
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 32 deletions.
10 changes: 2 additions & 8 deletions docs/source/about/contributor-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,23 +140,17 @@ followed the `earlier instructions <Development Environment>`_. The suite covers

3. Client-side Javascript code with UVU_

Before running the test suite you'll need to install the required browsers by running:

.. code-block:: bash
playwright install
Once you've installed them you'll be able to run:

.. code-block:: bash
nox -s test
nox -s check-python-tests
You can observe the browser as the tests are running by passing an extra flag:

.. code-block:: bash
nox -s test -- --headed
nox -s check-python-tests -- --headed
To see a full list of available commands (e.g. ``nox -s <your-command>``) run:

Expand Down
19 changes: 12 additions & 7 deletions src/reactpy/backend/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
from pathlib import Path, PurePosixPath
from typing import Any, Awaitable, Sequence, cast

import uvicorn
from asgiref.typing import ASGIApplication
from uvicorn.config import Config as UvicornConfig
from uvicorn.server import Server as UvicornServer

from reactpy import __file__ as _reactpy_file_path
from reactpy import html
Expand All @@ -31,29 +30,35 @@ async def serve_development_asgi(
port: int,
started: asyncio.Event | None,
) -> None:
"""Run a development server for starlette"""
server = UvicornServer(
UvicornConfig(
"""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"): # pragma: no cover
server.servers = []
await asyncio.wait_for(server.shutdown(), timeout=3)


async def _check_if_started(server: UvicornServer, started: asyncio.Event) -> None:
async def _check_if_started(server: uvicorn.Server, started: asyncio.Event) -> None:
while not server.started:
await asyncio.sleep(0.2)
started.set()
Expand Down
4 changes: 2 additions & 2 deletions src/reactpy/backend/flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ def use_request() -> Request:
def use_connection() -> Connection[_FlaskCarrier]:
"""Get the current :class:`Connection`"""
conn = _use_connection()
if not isinstance(conn.carrier, _FlaskCarrier):
raise TypeError( # pragma: no cover
if not isinstance(conn.carrier, _FlaskCarrier): # pragma: no cover
raise TypeError(
f"Connection has unexpected carrier {conn.carrier}. "
"Are you running with a Flask server?"
)
Expand Down
12 changes: 5 additions & 7 deletions src/reactpy/backend/sanic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import json
import logging
from dataclasses import dataclass
from typing import Any, MutableMapping, Tuple
from typing import Any, Tuple
from urllib import parse as urllib_parse
from uuid import uuid4

Expand Down Expand Up @@ -82,8 +82,8 @@ def use_websocket() -> WebSocketConnection:
def use_connection() -> Connection[_SanicCarrier]:
"""Get the current :class:`Connection`"""
conn = _use_connection()
if not isinstance(conn.carrier, _SanicCarrier):
raise TypeError( # pragma: no cover
if not isinstance(conn.carrier, _SanicCarrier): # pragma: no cover
raise TypeError(
f"Connection has unexpected carrier {conn.carrier}. "
"Are you running with a Sanic server?"
)
Expand Down Expand Up @@ -162,11 +162,9 @@ async def model_stream(
request: request.Request, socket: WebSocketConnection, path: str = ""
) -> None:
asgi_app = getattr(request.app, "_asgi_app", None)
if asgi_app is None: # pragma: no cover
scope = asgi_app.transport.scope if asgi_app else {}
if not scope: # pragma: no cover
logger.warning("No scope. Sanic may not be running with an ASGI server")
scope: MutableMapping[str, Any] = {}
else:
scope = asgi_app.transport.scope

send, recv = _make_send_recv_callbacks(socket)
await serve_layout(
Expand Down
4 changes: 2 additions & 2 deletions src/reactpy/backend/starlette.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ def use_websocket() -> WebSocket:

def use_connection() -> Connection[WebSocket]:
conn = _use_connection()
if not isinstance(conn.carrier, WebSocket):
raise TypeError( # pragma: no cover
if not isinstance(conn.carrier, WebSocket): # pragma: no cover
raise TypeError(
f"Connection has unexpected carrier {conn.carrier}. "
"Are you running with a Flask server?"
)
Expand Down
4 changes: 2 additions & 2 deletions src/reactpy/backend/tornado.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ def use_request() -> HTTPServerRequest:

def use_connection() -> Connection[HTTPServerRequest]:
conn = _use_connection()
if not isinstance(conn.carrier, HTTPServerRequest):
raise TypeError( # pragma: no cover
if not isinstance(conn.carrier, HTTPServerRequest): # pragma: no cover
raise TypeError(
f"Connection has unexpected carrier {conn.carrier}. "
"Are you running with a Flask server?"
)
Expand Down
6 changes: 2 additions & 4 deletions src/reactpy/backend/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,8 @@ def all_implementations() -> Iterator[BackendImplementation[Any]]:
logger.debug(f"Failed to import {name!r}", exc_info=True)
continue

if not isinstance(module, BackendImplementation):
raise TypeError( # pragma: no cover
f"{module.__name__!r} is an invalid implementation"
)
if not isinstance(module, BackendImplementation): # pragma: no cover
raise TypeError(f"{module.__name__!r} is an invalid implementation")

yield module

Expand Down

0 comments on commit 8caf973

Please sign in to comment.