Skip to content

Commit de8e165

Browse files
committed
check backend route priorities
1 parent b469baa commit de8e165

File tree

8 files changed

+47
-21
lines changed

8 files changed

+47
-21
lines changed

src/idom/backend/_urls.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from pathlib import PurePosixPath
2+
3+
4+
PATH_PREFIX = PurePosixPath("/_idom")
5+
MODULES_PATH = PATH_PREFIX / "modules"
6+
ASSETS_PATH = PATH_PREFIX / "assets"
7+
STREAM_PATH = PATH_PREFIX / "stream"

src/idom/backend/default.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ def create_development_app() -> Any:
2323
return _default_implementation().create_development_app()
2424

2525

26+
def Options(*args: Any, **kwargs: Any) -> Any:
27+
"""Create configuration options"""
28+
return _default_implementation().Options(*args, **kwargs)
29+
30+
2631
async def serve_development_app(
2732
app: Any,
2833
host: str,

src/idom/backend/flask.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from idom.core.types import ComponentType, RootComponentConstructor
3434
from idom.utils import Ref
3535

36+
from ._urls import ASSETS_PATH, MODULES_PATH, PATH_PREFIX, STREAM_PATH
3637
from .utils import (
3738
CLIENT_BUILD_DIR,
3839
safe_client_build_dir_path,
@@ -55,7 +56,7 @@ def configure(
5556
"""
5657
options = options or Options()
5758

58-
api_bp = Blueprint(f"idom_api_{id(app)}", __name__, url_prefix="/_idom")
59+
api_bp = Blueprint(f"idom_api_{id(app)}", __name__, url_prefix=str(PATH_PREFIX))
5960
spa_bp = Blueprint(f"idom_spa_{id(app)}", __name__, url_prefix=options.url_prefix)
6061

6162
_setup_single_view_dispatcher_route(api_bp, options, component)
@@ -161,11 +162,11 @@ def _setup_common_routes(
161162

162163
if options.serve_static_files:
163164

164-
@api_blueprint.route("/assets/<path:path>")
165+
@api_blueprint.route(f"/{ASSETS_PATH.name}/<path:path>")
165166
def send_assets_dir(path: str = "") -> Any:
166167
return send_file(safe_client_build_dir_path(f"assets/{path}"))
167168

168-
@api_blueprint.route("/modules/<path:path>")
169+
@api_blueprint.route(f"/{MODULES_PATH.name}/<path:path>")
169170
def send_modules_dir(path: str = "") -> Any:
170171
return send_file(safe_web_modules_dir_path(path))
171172

@@ -189,8 +190,8 @@ def recv() -> LayoutEvent:
189190

190191
_dispatch_in_thread(ws, path, constructor(), send, recv)
191192

192-
sock.route("stream", endpoint="without_path")(model_stream)
193-
sock.route("stream/<path:path>", endpoint="with_path")(model_stream)
193+
sock.route(STREAM_PATH.name, endpoint="without_path")(model_stream)
194+
sock.route(f"{STREAM_PATH.name}/<path:path>", endpoint="with_path")(model_stream)
194195

195196

196197
def _dispatch_in_thread(

src/idom/backend/sanic.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from idom.core.types import RootComponentConstructor
2626

2727
from ._asgi import serve_development_asgi
28+
from ._urls import ASSETS_PATH, MODULES_PATH, PATH_PREFIX, STREAM_PATH
2829
from .hooks import ConnectionContext
2930
from .hooks import use_connection as _use_connection
3031
from .utils import (
@@ -44,7 +45,7 @@ def configure(
4445
options = options or Options()
4546

4647
spa_bp = Blueprint(f"idom_spa_{id(app)}", url_prefix=options.url_prefix)
47-
api_bp = Blueprint(f"idom_api_{id(app)}", url_prefix="/_idom")
48+
api_bp = Blueprint(f"idom_api_{id(app)}", url_prefix=str(PATH_PREFIX))
4849

4950
_setup_common_routes(api_bp, spa_bp, options)
5051
_setup_single_view_dispatcher_route(api_bp, component, options)
@@ -133,7 +134,7 @@ async def asset_files(
133134
path = urllib_parse.unquote(path)
134135
return await response.file(safe_client_build_dir_path(f"assets/{path}"))
135136

136-
api_blueprint.add_route(asset_files, "/assets/<path:path>")
137+
api_blueprint.add_route(asset_files, f"/{ASSETS_PATH.name}/<path:path>")
137138

138139
async def web_module_files(
139140
request: request.Request,
@@ -146,7 +147,7 @@ async def web_module_files(
146147
mime_type="text/javascript",
147148
)
148149

149-
api_blueprint.add_route(web_module_files, "/modules/<path:path>")
150+
api_blueprint.add_route(web_module_files, f"/{MODULES_PATH.name}/<path:path>")
150151

151152

152153
def _setup_single_view_dispatcher_route(
@@ -189,8 +190,8 @@ async def model_stream(
189190
recv,
190191
)
191192

192-
api_blueprint.add_websocket_route(model_stream, "/stream")
193-
api_blueprint.add_websocket_route(model_stream, "/stream/<path:path>/")
193+
api_blueprint.add_websocket_route(model_stream, f"/{STREAM_PATH.name}")
194+
api_blueprint.add_websocket_route(model_stream, f"/{STREAM_PATH.name}/<path:path>/")
194195

195196

196197
def _make_send_recv_callbacks(

src/idom/backend/starlette.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from idom.core.types import RootComponentConstructor
2727

2828
from ._asgi import serve_development_asgi
29+
from ._urls import ASSETS_PATH, MODULES_PATH, STREAM_PATH
2930
from .hooks import ConnectionContext
3031
from .hooks import use_connection as _use_connection
3132
from .utils import CLIENT_BUILD_DIR
@@ -115,11 +116,11 @@ def _setup_common_routes(options: Options, app: Starlette) -> None:
115116

116117
if options.serve_static_files:
117118
app.mount(
118-
"/_idom/modules",
119+
str(MODULES_PATH),
119120
StaticFiles(directory=IDOM_WEB_MODULES_DIR.current, check_dir=False),
120121
)
121122
app.mount(
122-
"/_idom/assets",
123+
str(ASSETS_PATH),
123124
StaticFiles(directory=CLIENT_BUILD_DIR / "assets", check_dir=False),
124125
)
125126
# register this last so it takes least priority
@@ -134,8 +135,8 @@ async def serve_index(request: Request) -> FileResponse:
134135
def _setup_single_view_dispatcher_route(
135136
options: Options, app: Starlette, constructor: RootComponentConstructor
136137
) -> None:
137-
@app.websocket_route("/_idom/stream")
138-
@app.websocket_route("/_idom/stream/{path:path}")
138+
@app.websocket_route(str(STREAM_PATH))
139+
@app.websocket_route(f"{STREAM_PATH}/{{path:path}}")
139140
async def model_stream(socket: WebSocket) -> None:
140141
await socket.accept()
141142
send, recv = _make_send_recv_callbacks(socket)

src/idom/backend/tornado.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from idom.core.serve import VdomJsonPatch, serve_json_patch
2323
from idom.core.types import ComponentConstructor
2424

25+
from ._urls import ASSETS_PATH, MODULES_PATH, STREAM_PATH
2526
from .hooks import ConnectionContext
2627
from .hooks import use_connection as _use_connection
2728
from .utils import CLIENT_BUILD_DIR
@@ -117,15 +118,15 @@ def _setup_common_routes(options: Options) -> _RouteHandlerSpecs:
117118
if options.serve_static_files:
118119
handlers.append(
119120
(
120-
r"/_idom/modules/(.*)",
121+
rf"{MODULES_PATH}/(.*)",
121122
StaticFileHandler,
122123
{"path": str(IDOM_WEB_MODULES_DIR.current)},
123124
)
124125
)
125126

126127
handlers.append(
127128
(
128-
r"/_idom/assets/(.*)",
129+
rf"{ASSETS_PATH}/(.*)",
129130
StaticFileHandler,
130131
{"path": str(CLIENT_BUILD_DIR / "assets")},
131132
)
@@ -158,12 +159,12 @@ def _setup_single_view_dispatcher_route(
158159
) -> _RouteHandlerSpecs:
159160
return [
160161
(
161-
r"/_idom/stream/(.*)",
162+
rf"{STREAM_PATH}/(.*)",
162163
ModelStreamHandler,
163164
{"component_constructor": constructor},
164165
),
165166
(
166-
r"/_idom/stream",
167+
str(STREAM_PATH),
167168
ModelStreamHandler,
168169
{"component_constructor": constructor},
169170
),

src/idom/backend/types.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import asyncio
44
from dataclasses import dataclass
5-
from typing import Any, Generic, MutableMapping, TypeVar
5+
from typing import Any, Callable, Generic, MutableMapping, TypeVar
66

77
from typing_extensions import Protocol, runtime_checkable
88

@@ -16,6 +16,9 @@
1616
class BackendImplementation(Protocol[_App]):
1717
"""Common interface for built-in web server/framework integrations"""
1818

19+
Options: Callable[..., Any]
20+
"""A constructor for options passed to :meth:`BackendImplementation.configure`"""
21+
1922
def configure(
2023
self,
2124
app: _App,

tests/test_backend/test_common.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
from dataclasses import dataclass
12
from typing import MutableMapping
23

34
import pytest
45

56
import idom
67
from idom import html
78
from idom.backend import default as default_implementation
8-
from idom.backend.types import Connection, Location
9+
from idom.backend._urls import PATH_PREFIX
10+
from idom.backend.types import BackendImplementation, Connection, Location
911
from idom.backend.utils import all_implementations
1012
from idom.testing import BackendFixture, DisplayFixture, poll
1113

@@ -16,7 +18,12 @@
1618
scope="module",
1719
)
1820
async def display(page, request):
19-
async with BackendFixture(implementation=request.param) as server:
21+
imp: BackendImplementation = request.param
22+
async with BackendFixture(
23+
implementation=imp,
24+
# we do this to check that route priorities for each backend are correct
25+
options=imp.Options(url_prefix=str(PATH_PREFIX)),
26+
) as server:
2027
async with DisplayFixture(backend=server, driver=page) as display:
2128
yield display
2229

0 commit comments

Comments
 (0)