Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 64c9e82

Browse filesBrowse files
authored
add use_connection hook (#823)
* add use_connection hook * add changelog entry * upgrade uvicorn * fix type annotation * remove unused imports * update docstring * increase type delay * configure default delay
1 parent 50e42c0 commit 64c9e82
Copy full SHA for 64c9e82

20 files changed

+276
-191
lines changed

‎docs/source/_custom_js/package-lock.json

Copy file name to clipboardExpand all lines: docs/source/_custom_js/package-lock.json
+3-3Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎docs/source/about/changelog.rst

Copy file name to clipboardExpand all lines: docs/source/about/changelog.rst
+12-1Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,18 @@ more info, see the :ref:`Contributor Guide <Creating a Changelog Entry>`.
2323
Unreleased
2424
----------
2525

26-
No changes.
26+
**Changed**
27+
28+
- :pull:`823` - The hooks ``use_location`` and ``use_scope`` are no longer
29+
implementation specific and are now available as top-level imports. Instead of each
30+
backend defining these hooks, backends establish a ``ConnectionContext`` with this
31+
information.
32+
33+
**Added**
34+
35+
- :pull:`823` - There is a new ``use_connection`` hook which returns a ``Connection``
36+
object. This ``Connection`` object contains a ``location`` and ``scope``, along with
37+
a ``carrier`` which is unique to each backend implementation.
2738

2839

2940
v0.40.2

‎requirements/pkg-extras.txt

Copy file name to clipboardExpand all lines: requirements/pkg-extras.txt
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# extra=starlette
22
starlette >=0.13.6
3-
uvicorn[standard] >=0.13.4
3+
uvicorn[standard] >=0.19.0
44

55
# extra=sanic
66
sanic >=21
77
sanic-cors
88

99
# extra=fastapi
1010
fastapi >=0.63.0
11-
uvicorn[standard] >=0.13.4
11+
uvicorn[standard] >=0.19.0
1212

1313
# extra=flask
1414
flask

‎src/idom/__init__.py

Copy file name to clipboardExpand all lines: src/idom/__init__.py
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from . import backend, config, html, logging, sample, types, web
2+
from .backend.hooks import use_connection, use_location, use_scope
23
from .backend.utils import run
34
from .core import hooks
45
from .core.component import component
@@ -25,6 +26,7 @@
2526
__version__ = "0.40.2" # DO NOT MODIFY
2627

2728
__all__ = [
29+
"backend",
2830
"component",
2931
"config",
3032
"create_context",
@@ -38,16 +40,18 @@
3840
"Ref",
3941
"run",
4042
"sample",
41-
"backend",
4243
"Stop",
4344
"types",
4445
"use_callback",
46+
"use_connection",
4547
"use_context",
4648
"use_debug_value",
4749
"use_effect",
50+
"use_location",
4851
"use_memo",
4952
"use_reducer",
5053
"use_ref",
54+
"use_scope",
5155
"use_state",
5256
"vdom",
5357
"web",

‎src/idom/backend/_asgi.py

Copy file name to clipboardExpand all lines: src/idom/backend/_asgi.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ async def serve_development_asgi(
2121
host=host,
2222
port=port,
2323
loop="asyncio",
24-
debug=True,
24+
reload=True,
2525
)
2626
)
2727

‎src/idom/backend/default.py

Copy file name to clipboardExpand all lines: src/idom/backend/default.py
+1-11Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from idom.types import RootComponentConstructor
77

8-
from .types import BackendImplementation, Location
8+
from .types import BackendImplementation
99
from .utils import all_implementations
1010

1111

@@ -35,16 +35,6 @@ async def serve_development_app(
3535
)
3636

3737

38-
def use_scope() -> Any:
39-
"""Return the current ASGI/WSGI scope"""
40-
return _default_implementation().use_scope()
41-
42-
43-
def use_location() -> Location:
44-
"""Return the current route as a string"""
45-
return _default_implementation().use_location()
46-
47-
4838
_DEFAULT_IMPLEMENTATION: BackendImplementation[Any] | None = None
4939

5040

‎src/idom/backend/fastapi.py

Copy file name to clipboardExpand all lines: src/idom/backend/fastapi.py
+2-8Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,10 @@
88
serve_development_app = starlette.serve_development_app
99
"""Alias for :func:`idom.backend.starlette.serve_development_app`"""
1010

11-
# see: https://github.com/idom-team/flake8-idom-hooks/issues/12
12-
use_location = starlette.use_location # noqa: ROH101
11+
use_connection = starlette.use_connection
1312
"""Alias for :func:`idom.backend.starlette.use_location`"""
1413

15-
# see: https://github.com/idom-team/flake8-idom-hooks/issues/12
16-
use_scope = starlette.use_scope # noqa: ROH101
17-
"""Alias for :func:`idom.backend.starlette.use_scope`"""
18-
19-
# see: https://github.com/idom-team/flake8-idom-hooks/issues/12
20-
use_websocket = starlette.use_websocket # noqa: ROH101
14+
use_websocket = starlette.use_websocket
2115
"""Alias for :func:`idom.backend.starlette.use_websocket`"""
2216

2317
Options = starlette.Options

‎src/idom/backend/flask.py

Copy file name to clipboardExpand all lines: src/idom/backend/flask.py
+36-37Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@
2525
from werkzeug.serving import BaseWSGIServer, make_server
2626

2727
import idom
28-
from idom.backend.types import Location
29-
from idom.core.hooks import Context, create_context, use_context
28+
from idom.backend.hooks import ConnectionContext
29+
from idom.backend.hooks import use_connection as _use_connection
30+
from idom.backend.types import Connection, Location
3031
from idom.core.layout import LayoutEvent, LayoutUpdate
3132
from idom.core.serve import serve_json_patch
3233
from idom.core.types import ComponentType, RootComponentConstructor
@@ -37,8 +38,6 @@
3738

3839
logger = logging.getLogger(__name__)
3940

40-
ConnectionContext: Context[Connection | None] = create_context(None)
41-
4241

4342
def configure(
4443
app: Flask, component: RootComponentConstructor, options: Options | None = None
@@ -107,45 +106,25 @@ def run_server() -> None:
107106
raise RuntimeError("Failed to shutdown server.")
108107

109108

110-
def use_location() -> Location:
111-
"""Get the current route as a string"""
112-
conn = use_connection()
113-
search = conn.request.query_string.decode()
114-
return Location(pathname="/" + conn.path, search="?" + search if search else "")
115-
116-
117-
def use_scope() -> dict[str, Any]:
118-
"""Get the current WSGI environment"""
119-
return use_request().environ
109+
def use_websocket() -> WebSocket:
110+
"""A handle to the current websocket"""
111+
return use_connection().carrier.websocket
120112

121113

122114
def use_request() -> Request:
123115
"""Get the current ``Request``"""
124-
return use_connection().request
116+
return use_connection().carrier.request
125117

126118

127-
def use_connection() -> Connection:
119+
def use_connection() -> Connection[_FlaskCarrier]:
128120
"""Get the current :class:`Connection`"""
129-
connection = use_context(ConnectionContext)
130-
if connection is None:
131-
raise RuntimeError( # pragma: no cover
132-
"No connection. Are you running with a Flask server?"
121+
conn = _use_connection()
122+
if not isinstance(conn.carrier, _FlaskCarrier):
123+
raise TypeError( # pragma: no cover
124+
f"Connection has unexpected carrier {conn.carrier}. "
125+
"Are you running with a Flask server?"
133126
)
134-
return connection
135-
136-
137-
@dataclass
138-
class Connection:
139-
"""A simple wrapper for holding connection information"""
140-
141-
request: Request
142-
"""The current request object"""
143-
144-
websocket: WebSocket
145-
"""A handle to the current websocket"""
146-
147-
path: str
148-
"""The current path being served"""
127+
return conn
149128

150129

151130
@dataclass
@@ -230,11 +209,20 @@ async def recv_coro() -> Any:
230209
return await async_recv_queue.get()
231210

232211
async def main() -> None:
212+
search = request.query_string.decode()
233213
await serve_json_patch(
234214
idom.Layout(
235215
ConnectionContext(
236-
component, value=Connection(request, websocket, path)
237-
)
216+
component,
217+
value=Connection(
218+
scope=request.environ,
219+
location=Location(
220+
pathname=f"/{path}",
221+
search=f"?{search}" if search else "",
222+
),
223+
carrier=_FlaskCarrier(request, websocket),
224+
),
225+
),
238226
),
239227
send_coro,
240228
recv_coro,
@@ -283,3 +271,14 @@ class _DispatcherThreadInfo(NamedTuple):
283271
dispatch_future: "asyncio.Future[Any]"
284272
thread_send_queue: "ThreadQueue[LayoutUpdate]"
285273
async_recv_queue: "AsyncQueue[LayoutEvent]"
274+
275+
276+
@dataclass
277+
class _FlaskCarrier:
278+
"""A simple wrapper for holding a Flask request and WebSocket"""
279+
280+
request: Request
281+
"""The current request object"""
282+
283+
websocket: WebSocket
284+
"""A handle to the current websocket"""

‎src/idom/backend/hooks.py

Copy file name to clipboard
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from __future__ import annotations
2+
3+
from typing import Any, MutableMapping
4+
5+
from idom.core.hooks import Context, create_context, use_context
6+
7+
from .types import Connection, Location
8+
9+
10+
# backend implementations should establish this context at the root of an app
11+
ConnectionContext: Context[Connection[Any] | None] = create_context(None)
12+
13+
14+
def use_connection() -> Connection[Any]:
15+
conn = use_context(ConnectionContext)
16+
if conn is None:
17+
raise RuntimeError("No backend established a connection.") # pragma: no cover
18+
return conn
19+
20+
21+
def use_scope() -> MutableMapping[str, Any]:
22+
return use_connection().scope
23+
24+
25+
def use_location() -> Location:
26+
return use_connection().location

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.