Skip to content

Commit 8cde76e

Browse files
committed
add url and route_id to routerdata as a replacement for pagedata
1 parent 09ed66c commit 8cde76e

6 files changed

Lines changed: 75 additions & 22 deletions

File tree

reflex/.templates/web/utils/state.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,10 @@ export const applyEvent = async (event, socket, navigate, params) => {
370370
...Object.fromEntries(new URLSearchParams(window.location.search)),
371371
...params(),
372372
},
373-
asPath: window.location.pathname + window.location.search,
373+
asPath:
374+
window.location.pathname +
375+
window.location.search +
376+
window.location.hash,
374377
};
375378
}
376379

reflex/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1741,7 +1741,7 @@ async def process(
17411741
if (path := router_data.get(constants.RouteVar.PATH))
17421742
else "404"
17431743
).removeprefix("/")
1744-
state.router = RouterData(router_data)
1744+
state.router = RouterData.from_router_data(router_data)
17451745

17461746
# Preprocess the event.
17471747
update = await app._preprocess(state, event)

reflex/istate/data.py

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import dataclasses
44
from collections.abc import Mapping
5+
from typing import TYPE_CHECKING
6+
from urllib.parse import _NetlocResultMixinStr, urlsplit
57

68
from reflex import constants
79
from reflex.utils import format
@@ -90,6 +92,35 @@ def serialize_frozen_dict_str_str(obj: _FrozenDictStrStr) -> dict:
9092
return dict(obj._data)
9193

9294

95+
class ReflexURL(str, _NetlocResultMixinStr):
96+
"""A class representing a URL split result."""
97+
98+
if TYPE_CHECKING:
99+
scheme: str
100+
netloc: str
101+
path: str
102+
query: str
103+
fragment: str
104+
105+
def __new__(cls, url: str):
106+
"""Create a new ReflexURL instance.
107+
108+
Args:
109+
url: the URL to split.
110+
111+
Returns:
112+
A new ReflexURL instance.
113+
"""
114+
(scheme, netloc, path, query, fragment) = urlsplit(url)
115+
obj = super().__new__(cls, url)
116+
object.__setattr__(obj, "scheme", scheme)
117+
object.__setattr__(obj, "netloc", netloc)
118+
object.__setattr__(obj, "path", path)
119+
object.__setattr__(obj, "query", query)
120+
object.__setattr__(obj, "fragment", fragment)
121+
return obj
122+
123+
93124
@dataclasses.dataclass(frozen=True)
94125
class PageData:
95126
"""An object containing page data."""
@@ -158,20 +189,33 @@ def __init__(self, router_data: dict | None = None):
158189
object.__setattr__(self, "session_id", session_id)
159190

160191

161-
@dataclasses.dataclass(frozen=True, init=False)
192+
@dataclasses.dataclass(frozen=True)
162193
class RouterData:
163194
"""An object containing RouterData."""
164195

165196
session: SessionData = dataclasses.field(default_factory=SessionData)
166197
headers: HeaderData = dataclasses.field(default_factory=HeaderData)
167198
page: PageData = dataclasses.field(default_factory=PageData)
199+
url: ReflexURL = dataclasses.field(default=ReflexURL(""))
200+
route_id: str = ""
168201

169-
def __init__(self, router_data: dict | None = None):
170-
"""Initialize the RouterData object.
202+
@classmethod
203+
def from_router_data(cls, router_data: dict) -> "RouterData":
204+
"""Create a RouterData object from the given router_data.
171205
172206
Args:
173207
router_data: the router_data dict.
208+
209+
Returns:
210+
A RouterData object initialized with the provided router_data.
174211
"""
175-
object.__setattr__(self, "session", SessionData(router_data))
176-
object.__setattr__(self, "headers", HeaderData(router_data))
177-
object.__setattr__(self, "page", PageData(router_data))
212+
return cls(
213+
session=SessionData(router_data),
214+
headers=HeaderData(router_data),
215+
page=PageData(router_data),
216+
url=ReflexURL(
217+
router_data.get(constants.RouteVar.HEADERS, {}).get("origin", "")
218+
+ router_data.get(constants.RouteVar.ORIGIN, "")
219+
),
220+
route_id=router_data.get(constants.RouteVar.PATH, ""),
221+
)

tests/units/test_app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,7 @@ def _dynamic_state_event(name, val, **kwargs):
10851085
"token": token,
10861086
**on_load_internal.router_data,
10871087
}
1088-
exp_router = RouterData(exp_router_data)
1088+
exp_router = RouterData.from_router_data(exp_router_data)
10891089
process_coro = process(
10901090
app,
10911091
event=on_load_internal,

tests/units/test_state.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070

7171

7272
formatted_router = {
73+
"route_id": "",
74+
"url": "",
7375
"session": {"client_token": "", "client_ip": "", "session_id": ""},
7476
"headers": {
7577
"host": "",
@@ -885,7 +887,7 @@ def test_get_client_token(test_state, router_data):
885887
test_state: The test state.
886888
router_data: The router data fixture.
887889
"""
888-
test_state.router = RouterData(router_data)
890+
test_state.router = RouterData.from_router_data(router_data)
889891
assert (
890892
test_state.router.session.client_token == "b181904c-3953-4a79-dc18-ae9518c22f05"
891893
)
@@ -898,7 +900,7 @@ def test_get_sid(test_state, router_data):
898900
test_state: A state.
899901
router_data: The router data fixture.
900902
"""
901-
test_state.router = RouterData(router_data)
903+
test_state.router = RouterData.from_router_data(router_data)
902904
assert test_state.router.session.session_id == "9fpxSzPb9aFMb4wFAAAH"
903905

904906

@@ -911,7 +913,7 @@ def test_get_headers(test_state, router_data, router_data_headers):
911913
router_data_headers: The expected headers.
912914
"""
913915
print(router_data_headers)
914-
test_state.router = RouterData(router_data)
916+
test_state.router = RouterData.from_router_data(router_data)
915917
print(test_state.router.headers)
916918
assert dataclasses.asdict(test_state.router.headers) == {
917919
format.to_snake_case(k): v for k, v in router_data_headers.items()
@@ -929,23 +931,23 @@ def test_get_client_ip(test_state, router_data):
929931
test_state: A state.
930932
router_data: The router data fixture.
931933
"""
932-
test_state.router = RouterData(router_data)
934+
test_state.router = RouterData.from_router_data(router_data)
933935
assert test_state.router.session.client_ip == "127.0.0.1"
934936

935937

936938
def test_get_current_page(test_state):
937939
assert test_state.router.page.path == ""
938940

939941
route = "mypage/subpage"
940-
test_state.router = RouterData({RouteVar.PATH: route})
942+
test_state.router = RouterData.from_router_data({RouteVar.PATH: route})
941943
assert test_state.router.page.path == route
942944

943945

944946
def test_get_query_params(test_state):
945947
assert test_state.router.page.params == {}
946948

947949
params = {"p1": "a", "p2": "b"}
948-
test_state.router = RouterData({RouteVar.QUERY: params})
950+
test_state.router = RouterData.from_router_data({RouteVar.QUERY: params})
949951
assert dict(test_state.router.page.params) == params
950952

951953

@@ -1996,7 +1998,9 @@ async def test_state_proxy(
19961998
assert child_state is not None
19971999
parent_state = child_state.parent_state
19982000
assert parent_state is not None
1999-
router_data = RouterData({"query": {}, "token": token, "sid": "test_sid"})
2001+
router_data = RouterData.from_router_data(
2002+
{"query": {}, "token": token, "sid": "test_sid"}
2003+
)
20002004
grandchild_state.router = router_data
20012005
namespace = mock_app.event_namespace
20022006
assert namespace is not None
@@ -2707,12 +2711,12 @@ class MutableContainsBase(BaseState):
27072711
dict_val[MutableContainsBase.get_full_name()]["items" + FIELD_MARKER][0], Foo
27082712
)
27092713
val = json_dumps(dict_val)
2710-
f_items = '[{"tags": ["123", "456"]}]'
2711-
f_formatted_router = str(formatted_router).replace("'", '"')
2712-
assert (
2713-
val
2714-
== f'{{"{MutableContainsBase.get_full_name()}": {{"items{FIELD_MARKER}": {f_items}, "router{FIELD_MARKER}": {f_formatted_router}}}}}'
2715-
)
2714+
assert json.loads(val) == {
2715+
MutableContainsBase.get_full_name(): {
2716+
f"items{FIELD_MARKER}": [{"tags": ["123", "456"]}],
2717+
f"router{FIELD_MARKER}": formatted_router,
2718+
}
2719+
}
27162720

27172721

27182722
def test_reset_with_mutables():

tests/units/utils/test_format.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,8 @@ def test_format_query_params(input, output):
548548

549549

550550
formatted_router = {
551+
"route_id": "",
552+
"url": "",
551553
"session": {"client_token": "", "client_ip": "", "session_id": ""},
552554
"headers": {
553555
"host": "",

0 commit comments

Comments
 (0)