Forráskód Böngészése

Merge branch 'main' of github.com:zauberzeug/nicegui

Falko Schindler 2 éve
szülő
commit
5759a7930f
5 módosított fájl, 37 hozzáadás és 16 törlés
  1. 15 7
      api_docs_and_examples.py
  2. 1 0
      nicegui/events.py
  3. 10 4
      nicegui/page.py
  4. 1 1
      nicegui/routes.py
  5. 10 4
      tests/test_pages.py

+ 15 - 7
api_docs_and_examples.py

@@ -643,20 +643,28 @@ If the page function expects a `request` argument, the request object is automat
 
     yield_page_ready = '''#### Yielding for Page-Ready
 
-This is a handy alternative to the `on_page_ready` callback (either as parameter of `@ui.page` or via `ui.on_page_ready` function).
+This is a handy alternative to the `on_page_ready` callback of the `@ui.page` decorator.
 
 If a `yield` statement is provided in a page builder function, all code below that statement is executed after the page is ready.
 This allows you to execute JavaScript; which is only possible after the page has been loaded (see [#112](https://github.com/zauberzeug/nicegui/issues/112)).
-Also it is possible to do async stuff while the user already sees the content added before the yield statement.
+Also it is possible to do async stuff while the user already sees the content which was added before the yield statement.
+
+The yield statement returns `nicegui.events.PageEvent`. 
+This contains the websocket of the client.
     '''
     with example(yield_page_ready):
+        from typing import Generator
+
+        from nicegui.events import PageEvent
+
         @ui.page('/yield_page_ready')
-        async def yield_page_ready():
+        async def yield_page_ready() -> Generator[None, PageEvent, None]:
             ui.label('This text is displayed immediately.')
-            yield
-            ui.run_javascript('document.title = "JavaScript-Controlled Title")')
-            await asyncio.sleep(3)
-            ui.label('This text is displayed 3 seconds after the page has been fully loaded.')
+            page_ready = yield
+            await ui.run_javascript('document.title = "JavaScript-Controlled Title")')
+            await asyncio.sleep(2)
+            ui.label('This text is displayed 2 seconds after the page has been fully loaded.')
+            ui.label(f'The IP address {page_ready.socket.client.host} could be obtained from the websocket.')
 
         ui.link('show page-ready code after yield', '/yield_page_ready')
 

+ 1 - 0
nicegui/events.py

@@ -9,6 +9,7 @@ from . import globals
 from .elements.element import Element
 from .helpers import is_coroutine
 from .lifecycle import on_startup
+from .page import PageEvent
 from .task_logger import create_task
 
 

+ 10 - 4
nicegui/page.py

@@ -5,6 +5,7 @@ import inspect
 import time
 import types
 import uuid
+from dataclasses import dataclass
 from functools import wraps
 from typing import Callable, Dict, Generator, List, Optional
 
@@ -22,6 +23,11 @@ from .page_builder import PageBuilder
 from .routes import add_route, convert_arguments
 
 
+@dataclass
+class PageEvent:
+    socket: WebSocket
+
+
 class Page(jp.QuasarPage):
 
     def __init__(self,
@@ -50,7 +56,7 @@ class Page(jp.QuasarPage):
         self.css = css
         self.connect_handler = on_connect
         self.page_ready_handler = on_page_ready
-        self.page_ready_generator: Optional[Generator[None, None, None]] = None
+        self.page_ready_generator: Optional[Generator[None, PageEvent, None]] = None
         self.disconnect_handler = on_disconnect
         self.shared = shared
         self.delete_flag = not shared
@@ -89,9 +95,9 @@ class Page(jp.QuasarPage):
         with globals.within_view(self.view):
             if self.page_ready_generator is not None:
                 if isinstance(self.page_ready_generator, types.AsyncGeneratorType):
-                    await self.page_ready_generator.__anext__()
+                    await self.page_ready_generator.asend(PageEvent(msg.websocket))
                 elif isinstance(self.page_ready_generator, types.GeneratorType):
-                    next(self.page_ready_generator)
+                    self.page_ready_generator.send(PageEvent(msg.websocket))
             if self.page_ready_handler:
                 arg_count = len(inspect.signature(self.page_ready_handler).parameters)
                 is_coro = is_coroutine(self.page_ready_handler)
@@ -183,7 +189,7 @@ class page:
         :param classes: tailwind classes for the container div (default: `'q-pa-md column items-start gap-4'`)
         :param css: CSS definitions
         :param on_connect: optional function or coroutine which is called for each new client connection
-        :param on_page_ready: optional function or coroutine which is called when the websocket is connected;  see `"Yield for Page Ready" <https://nicegui.io/#yield_for_page_ready>`_ as an alternative.
+        :param on_page_ready: optional function or coroutine which is called when the websocket is connected;  see `"Yielding for Page-Ready" <https://nicegui.io/reference#yielding_for_page-ready>`_ as an alternative.
         :param on_disconnect: optional function or coroutine which is called when a client disconnects
         :param shared: whether the page instance is shared between multiple clients (default: `False`)
         """

+ 1 - 1
nicegui/routes.py

@@ -18,7 +18,7 @@ def add_route(self, route: BaseRoute) -> None:
 
     Adds a new `Starlette route <https://www.starlette.io/routing/>`_.
     Routed paths must start with a slash "/".
-    Also see `@ui.get <https://nicegui.io/#get_decorator>`_ and `ui.add_static_files <https://nicegui.io/#get_decorator>`_
+    Also see `@ui.get <https://nicegui.io/reference#get_decorator>`_ and `ui.add_static_files <https://nicegui.io/reference#get_decorator>`_
     for more convenient ways to deliver non-UI content.
 
     :param route: Starlette route including a path and a function to be called

+ 10 - 4
tests/test_pages.py

@@ -1,9 +1,11 @@
 import asyncio
 from time import time
+from typing import Generator
 from uuid import uuid4
 
 import justpy.htmlcomponents
 from nicegui import task_logger, ui
+from nicegui.events import PageEvent
 from starlette.requests import Request
 
 from .screen import Screen
@@ -191,29 +193,33 @@ def test_adding_elements_in_on_page_ready_event(screen: Screen):
 
 def test_pageready_after_yield_on_async_page(screen: Screen):
     @ui.page('/')
-    async def page():
+    async def page() -> Generator[None, PageEvent, None]:
         ui.label('before')
-        yield
+        page_ready = yield
         await asyncio.sleep(1)
         ui.label('after')
+        ui.label(page_ready.socket.base_url)
 
     screen.open('/')
     screen.should_contain('before')
     screen.should_not_contain('after')
     screen.wait(1)
     screen.should_contain('after')
+    screen.should_contain('ws://localhost:3392/')
 
 
 def test_pageready_after_yield_on_non_async_page(screen: Screen):
     @ui.page('/')
-    def page():
+    def page() -> Generator[None, PageEvent, None]:
         t = time()
-        yield
+        page_ready = yield
         ui.label(f'loading page took {time() - t:.2f} seconds')
+        ui.label(page_ready.socket.base_url)
 
     screen.open('/')
     timing = screen.find('loading page took')
     assert 0 < float(timing.text.split()[-2]) < 3
+    screen.should_contain('ws://localhost:3392/')
 
 
 def test_pageready_after_yield_on_shared_page_raises_exception(screen: Screen):