Skip to content

Commit 2119fb1

Browse files
committed
Reduce dependencies by making ASGI optional
1 parent 5afa28b commit 2119fb1

File tree

13 files changed

+116
-132
lines changed

13 files changed

+116
-132
lines changed

docs/source/about/changelog.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ Unreleased
1616
----------
1717

1818
**Added**
19-
- :pull:`1113` - Added ``reactpy.ReactPy`` that can be used to run ReactPy in standalone mode.
20-
- :pull:`1113` - Added ``reactpy.ReactPyMiddleware`` that can be used to run ReactPy with any ASGI compatible framework.
19+
- :pull:`1113` - Added ``reactpy.asgi.ReactPy`` that can be used to run ReactPy in standalone mode via ASGI.
20+
- :pull:`1113` - Added ``reactpy.asgi.ReactPyMiddleware`` that can be used to utilize ReactPy within any ASGI compatible framework.
2121
- :pull:`1113` - Added ``reactpy.templatetags.Jinja`` that can be used alongside ``ReactPyMiddleware`` to embed several ReactPy components into your existing application.
2222
- :pull:`1113` - Added ``uvicorn`` and ``jinja`` installation extras (for example ``pip install reactpy[jinja]``).
2323
- :pull:`1113` - Added support for Python 3.12 and 3.13.

pyproject.toml

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,21 @@ classifiers = [
2828
"Programming Language :: Python :: Implementation :: PyPy",
2929
]
3030
dependencies = [
31-
"exceptiongroup >=1.0",
32-
"typing-extensions >=3.10",
33-
"anyio >=3",
3431
"fastjsonschema >=2.14.5",
3532
"requests >=2",
36-
"asgiref >=3",
3733
"lxml >=4",
38-
"servestatic >=3.0.0",
39-
"orjson >=3",
40-
"asgi-tools",
34+
"anyio >=3",
35+
"typing-extensions >=3.10",
4136
]
4237
dynamic = ["version"]
4338
urls.Changelog = "https://reactpy.dev/docs/about/changelog.html"
4439
urls.Documentation = "https://reactpy.dev/"
4540
urls.Source = "https://github.com/reactive-python/reactpy"
4641

4742
[project.optional-dependencies]
48-
all = ["reactpy[jinja,uvicorn,testing]"]
43+
all = ["reactpy[asgi,jinja,uvicorn,testing]"]
44+
standard = ["reactpy[asgi]"]
45+
asgi = ["asgiref", "asgi-tools", "servestatic", "orjson"]
4946
jinja = ["jinja2-simple-tags", "jinja2 >=3"]
5047
uvicorn = ["uvicorn[standard]"]
5148
testing = ["playwright"]
@@ -91,14 +88,12 @@ artifacts = []
9188

9289
[tool.hatch.envs.hatch-test]
9390
extra-dependencies = [
91+
"reactpy[all]",
9492
"pytest-sugar",
9593
"pytest-asyncio",
9694
"responses",
97-
"playwright",
95+
"exceptiongroup",
9896
"jsonpointer",
99-
"uvicorn[standard]",
100-
"jinja2-simple-tags",
101-
"jinja2",
10297
"starlette",
10398
]
10499

@@ -158,6 +153,7 @@ serve = [
158153

159154
[tool.hatch.envs.python]
160155
extra-dependencies = [
156+
"reactpy[all]",
161157
"ruff",
162158
"toml",
163159
"mypy==1.8",

src/reactpy/__init__.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
from reactpy import asgi, config, logging, types, web, widgets
1+
from reactpy import config, logging, types, web, widgets
22
from reactpy._html import html
3-
from reactpy.asgi.executors.standalone import ReactPy
4-
from reactpy.asgi.middleware import ReactPyMiddleware
53
from reactpy.core import hooks
64
from reactpy.core.component import component
75
from reactpy.core.events import event
@@ -29,10 +27,7 @@
2927

3028
__all__ = [
3129
"Layout",
32-
"ReactPy",
33-
"ReactPyMiddleware",
3430
"Ref",
35-
"asgi",
3631
"component",
3732
"config",
3833
"create_context",

src/reactpy/asgi/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from reactpy.asgi.executors.pyscript import ReactPyCSR
2+
from reactpy.asgi.executors.standalone import ReactPy
3+
from reactpy.asgi.middleware import ReactPyMiddleware
4+
5+
__all__ = ["ReactPy", "ReactPyCSR", "ReactPyMiddleware"]

src/reactpy/asgi/executors/pyscript.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@
1616
from reactpy.asgi.middleware import ReactPyMiddleware
1717
from reactpy.asgi.utils import vdom_head_to_html
1818
from reactpy.pyscript.utils import pyscript_component_html, pyscript_setup_html
19-
from reactpy.types import (
20-
ReactPyConfig,
21-
VdomDict,
22-
)
19+
from reactpy.types import ReactPyConfig, VdomDict
2320

2421

2522
class ReactPyCSR(ReactPy):

src/reactpy/asgi/executors/standalone.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,9 @@
1414

1515
from reactpy import html
1616
from reactpy.asgi.middleware import ReactPyMiddleware
17+
from reactpy.asgi.types import AsgiApp, AsgiHttpApp, AsgiLifespanApp, AsgiWebsocketApp
1718
from reactpy.asgi.utils import import_dotted_path, vdom_head_to_html
18-
from reactpy.types import (
19-
AsgiApp,
20-
AsgiHttpApp,
21-
AsgiLifespanApp,
22-
AsgiWebsocketApp,
23-
ReactPyConfig,
24-
RootComponentConstructor,
25-
VdomDict,
26-
)
19+
from reactpy.types import ReactPyConfig, RootComponentConstructor, VdomDict
2720
from reactpy.utils import asgi_component_html
2821

2922
_logger = getLogger(__name__)

src/reactpy/asgi/middleware.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,19 @@
1818
from typing_extensions import Unpack
1919

2020
from reactpy import config
21-
from reactpy.asgi.utils import check_path, import_components, process_settings
22-
from reactpy.core.hooks import ConnectionContext
23-
from reactpy.core.layout import Layout
24-
from reactpy.core.serve import serve_layout
25-
from reactpy.types import (
21+
from reactpy.asgi.types import (
2622
AsgiApp,
2723
AsgiHttpApp,
2824
AsgiLifespanApp,
2925
AsgiWebsocketApp,
3026
AsgiWebsocketReceive,
3127
AsgiWebsocketSend,
32-
Connection,
33-
Location,
34-
ReactPyConfig,
35-
RootComponentConstructor,
3628
)
29+
from reactpy.asgi.utils import check_path, import_components, process_settings
30+
from reactpy.core.hooks import ConnectionContext
31+
from reactpy.core.layout import Layout
32+
from reactpy.core.serve import serve_layout
33+
from reactpy.types import Connection, Location, ReactPyConfig, RootComponentConstructor
3734

3835
_logger = logging.getLogger(__name__)
3936

@@ -222,7 +219,7 @@ async def run_dispatcher(self) -> None:
222219
self.scope["query_string"].decode(), strict_parsing=True
223220
)
224221
connection = Connection(
225-
scope=self.scope,
222+
scope=self.scope, # type: ignore
226223
location=Location(
227224
path=ws_query_string.get("http_pathname", [""])[0],
228225
query_string=ws_query_string.get("http_query_string", [""])[0],

src/reactpy/asgi/types.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"""These types are separated from the main module to avoid dependency issues."""
2+
3+
from __future__ import annotations
4+
5+
from collections.abc import Awaitable
6+
from typing import Callable, Union
7+
8+
from asgiref import typing as asgi_types
9+
10+
AsgiHttpReceive = Callable[
11+
[],
12+
Awaitable[asgi_types.HTTPRequestEvent | asgi_types.HTTPDisconnectEvent],
13+
]
14+
15+
AsgiHttpSend = Callable[
16+
[
17+
asgi_types.HTTPResponseStartEvent
18+
| asgi_types.HTTPResponseBodyEvent
19+
| asgi_types.HTTPResponseTrailersEvent
20+
| asgi_types.HTTPServerPushEvent
21+
| asgi_types.HTTPDisconnectEvent
22+
],
23+
Awaitable[None],
24+
]
25+
26+
AsgiWebsocketReceive = Callable[
27+
[],
28+
Awaitable[
29+
asgi_types.WebSocketConnectEvent
30+
| asgi_types.WebSocketDisconnectEvent
31+
| asgi_types.WebSocketReceiveEvent
32+
],
33+
]
34+
35+
AsgiWebsocketSend = Callable[
36+
[
37+
asgi_types.WebSocketAcceptEvent
38+
| asgi_types.WebSocketSendEvent
39+
| asgi_types.WebSocketResponseStartEvent
40+
| asgi_types.WebSocketResponseBodyEvent
41+
| asgi_types.WebSocketCloseEvent
42+
],
43+
Awaitable[None],
44+
]
45+
46+
AsgiLifespanReceive = Callable[
47+
[],
48+
Awaitable[asgi_types.LifespanStartupEvent | asgi_types.LifespanShutdownEvent],
49+
]
50+
51+
AsgiLifespanSend = Callable[
52+
[
53+
asgi_types.LifespanStartupCompleteEvent
54+
| asgi_types.LifespanStartupFailedEvent
55+
| asgi_types.LifespanShutdownCompleteEvent
56+
| asgi_types.LifespanShutdownFailedEvent
57+
],
58+
Awaitable[None],
59+
]
60+
61+
AsgiHttpApp = Callable[
62+
[asgi_types.HTTPScope, AsgiHttpReceive, AsgiHttpSend],
63+
Awaitable[None],
64+
]
65+
66+
AsgiWebsocketApp = Callable[
67+
[asgi_types.WebSocketScope, AsgiWebsocketReceive, AsgiWebsocketSend],
68+
Awaitable[None],
69+
]
70+
71+
AsgiLifespanApp = Callable[
72+
[asgi_types.LifespanScope, AsgiLifespanReceive, AsgiLifespanSend],
73+
Awaitable[None],
74+
]
75+
76+
77+
AsgiApp = Union[AsgiHttpApp, AsgiWebsocketApp, AsgiLifespanApp]

src/reactpy/core/hooks.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
overload,
1717
)
1818

19-
from asgiref import typing as asgi_types
2019
from typing_extensions import TypeAlias
2120

2221
from reactpy.config import REACTPY_DEBUG
@@ -25,9 +24,11 @@
2524
from reactpy.utils import Ref
2625

2726
if not TYPE_CHECKING:
28-
# make flake8 think that this variable exists
2927
ellipsis = type(...)
3028

29+
if TYPE_CHECKING:
30+
from asgiref import typing as asgi_types
31+
3132

3233
__all__ = [
3334
"use_async_effect",
@@ -339,7 +340,7 @@ def use_connection() -> Connection[Any]:
339340

340341
def use_scope() -> asgi_types.HTTPScope | asgi_types.WebSocketScope:
341342
"""Get the current :class:`~reactpy.types.Connection`'s scope."""
342-
return use_connection().scope
343+
return use_connection().scope # type: ignore
343344

344345

345346
def use_location() -> Location:

src/reactpy/logging.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,7 @@
1818
"stream": sys.stdout,
1919
}
2020
},
21-
"formatters": {
22-
"generic": {
23-
"format": "%(asctime)s | %(log_color)s%(levelname)s%(reset)s | %(message)s",
24-
"datefmt": r"%Y-%m-%dT%H:%M:%S%z",
25-
}
26-
},
21+
"formatters": {"generic": {"datefmt": r"%Y-%m-%dT%H:%M:%S%z"}},
2722
}
2823
)
2924

0 commit comments

Comments
 (0)