Skip to content

Commit 865d615

Browse files
committed
Capture query_parameters with wildcard routing
1 parent b4652eb commit 865d615

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
@@ -149,6 +149,7 @@ def _reset_match(self) -> None:
149149

150150
def _find_matching_path(self) -> RouteMatch | None:
151151
match: RouteMatch | None = None
152+
query_params: QueryParams | None = None
152153
relative_path = self._router.current_path[len(self._root_path or ''):]
153154
if not relative_path.startswith('/'):
154155
relative_path = '/' + relative_path
@@ -157,17 +158,22 @@ def _find_matching_path(self) -> RouteMatch | None:
157158
path = '/'.join(segments)
158159
if not path:
159160
path = '/'
160-
match = self._match_route(path)
161+
parsed_url = urlparse(path)
162+
163+
if query_params is None and parsed_url.query:
164+
query_params = QueryParams(parsed_url.query)
165+
166+
match = self._match_route(parsed_url, query_params)
161167
if match is not None:
162168
match.remaining_path = urlparse(relative_path).path.rstrip('/')[len(match.path):]
163169
break
164170
segments.pop()
165171
return match
166172

167-
def _match_route(self, path: str) -> RouteMatch | None:
168-
parsed_url = urlparse(path)
173+
def _match_route(self, parsed_url: ParseResult, query_params: QueryParams | None) -> RouteMatch | None:
169174
path_only = parsed_url.path.rstrip('/')
170-
query_params = QueryParams(parsed_url.query) if parsed_url.query else QueryParams()
175+
if query_params is None:
176+
query_params = QueryParams(parsed_url.query) if parsed_url.query else QueryParams()
171177
fragment = parsed_url.fragment
172178
if not path_only.startswith('/'):
173179
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)