Skip to content

Commit a992b33

Browse files
committed
Capture query_parameters with wildcard routing
1 parent 93b6553 commit a992b33

File tree

2 files changed

+30
-7
lines changed

2 files changed

+30
-7
lines changed

nicegui/elements/sub_pages.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import inspect
55
import re
66
from typing import Any, Callable
7-
from urllib.parse import urlparse
7+
from urllib.parse import urlparse, ParseResult
88

99
from starlette.datastructures import QueryParams
1010
from typing_extensions import Self
@@ -147,6 +147,7 @@ def _reset_match(self) -> None:
147147

148148
def _find_matching_path(self) -> RouteMatch | None:
149149
match: RouteMatch | None = None
150+
query_params: QueryParams | None = None
150151
relative_path = self._router.current_path[len(self._root_path or ''):]
151152
if not relative_path.startswith('/'):
152153
relative_path = '/' + relative_path
@@ -155,17 +156,22 @@ def _find_matching_path(self) -> RouteMatch | None:
155156
path = '/'.join(segments)
156157
if not path:
157158
path = '/'
158-
match = self._match_route(path)
159+
parsed_url = urlparse(path)
160+
161+
if query_params is None and parsed_url.query:
162+
query_params = QueryParams(parsed_url.query)
163+
164+
match = self._match_route(parsed_url, query_params)
159165
if match is not None:
160166
match.remaining_path = urlparse(relative_path).path.rstrip('/')[len(match.path):]
161167
break
162168
segments.pop()
163169
return match
164170

165-
def _match_route(self, path: str) -> RouteMatch | None:
166-
parsed_url = urlparse(path)
171+
def _match_route(self, parsed_url: ParseResult, query_params: QueryParams | None) -> RouteMatch | None:
167172
path_only = parsed_url.path.rstrip('/')
168-
query_params = QueryParams(parsed_url.query) if parsed_url.query else QueryParams()
173+
if query_params is None:
174+
query_params = QueryParams(parsed_url.query) if parsed_url.query else QueryParams()
169175
fragment = parsed_url.fragment
170176
if not path_only.startswith('/'):
171177
path_only = '/' + path_only

tests/test_sub_pages.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -693,15 +693,16 @@ async def main(delay: float = 0):
693693

694694

695695
@pytest.mark.parametrize('use_page_arguments', [True, False])
696-
def test_sub_page_with_query_parameters(screen: Screen, use_page_arguments: bool):
696+
@pytest.mark.parametrize('show_404', [True, False])
697+
def test_sub_page_with_query_parameters(screen: Screen, use_page_arguments: bool, show_404: bool):
697698
calls = {'index': 0, 'main_content': 0}
698699

699700
@ui.page('/')
700701
def index():
701702
calls['index'] += 1
702703
ui.link('Link to main', '/?access=link')
703704
ui.button('Button to main', on_click=lambda: ui.navigate.to('/?access=button'))
704-
ui.sub_pages({'/': with_page_arguments if use_page_arguments else with_parameter})
705+
ui.sub_pages({'/': with_page_arguments if use_page_arguments else with_parameter}, show_404=show_404)
705706

706707
def with_page_arguments(args: PageArguments):
707708
calls['main_content'] += 1
@@ -1250,3 +1251,19 @@ def sub_page(args: PageArguments):
12501251

12511252
screen.open('/sub/x/2/a')
12521253
screen.should_contain('remaining=/x/2/a')
1254+
1255+
1256+
def test_query_parameters_wildcard_routing(screen: Screen):
1257+
@ui.page('/')
1258+
@ui.page('/{_:path}')
1259+
def index():
1260+
ui.sub_pages({'/sub': sub_page}, show_404=False)
1261+
1262+
def sub_page(args: PageArguments):
1263+
ui.label(f'query_parameters={args.query_parameters}')
1264+
1265+
screen.open('/sub?color=red')
1266+
screen.should_contain('query_parameters=color=red')
1267+
1268+
screen.open('/sub/x/2/a?color=blue')
1269+
screen.should_contain('query_parameters=color=blue')

0 commit comments

Comments
 (0)