Skip to content

Commit d76a0e7

Browse files
committed
first shot at getting correct http status codes
even in when sub page builder is async
1 parent b8e452b commit d76a0e7

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

nicegui/page.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,7 @@ async def decorated(*dec_args, **dec_kwargs) -> Response:
145145
dec_kwargs['client'] = client
146146
try:
147147
result = func(*dec_args, **dec_kwargs)
148-
# NOTE: after building the page, there might be sub pages that have 404 -- and initial requests should send 404 status request in such cases
149-
sub_pages_elements = [e for e in client.elements.values() if isinstance(e, SubPages)]
150-
if any(sub_pages.has_404 for sub_pages in sub_pages_elements):
151-
raise HTTPException(404, f'{client.sub_pages_router.current_path} not found')
148+
await self._await_sub_pages_and_raise_404(client)
152149
except Exception as e:
153150
return create_error_page(e, request)
154151
if helpers.is_coroutine_function(func):
@@ -174,6 +171,7 @@ async def wait_for_result() -> Optional[Response]:
174171
else:
175172
result = None
176173
task.add_done_callback(check_for_late_return_value)
174+
await self._await_sub_pages_and_raise_404(client)
177175
if isinstance(result, Response): # NOTE if setup returns a response, we don't need to render the page
178176
return result
179177
binding._refresh_step() # pylint: disable=protected-access
@@ -192,3 +190,13 @@ async def wait_for_result() -> Optional[Response]:
192190
self.api_router.get(self._path, **self.kwargs)(decorated)
193191
Client.page_routes[func] = self.path
194192
return func
193+
194+
@staticmethod
195+
async def _await_sub_pages_and_raise_404(client: Client) -> None:
196+
"""Some sub pages might finish async and decide 404"""
197+
sub_pages_elements = [e for e in client.elements.values() if isinstance(e, SubPages)]
198+
if any(sp._active_tasks for sp in sub_pages_elements): # pylint: disable=protected-access
199+
await asyncio.sleep(0) # NOTE: give background tasks a brief chance to schedule nested sub pages
200+
sub_pages_elements = [e for e in client.elements.values() if isinstance(e, SubPages)]
201+
if any(sp.has_404 for sp in sub_pages_elements):
202+
raise HTTPException(404, f'{client.sub_pages_router.current_path} not found')

tests/test_sub_pages.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,8 +1087,12 @@ def main():
10871087
ui.label('main page')
10881088

10891089
screen.open('/bad_path')
1090-
screen.should_contain('HTTPException: 404: /bad_path not found')
10911090
assert httpx.get(f'http://localhost:{Screen.PORT}/bad_path').status_code == 404
1091+
screen.should_contain('HTTPException: 404: /bad_path not found')
1092+
1093+
assert httpx.get(f'http://localhost:{Screen.PORT}/').status_code == 200
1094+
screen.open('/')
1095+
screen.should_contain('main page')
10921096

10931097

10941098
def test_http_404_on_initial_request_with_async_page_builder(screen: Screen):
@@ -1103,9 +1107,38 @@ def main():
11031107
ui.label('main page')
11041108

11051109
screen.open('/bad_path')
1110+
assert httpx.get(f'http://localhost:{Screen.PORT}/bad_path').status_code == 404
11061111
# NOTE: due to the async page builder, sub pages can not determine 404 status on initial request (see https://github.com/zauberzeug/nicegui/pull/5089)
1107-
screen.should_contain('404: sub page /bad_path not found')
1108-
assert httpx.get(f'http://localhost:{Screen.PORT}/bad_path').status_code == 200
1112+
screen.should_contain('HTTPException: 404: /bad_path not found')
1113+
1114+
assert httpx.get(f'http://localhost:{Screen.PORT}/').status_code == 200
1115+
screen.open('/')
1116+
screen.should_contain('main page')
1117+
1118+
1119+
def test_http_404_on_initial_request_with_async_sub_page_builder(screen: Screen):
1120+
@ui.page('/')
1121+
@ui.page('/{_:path}')
1122+
def index():
1123+
ui.sub_pages({
1124+
'/': main,
1125+
})
1126+
1127+
async def main():
1128+
ui.label('main page')
1129+
ui.sub_pages({
1130+
'/': lambda: ui.label('sub main page'),
1131+
'/sub': lambda: ui.label('sub sub page'),
1132+
})
1133+
1134+
screen.open('/bad_path')
1135+
assert httpx.get(f'http://localhost:{Screen.PORT}/bad_path').status_code == 404
1136+
# NOTE: due to the async page builder, sub pages can not determine 404 status on initial request (see https://github.com/zauberzeug/nicegui/pull/5089)
1137+
screen.should_contain('HTTPException: 404: /bad_path not found')
1138+
1139+
assert httpx.get(f'http://localhost:{Screen.PORT}/sub').status_code == 200
1140+
screen.open('/sub')
1141+
screen.should_contain('sub sub page')
11091142

11101143

11111144
def test_clearing_sub_pages_element(screen: Screen):

0 commit comments

Comments
 (0)