From 39547ea5b254b564f5b8a1bdafb3293070162a3c Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Sun, 14 Apr 2024 11:23:09 +0200 Subject: [PATCH 01/38] "Remote-Containers" extension has been renamed to "Dev Containers" (#2854) --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca89e0eeb..c3da92fe8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,9 +25,9 @@ We're always looking for bug fixes, performance improvements, and new features. The simplest way to setup a fully functioning development environment is to start our Dev Container in VS Code: -1. Ensure you have VS Code, Docker and the Remote-Containers extension installed. +1. Ensure you have VS Code, Docker and the Dev Containers extension installed. 2. Open the project root directory in VS Code. -3. Press `F1`, type `Remote-Containers: Open Folder in Container`, and hit enter (or use the bottom-left corner icon in VS Code to reopen in container). +3. Press `F1`, type `Dev Containers: Open Folder in Container`, and hit enter (or use the bottom-left corner icon in VS Code to reopen in container). 4. Wait until image has been build. 5. Happy coding. From c36834a6c186892a54157e09edc7cbf9255ba596 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Sun, 14 Apr 2024 13:10:46 +0200 Subject: [PATCH 02/38] introduce orthographic camera for `ui.scene` (#2890) --- nicegui/elements/scene.js | 12 +++++++++++- nicegui/elements/scene.py | 5 ++++- website/documentation/content/scene_documentation.py | 8 ++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/nicegui/elements/scene.js b/nicegui/elements/scene.js index 336446d61..15410b8cd 100644 --- a/nicegui/elements/scene.js +++ b/nicegui/elements/scene.js @@ -66,7 +66,12 @@ export default { window["scene_" + this.$el.id] = this.scene; // NOTE: for selenium tests only this.look_at = new THREE.Vector3(0, 0, 0); - this.camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.1, 1000); + const aspect = this.width / this.height; + if (this.camera_type === "perspective") { + this.camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000); + } else { + this.camera = new THREE.OrthographicCamera(-aspect, aspect, 1, -1, 0.1, 1000); + } this.camera.lookAt(this.look_at); this.camera.up = new THREE.Vector3(0, 0, 1); this.camera.position.set(0, -3, 5); @@ -410,6 +415,10 @@ export default { this.text_renderer.setSize(clientWidth, clientHeight); this.text3d_renderer.setSize(clientWidth, clientHeight); this.camera.aspect = clientWidth / clientHeight; + if (this.camera_type === "orthographic") { + this.camera.left = -this.camera.aspect; + this.camera.right = this.camera.aspect; + } this.camera.updateProjectionMatrix(); }, }, @@ -418,6 +427,7 @@ export default { width: Number, height: Number, grid: Boolean, + camera_type: String, drag_constraints: String, }, }; diff --git a/nicegui/elements/scene.py b/nicegui/elements/scene.py index 2ec9d9284..185b79ff0 100644 --- a/nicegui/elements/scene.py +++ b/nicegui/elements/scene.py @@ -1,6 +1,6 @@ import asyncio from dataclasses import dataclass -from typing import Any, Callable, Dict, List, Optional, Union +from typing import Any, Callable, Dict, List, Literal, Optional, Union from typing_extensions import Self @@ -71,6 +71,7 @@ def __init__(self, width: int = 400, height: int = 300, grid: bool = True, + camera_type: Literal['perspective', 'orthographic'] = 'perspective', on_click: Optional[Callable[..., Any]] = None, on_drag_start: Optional[Callable[..., Any]] = None, on_drag_end: Optional[Callable[..., Any]] = None, @@ -86,6 +87,7 @@ def __init__(self, :param width: width of the canvas :param height: height of the canvas :param grid: whether to display a grid + :param camera_type: type of camera to use (``'perspective'`` or ``'orthographic'``) :param on_click: callback to execute when a 3D object is clicked :param on_drag_start: callback to execute when a 3D object is dragged :param on_drag_end: callback to execute when a 3D object is dropped @@ -95,6 +97,7 @@ def __init__(self, self._props['width'] = width self._props['height'] = height self._props['grid'] = grid + self._props['camera_type'] = camera_type self.objects: Dict[str, Object3D] = {} self.stack: List[Union[Object3D, SceneObject]] = [SceneObject()] self.camera: SceneCamera = SceneCamera() diff --git a/website/documentation/content/scene_documentation.py b/website/documentation/content/scene_documentation.py index 0cd7034cc..f04bc2c9d 100644 --- a/website/documentation/content/scene_documentation.py +++ b/website/documentation/content/scene_documentation.py @@ -113,4 +113,12 @@ async def wait_for_init() -> None: scene.move_camera(x=1, y=-1, z=1.5, duration=2) +@doc.demo('Orthographic Camera', ''' + You can use the `camera_type` argument to `ui.scene` to use an orthographic instead of a perspective camera. +''') +def orthographic_camera() -> None: + with ui.scene(camera_type='orthographic').classes('w-full h-64') as scene: + scene.box() + + doc.reference(ui.scene) From dca25d3ab4868bdd5876969e28513b03e94990cf Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Mon, 15 Apr 2024 10:53:39 +0200 Subject: [PATCH 03/38] remove orthographic cameras from next release --- nicegui/elements/scene.py | 6 ++---- website/documentation/content/scene_documentation.py | 12 ++++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/nicegui/elements/scene.py b/nicegui/elements/scene.py index 185b79ff0..10292ba16 100644 --- a/nicegui/elements/scene.py +++ b/nicegui/elements/scene.py @@ -1,6 +1,6 @@ import asyncio from dataclasses import dataclass -from typing import Any, Callable, Dict, List, Literal, Optional, Union +from typing import Any, Callable, Dict, List, Optional, Union from typing_extensions import Self @@ -71,7 +71,6 @@ def __init__(self, width: int = 400, height: int = 300, grid: bool = True, - camera_type: Literal['perspective', 'orthographic'] = 'perspective', on_click: Optional[Callable[..., Any]] = None, on_drag_start: Optional[Callable[..., Any]] = None, on_drag_end: Optional[Callable[..., Any]] = None, @@ -87,7 +86,6 @@ def __init__(self, :param width: width of the canvas :param height: height of the canvas :param grid: whether to display a grid - :param camera_type: type of camera to use (``'perspective'`` or ``'orthographic'``) :param on_click: callback to execute when a 3D object is clicked :param on_drag_start: callback to execute when a 3D object is dragged :param on_drag_end: callback to execute when a 3D object is dropped @@ -97,7 +95,7 @@ def __init__(self, self._props['width'] = width self._props['height'] = height self._props['grid'] = grid - self._props['camera_type'] = camera_type + self._props['camera_type'] = 'perspective' self.objects: Dict[str, Object3D] = {} self.stack: List[Union[Object3D, SceneObject]] = [SceneObject()] self.camera: SceneCamera = SceneCamera() diff --git a/website/documentation/content/scene_documentation.py b/website/documentation/content/scene_documentation.py index f04bc2c9d..e5a2e8356 100644 --- a/website/documentation/content/scene_documentation.py +++ b/website/documentation/content/scene_documentation.py @@ -113,12 +113,12 @@ async def wait_for_init() -> None: scene.move_camera(x=1, y=-1, z=1.5, duration=2) -@doc.demo('Orthographic Camera', ''' - You can use the `camera_type` argument to `ui.scene` to use an orthographic instead of a perspective camera. -''') -def orthographic_camera() -> None: - with ui.scene(camera_type='orthographic').classes('w-full h-64') as scene: - scene.box() +# @doc.demo('Orthographic Camera', ''' +# You can use the `camera_type` argument to `ui.scene` to use an orthographic instead of a perspective camera. +# ''') +# def orthographic_camera() -> None: +# with ui.scene(camera_type='orthographic').classes('w-full h-64') as scene: +# scene.box() doc.reference(ui.scene) From 2a46e2455fb3b8185dbe0f3a65c6c9f07b61b41b Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Mon, 15 Apr 2024 11:13:35 +0200 Subject: [PATCH 04/38] remove default auto-close prop from `ui.menu` (fixes #2894) --- nicegui/elements/menu.py | 11 +++++------ website/documentation/content/menu_documentation.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/nicegui/elements/menu.py b/nicegui/elements/menu.py index ce3ffdc80..845928fd0 100644 --- a/nicegui/elements/menu.py +++ b/nicegui/elements/menu.py @@ -17,10 +17,12 @@ def __init__(self, *, value: bool = False) -> None: Creates a menu based on Quasar's `QMenu `_ component. The menu should be placed inside the element where it should be shown. + Advanced tip: + Use the `auto-close` prop to automatically close the menu on any click event directly without a server round-trip. + :param value: whether the menu is already opened (default: `False`) """ super().__init__(tag='q-menu', value=value, on_value_change=None) - self._props['auto-close'] = True def open(self) -> None: """Open the menu.""" @@ -65,11 +67,8 @@ def __init__(self, self._props['clickable'] = True self.menu = self._find_menu() - if self.menu: - if auto_close: - self.on_click(self.menu.close) - else: - self.menu.props(remove='auto-close') + if self.menu and auto_close: + self.on_click(self.menu.close) def _find_menu(self) -> Optional[Union[Menu, ContextMenu]]: element: Element = self diff --git a/website/documentation/content/menu_documentation.py b/website/documentation/content/menu_documentation.py index 04704557c..750371d12 100644 --- a/website/documentation/content/menu_documentation.py +++ b/website/documentation/content/menu_documentation.py @@ -17,4 +17,14 @@ def main_demo() -> None: ui.menu_item('Close', menu.close) +@doc.demo('Client-side auto-close', ''' + Use the `auto-close` prop to automatically close the menu on any click event directly without a server round-trip. +''') +def auto_close(): + with ui.button(icon='menu'): + with ui.menu().props('auto-close'): + toggle = ui.toggle(['fastfood', 'cake', 'icecream'], value='fastfood') + ui.icon('', size='md').bind_name_from(toggle, 'value') + + doc.reference(ui.menu) From 0e53ffe07cfcd33553392062ba14c66872a1175f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 10:12:26 +0000 Subject: [PATCH 05/38] Update citation.cff and pyproject.toml --- CITATION.cff | 6 +++--- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 34a0b8f54..bd9bb1ad0 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -8,7 +8,7 @@ authors: given-names: Rodja orcid: https://orcid.org/0009-0009-4735-6227 title: 'NiceGUI: Web-based user interfaces with Python. The nice way.' -version: v1.4.21 -date-released: '2024-04-12' +version: v1.4.22 +date-released: '2024-04-15' url: https://github.com/zauberzeug/nicegui -doi: 10.5281/zenodo.10965450 +doi: 10.5281/zenodo.10973178 diff --git a/pyproject.toml b/pyproject.toml index 19f1f8cd8..a0072f4ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nicegui" -version = "1.4.21-dev" +version = "1.4.22-dev" description = "Create web-based user interfaces with Python. The nice way." authors = ["Zauberzeug GmbH "] license = "MIT" From fc5bd3cd2933aeff65eef131a072b2efda65acf0 Mon Sep 17 00:00:00 2001 From: Rodja Trappe Date: Tue, 16 Apr 2024 06:41:01 +0200 Subject: [PATCH 06/38] note about run.cpu_bound problem with classes --- website/documentation/content/section_action_events.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/documentation/content/section_action_events.py b/website/documentation/content/section_action_events.py index 25fafa7f3..476cb03e7 100644 --- a/website/documentation/content/section_action_events.py +++ b/website/documentation/content/section_action_events.py @@ -71,6 +71,9 @@ async def async_task(): NiceGUI provides a `cpu_bound` function for running CPU-bound tasks in a separate process. This is useful for long-running computations that would otherwise block the event loop and make the UI unresponsive. The function returns a future that can be awaited. + NOTE: The function needs to transfer the whole state of the passed function to the process (which is done with pickle). + It is encouraged to create static methods (or free functions) which get all the data as simple parameters (eg. no class/ui logic) + and return the result (instead of writing it in class properties or global variables). ''') def cpu_bound_demo(): import time From e506a1e99b8c35d0b9f16ab2130f00616380c841 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Tue, 16 Apr 2024 10:01:20 +0200 Subject: [PATCH 07/38] review --- website/documentation/content/section_action_events.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/website/documentation/content/section_action_events.py b/website/documentation/content/section_action_events.py index 476cb03e7..499076543 100644 --- a/website/documentation/content/section_action_events.py +++ b/website/documentation/content/section_action_events.py @@ -71,9 +71,11 @@ async def async_task(): NiceGUI provides a `cpu_bound` function for running CPU-bound tasks in a separate process. This is useful for long-running computations that would otherwise block the event loop and make the UI unresponsive. The function returns a future that can be awaited. - NOTE: The function needs to transfer the whole state of the passed function to the process (which is done with pickle). - It is encouraged to create static methods (or free functions) which get all the data as simple parameters (eg. no class/ui logic) - and return the result (instead of writing it in class properties or global variables). + + **Note:** + The function needs to transfer the whole state of the passed function to the process, which is done with pickle. + It is encouraged to create free functions or static methods which get all the data as simple parameters (i.e. no class or UI logic) + and return the result, instead of writing it in class properties or global variables. ''') def cpu_bound_demo(): import time From b7f0ec5ba433aa06f420b8c372133cb472acb222 Mon Sep 17 00:00:00 2001 From: Rodja Trappe Date: Tue, 16 Apr 2024 10:16:49 +0200 Subject: [PATCH 08/38] process tab_id in handshakes via On Air (#2902) --- nicegui/air.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nicegui/air.py b/nicegui/air.py index e60d108af..8f7a5ec30 100644 --- a/nicegui/air.py +++ b/nicegui/air.py @@ -122,6 +122,7 @@ def _handle_handshake(data: Dict[str, Any]) -> bool: return False client = Client.instances[client_id] client.environ = data['environ'] + client.tab_id = data['tab_id'] client.on_air = True client.handle_handshake() return True From a2544c1278e3586de038fa773d3290f78114be9c Mon Sep 17 00:00:00 2001 From: Aaron Fuller <159853563+afullerx@users.noreply.github.com> Date: Tue, 16 Apr 2024 05:12:27 -0400 Subject: [PATCH 09/38] Replace repeated polling in Outbox.loop() with an asyncio event (see #2482) (#2867) * Add asyncio events to outbox * Moved event clearing as a minor optimization * clean up timeout argument * Change timeout duration * Handle connection timeout * Add log import * remove extraneous whitespace * code review and improvement * Add asyncio.TimeoutError for Python < 3.11 * Fix test hangs --------- Co-authored-by: Falko Schindler --- nicegui/outbox.py | 24 ++++++++++++++++++++---- tests/test_input.py | 5 +++-- tests/test_javascript.py | 1 + 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/nicegui/outbox.py b/nicegui/outbox.py index 93ba8b75e..77c0a0356 100644 --- a/nicegui/outbox.py +++ b/nicegui/outbox.py @@ -23,35 +23,51 @@ def __init__(self, client: Client) -> None: self.updates: Dict[ElementId, Optional[Element]] = {} self.messages: Deque[Message] = deque() self._should_stop = False + self._enqueue_event: Optional[asyncio.Event] = None if core.app.is_started: background_tasks.create(self.loop(), name=f'outbox loop {client.id}') else: core.app.on_startup(self.loop) + def _set_enqueue_event(self) -> None: + """Set the enqueue event while accounting for lazy initialization.""" + if self._enqueue_event: + self._enqueue_event.set() + def enqueue_update(self, element: Element) -> None: """Enqueue an update for the given element.""" self.updates[element.id] = element + self._set_enqueue_event() def enqueue_delete(self, element: Element) -> None: """Enqueue a deletion for the given element.""" self.updates[element.id] = None + self._set_enqueue_event() def enqueue_message(self, message_type: MessageType, data: Any, target_id: ClientId) -> None: """Enqueue a message for the given client.""" self.messages.append((target_id, message_type, data)) + self._set_enqueue_event() async def loop(self) -> None: """Send updates and messages to all clients in an endless loop.""" + self._enqueue_event = asyncio.Event() + self._enqueue_event.set() + while not self._should_stop: try: - await asyncio.sleep(0.01) - - if not self.updates and not self.messages: - continue + if not self._enqueue_event.is_set(): + try: + await asyncio.wait_for(self._enqueue_event.wait(), timeout=1.0) + except (TimeoutError, asyncio.TimeoutError): + continue if not self.client.has_socket_connection: + await asyncio.sleep(0.1) continue + self._enqueue_event.clear() + coros = [] data = { element_id: None if element is None else element._to_dict() # pylint: disable=protected-access diff --git a/tests/test_input.py b/tests/test_input.py index 3212e63ba..c54db2d3e 100644 --- a/tests/test_input.py +++ b/tests/test_input.py @@ -122,11 +122,12 @@ def test_autocompletion(screen: Screen): assert element.get_attribute('value') == 'fx' assert input_.value == 'fx' - input_.set_autocomplete(['one', 'two']) + input_.set_autocomplete(['once', 'twice']) + screen.wait(0.2) element.send_keys(Keys.BACKSPACE) element.send_keys(Keys.BACKSPACE) element.send_keys('o') - screen.should_contain('ne') + screen.should_contain('nce') def test_clearable_input(screen: Screen): diff --git a/tests/test_javascript.py b/tests/test_javascript.py index 147868d32..0d1ba4fbe 100644 --- a/tests/test_javascript.py +++ b/tests/test_javascript.py @@ -40,6 +40,7 @@ def page(): screen.open('/') screen.should_contain('before js') screen.should_contain('after js') + screen.wait(0.5) screen.should_contain('New Title') From fd99e6ce8a22baeb2c640482ba951fba8d71ac56 Mon Sep 17 00:00:00 2001 From: Ezbaze <68749104+Ezbaze@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:13:39 +0100 Subject: [PATCH 10/38] Fix type in a url to fastapi docs. (#2908) --- website/documentation/content/page_documentation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/documentation/content/page_documentation.py b/website/documentation/content/page_documentation.py index 5c79b4b29..821a1de1e 100644 --- a/website/documentation/content/page_documentation.py +++ b/website/documentation/content/page_documentation.py @@ -18,7 +18,7 @@ def dark_page(): @doc.demo('Pages with Path Parameters', ''' - Page routes can contain parameters like [FastAPI](https://fastapi.tiangolo.com/tutorial/path-params/>). + Page routes can contain parameters like [FastAPI](https://fastapi.tiangolo.com/tutorial/path-params/). If type-annotated, they are automatically converted to bool, int, float and complex values. If the page function expects a `request` argument, the request object is automatically provided. The `client` argument provides access to the websocket connection, layout, etc. From c1334ec88f39fda9bbd4a1b7b8c3ba60d04f1419 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Thu, 18 Apr 2024 14:33:10 +0200 Subject: [PATCH 11/38] extend storage documentation --- website/documentation/content/storage_documentation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/documentation/content/storage_documentation.py b/website/documentation/content/storage_documentation.py index 44705654c..b0c7309ff 100644 --- a/website/documentation/content/storage_documentation.py +++ b/website/documentation/content/storage_documentation.py @@ -48,10 +48,12 @@ | Location | Server | Server | Server | Server | Browser | | Across tabs | No | No | Yes | Yes | Yes | | Across browsers | No | No | No | Yes | No | + | Across server restarts | No | No | No | Yes | No | | Across page reloads | Yes | No | Yes | Yes | Yes | | Needs page builder function | Yes | Yes | Yes | No | Yes | | Needs client connection | Yes | No | No | No | No | | Write only before response | No | No | No | No | Yes | + | Needs serializable data | No | No | Yes | Yes | Yes | ''') def storage_demo(): from nicegui import app From 97d4027325ef7d88891e33256501eb1e5cef9c87 Mon Sep 17 00:00:00 2001 From: Rodja Trappe Date: Fri, 19 Apr 2024 19:43:03 +0200 Subject: [PATCH 12/38] using swap-feature from fly.io --- fly-entrypoint.sh | 6 ------ fly.toml | 5 ++--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/fly-entrypoint.sh b/fly-entrypoint.sh index a3d72b9d5..3b32f974d 100755 --- a/fly-entrypoint.sh +++ b/fly-entrypoint.sh @@ -1,12 +1,6 @@ #!/bin/bash set -e -if [[ ! -z "$SWAP" ]]; then - fallocate -l $(($(stat -f -c "(%a*%s/10)*7" .))) _swapfile - mkswap _swapfile - swapon _swapfile -fi - free -hm df -h exec "$@" diff --git a/fly.toml b/fly.toml index d10a7a8de..667a91cd4 100644 --- a/fly.toml +++ b/fly.toml @@ -7,6 +7,8 @@ app = "nicegui" primary_region = "fra" kill_signal = "SIGTERM" kill_timeout = "5s" +swap_size_mb = 2048 + [build] dockerfile = "fly.dockerfile" @@ -17,9 +19,6 @@ kill_timeout = "5s" [processes] app = "" -[env] - SWAP = "true" - [[services]] protocol = "tcp" internal_port = 8080 From 0994ca62912ebf2820290c7d077a53bbc7fccc65 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Sat, 20 Apr 2024 18:47:01 +0200 Subject: [PATCH 13/38] add early exit when setting the value of ui.state variables (#2922) --- nicegui/functions/refreshable.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nicegui/functions/refreshable.py b/nicegui/functions/refreshable.py index 1e3b1a6fa..b46b3f8d1 100644 --- a/nicegui/functions/refreshable.py +++ b/nicegui/functions/refreshable.py @@ -154,6 +154,8 @@ def state(value: Any) -> Tuple[Any, Callable[[Any], None]]: value = target.locals[target.next_index] def set_value(new_value: Any, index=target.next_index) -> None: + if target.locals[index] == new_value: + return target.locals[index] = new_value target.refreshable.refresh() From fb53bfc6975d0c6977e26b0ba9da1593c328e02c Mon Sep 17 00:00:00 2001 From: Rodja Trappe Date: Sun, 21 Apr 2024 04:36:54 +0200 Subject: [PATCH 14/38] more servers for tokyo --- set_scale.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/set_scale.sh b/set_scale.sh index 33a45af48..ef61928fe 100755 --- a/set_scale.sh +++ b/set_scale.sh @@ -16,7 +16,7 @@ fly scale count app=1 --region otp -y # Bucharest, Romania fly scale count app=1 --region jnb -y # Johannesburg, South Africa fly scale count app=1 --region bom -y # Mumbai, India -fly scale count app=1 --region nrt -y # Tokyo, Japan +fly scale count app=3 --region nrt -y # Tokyo, Japan fly scale count app=1 --region sin -y # Singapor fly scale count app=3 --region hkg -y # Hong Kong From aa8ec69304a09c7601544c6b7a9680603f193533 Mon Sep 17 00:00:00 2001 From: Rodja Trappe Date: Mon, 22 Apr 2024 11:58:26 +0200 Subject: [PATCH 15/38] Show scroll to bottom in ui.table demo (#2927) * show scroll to bottom in ui.table demo * review --------- Co-authored-by: Falko Schindler --- .../content/table_documentation.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/website/documentation/content/table_documentation.py b/website/documentation/content/table_documentation.py index f9338eea0..2641a10b4 100644 --- a/website/documentation/content/table_documentation.py +++ b/website/documentation/content/table_documentation.py @@ -139,21 +139,18 @@ def table_from_pandas_demo(): @doc.demo('Adding rows', ''' It's simple to add new rows with the `add_rows(dict)` method. + With the "virtual-scroll" prop set, the table can be programmatically scrolled with the `scrollTo` JavaScript function. ''') def adding_rows(): - import os - import random + from datetime import datetime def add(): - item = os.urandom(10 // 2).hex() - table.add_rows({'id': item, 'count': random.randint(0, 100)}) + table.add_rows({'date': datetime.now().strftime('%c')}) + table.run_method('scrollTo', len(table.rows)-1) - ui.button('add', on_click=add) - columns = [ - {'name': 'id', 'label': 'ID', 'field': 'id'}, - {'name': 'count', 'label': 'Count', 'field': 'count'}, - ] - table = ui.table(columns=columns, rows=[], row_key='id').classes('w-full') + columns = [{'name': 'date', 'label': 'Date', 'field': 'date'}] + table = ui.table(columns=columns, rows=[]).classes('h-52').props('virtual-scroll') + ui.button('Add row', on_click=add) @doc.demo('Custom sorting and formatting', ''' From 1541006ef865bc39012bd24cb07e18bcd28b4b17 Mon Sep 17 00:00:00 2001 From: Rodja Trappe Date: Mon, 22 Apr 2024 12:01:03 +0200 Subject: [PATCH 16/38] Introduce ui.context as a simpler method to get Client, Slot-Stack etc (#2879) * provide ui.context * use ui.context instead of page injector * add `context` to `__all__` * remove unnecessary file --------- Co-authored-by: Falko Schindler --- examples/chat_app/main.py | 6 ++-- examples/descope_auth/user.py | 6 ++-- examples/download_text_as_file/main.py | 6 ++-- examples/infinite_scroll/main.py | 6 ++-- nicegui/ui.py | 2 ++ tests/test_auto_context.py | 4 +-- tests/test_interactive_image.py | 6 ++-- tests/test_javascript.py | 6 ++-- tests/test_lifecycle.py | 6 ++-- tests/test_page.py | 36 +++++++++---------- tests/test_storage.py | 8 ++--- .../content/page_documentation.py | 8 ++--- .../content/storage_documentation.py | 6 ++-- 13 files changed, 53 insertions(+), 53 deletions(-) diff --git a/examples/chat_app/main.py b/examples/chat_app/main.py index 68467235c..cf91bab18 100755 --- a/examples/chat_app/main.py +++ b/examples/chat_app/main.py @@ -3,7 +3,7 @@ from typing import List, Tuple from uuid import uuid4 -from nicegui import Client, ui +from nicegui import ui messages: List[Tuple[str, str, str, str]] = [] @@ -16,7 +16,7 @@ def chat_messages(own_id: str) -> None: @ui.page('/') -async def main(client: Client): +async def main(): def send() -> None: stamp = datetime.utcnow().strftime('%X') messages.append((user_id, avatar, text.value, stamp)) @@ -36,7 +36,7 @@ def send() -> None: ui.markdown('simple chat app built with [NiceGUI](https://nicegui.io)') \ .classes('text-xs self-end mr-8 m-[-1em] text-primary') - await client.connected() # chat_messages(...) uses run_javascript which is only possible after connecting + await ui.context.get_client().connected() # chat_messages(...) uses run_javascript which is only possible after connecting with ui.column().classes('w-full max-w-2xl mx-auto items-stretch'): chat_messages(user_id) diff --git a/examples/descope_auth/user.py b/examples/descope_auth/user.py index 07515732a..33d26409d 100644 --- a/examples/descope_auth/user.py +++ b/examples/descope_auth/user.py @@ -4,7 +4,7 @@ from descope import AuthException, DescopeClient -from nicegui import Client, app, helpers, ui +from nicegui import app, helpers, ui DESCOPE_ID = os.environ.get('DESCOPE_PROJECT_ID', '') @@ -52,7 +52,7 @@ class page(ui.page): LOGIN_PATH = '/login' def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]: - async def content(client: Client): + async def content(): ui.add_head_html('') ui.add_head_html('') ui.add_body_html(f''' @@ -61,7 +61,7 @@ async def content(client: Client): const sessionToken = sdk.getSessionToken() ''') - await client.connected() + await ui.context.get_client().connected() if await self._is_logged_in(): if self.path == self.LOGIN_PATH: self._refresh() diff --git a/examples/download_text_as_file/main.py b/examples/download_text_as_file/main.py index 515344e3a..4e9935254 100755 --- a/examples/download_text_as_file/main.py +++ b/examples/download_text_as_file/main.py @@ -4,11 +4,11 @@ from fastapi.responses import StreamingResponse -from nicegui import Client, app, ui +from nicegui import app, ui @ui.page('/') -async def index(client: Client): +async def index(): download_path = f'/download/{uuid.uuid4()}.txt' @app.get(download_path) @@ -21,7 +21,7 @@ def download(): ui.button('Download', on_click=lambda: ui.download(download_path)) # cleanup the download route after the client disconnected - await client.disconnected() + await ui.context.get_client().disconnected() app.routes[:] = [route for route in app.routes if route.path != download_path] ui.run() diff --git a/examples/infinite_scroll/main.py b/examples/infinite_scroll/main.py index d7344ca34..7f63bb1da 100755 --- a/examples/infinite_scroll/main.py +++ b/examples/infinite_scroll/main.py @@ -1,15 +1,15 @@ #!/usr/bin/env python3 import time -from nicegui import Client, ui +from nicegui import ui @ui.page('/') -async def page(client: Client): +async def page(): async def check(): if await ui.run_javascript('window.pageYOffset >= document.body.offsetHeight - 2 * window.innerHeight'): ui.image(f'https://picsum.photos/640/360?{time.time()}') - await client.connected() + await ui.context.get_client().connected() ui.timer(0.1, check) diff --git a/nicegui/ui.py b/nicegui/ui.py index 5c5e61a3e..fe3faba69 100644 --- a/nicegui/ui.py +++ b/nicegui/ui.py @@ -20,6 +20,7 @@ 'color_picker', 'colors', 'column', + 'context', 'context_menu', 'dark_mode', 'date', @@ -121,6 +122,7 @@ 'run_with', ] +from . import context from .element import Element as element from .elements.aggrid import AgGrid as aggrid from .elements.audio import Audio as audio diff --git a/tests/test_auto_context.py b/tests/test_auto_context.py index 13dcf5d0b..92afc8dc0 100644 --- a/tests/test_auto_context.py +++ b/tests/test_auto_context.py @@ -50,9 +50,9 @@ async def add_b(): def test_autoupdate_after_connected(screen: Screen): @ui.page('/') - async def page(client: Client): + async def page(): ui.label('before connected') - await client.connected() + await ui.context.get_client().connected() ui.label('after connected') await asyncio.sleep(1) ui.label('one') diff --git a/tests/test_interactive_image.py b/tests/test_interactive_image.py index eed252150..facdbcef1 100644 --- a/tests/test_interactive_image.py +++ b/tests/test_interactive_image.py @@ -3,14 +3,14 @@ import pytest from selenium.webdriver.common.action_chains import ActionChains -from nicegui import Client, ui +from nicegui import ui from nicegui.testing import Screen def test_set_source_in_tab(screen: Screen): """https://github.com/zauberzeug/nicegui/issues/488""" @ui.page('/') - async def page(client: Client): + async def page(): with ui.tabs() as tabs: ui.tab('A') ui.tab('B') @@ -20,7 +20,7 @@ async def page(client: Client): img = ui.interactive_image() with ui.tab_panel('B'): ui.label('Tab B') - await client.connected() + await ui.context.get_client().connected() img.set_source('https://picsum.photos/id/29/640/360') screen.open('/') diff --git a/tests/test_javascript.py b/tests/test_javascript.py index 0d1ba4fbe..39eeca279 100644 --- a/tests/test_javascript.py +++ b/tests/test_javascript.py @@ -1,4 +1,4 @@ -from nicegui import Client, ui +from nicegui import ui from nicegui.testing import Screen @@ -14,9 +14,9 @@ def test_run_javascript_on_button_press(screen: Screen): def test_run_javascript_on_value_change(screen: Screen): @ui.page('/') - async def page(client: Client): + async def page(): ui.radio(['A', 'B'], on_change=lambda e: ui.run_javascript(f'document.title = "Page {e.value}"')) - await client.connected() + await ui.context.get_client().connected() ui.run_javascript('document.title = "Initial Title"') screen.open('/') diff --git a/tests/test_lifecycle.py b/tests/test_lifecycle.py index 55b85e7a6..bfe60728f 100644 --- a/tests/test_lifecycle.py +++ b/tests/test_lifecycle.py @@ -1,6 +1,6 @@ from typing import List -from nicegui import Client, app, ui +from nicegui import app, ui from nicegui.testing import Screen @@ -34,8 +34,8 @@ def test_connect_disconnect_is_called_for_each_client(screen: Screen): events: List[str] = [] @ui.page('/', reconnect_timeout=0) - def page(client: Client): - ui.label(f'client id: {client.id}') + def page(): + ui.label(f'client id: {ui.context.get_client().id}') app.on_connect(lambda: events.append('connect')) app.on_disconnect(lambda: events.append('disconnect')) diff --git a/tests/test_page.py b/tests/test_page.py index c195d2742..e83d0a8a3 100644 --- a/tests/test_page.py +++ b/tests/test_page.py @@ -6,7 +6,7 @@ from fastapi.responses import PlainTextResponse from selenium.webdriver.common.by import By -from nicegui import Client, background_tasks, ui +from nicegui import background_tasks, ui from nicegui.testing import Screen @@ -117,10 +117,10 @@ async def takes_a_while() -> None: label.text = 'delayed data has been loaded' @ui.page('/') - async def page(client: Client): + async def page(): nonlocal label label = ui.label() - await client.connected() + await ui.context.get_client().connected() await load() screen.open('/') @@ -131,10 +131,10 @@ def test_wait_for_disconnect(screen: Screen): events = [] @ui.page('/', reconnect_timeout=0) - async def page(client: Client): - await client.connected() + async def page(): + await ui.context.get_client().connected() events.append('connected') - await client.disconnected() + await ui.context.get_client().disconnected() events.append('disconnected') screen.open('/') @@ -148,8 +148,8 @@ def test_wait_for_disconnect_without_awaiting_connected(screen: Screen): events = [] @ui.page('/', reconnect_timeout=0) - async def page(client: Client): - await client.disconnected() + async def page(): + await ui.context.get_client().disconnected() events.append('disconnected') screen.open('/') @@ -161,9 +161,9 @@ async def page(client: Client): def test_adding_elements_after_connected(screen: Screen): @ui.page('/') - async def page(client: Client): + async def page(): ui.label('before') - await client.connected() + await ui.context.get_client().connected() ui.label('after') screen.open('/') @@ -184,8 +184,8 @@ def page(): def test_exception_after_connected(screen: Screen): @ui.page('/') - async def page(client: Client): - await client.connected() + async def page(): + await ui.context.get_client().connected() ui.label('this is shown') raise RuntimeError('some exception') @@ -205,9 +205,9 @@ def page(id_: int): def test_adding_elements_during_onconnect(screen: Screen): @ui.page('/') - def page(client: Client): + def page(): ui.label('Label 1') - client.on_connect(lambda: ui.label('Label 2')) + ui.context.get_client().on_connect(lambda: ui.label('Label 2')) screen.open('/') screen.should_contain('Label 2') @@ -215,11 +215,11 @@ def page(client: Client): def test_async_connect_handler(screen: Screen): @ui.page('/') - def page(client: Client): + def page(): async def run_js(): result.text = await ui.run_javascript('41 + 1') result = ui.label() - client.on_connect(run_js) + ui.context.get_client().on_connect(run_js) screen.open('/') screen.should_contain('42') @@ -291,8 +291,8 @@ async def page(plain: bool = False): def test_warning_about_to_late_responses(screen: Screen): @ui.page('/') - async def page(client: Client): - await client.connected() + async def page(): + await ui.context.get_client().connected() ui.label('NiceGUI page') return PlainTextResponse('custom response') diff --git a/tests/test_storage.py b/tests/test_storage.py index 566bf730b..621287454 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -49,8 +49,8 @@ async def page(): def test_browser_storage_modifications_after_page_load_are_forbidden(screen: Screen): @ui.page('/') - async def page(client: Client): - await client.connected() + async def page(): + await ui.context.get_client().connected() try: app.storage.browser['test'] = 'data' except TypeError as e: @@ -63,9 +63,9 @@ async def page(client: Client): def test_user_storage_modifications(screen: Screen): @ui.page('/') - async def page(client: Client, delayed: bool = False): + async def page(delayed: bool = False): if delayed: - await client.connected() + await ui.context.get_client().connected() app.storage.user['count'] = app.storage.user.get('count', 0) + 1 ui.label().bind_text_from(app.storage.user, 'count') diff --git a/website/documentation/content/page_documentation.py b/website/documentation/content/page_documentation.py index 821a1de1e..56c0d6981 100644 --- a/website/documentation/content/page_documentation.py +++ b/website/documentation/content/page_documentation.py @@ -42,15 +42,13 @@ def page(word: str, count: int): def wait_for_connected_demo(): import asyncio - from nicegui import Client - @ui.page('/wait_for_connection') - async def wait_for_connection(client: Client): + async def wait_for_connection(): ui.label('This text is displayed immediately.') - await client.connected() + await ui.context.get_client().connected() 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 {client.ip} was obtained from the websocket.') + ui.label(f'The IP address {ui.context.get_client().ip} was obtained from the websocket.') ui.link('wait for connection', wait_for_connection) diff --git a/website/documentation/content/storage_documentation.py b/website/documentation/content/storage_documentation.py index b0c7309ff..56ce7590c 100644 --- a/website/documentation/content/storage_documentation.py +++ b/website/documentation/content/storage_documentation.py @@ -118,11 +118,11 @@ def ui_state(): It is also more secure to use such a volatile storage for scenarios like logging into a bank account or accessing a password manager. ''') def tab_storage(): - from nicegui import Client, app + from nicegui import app # @ui.page('/') - # async def index(client: Client): - # await client.connected() + # async def index(): + # await ui.context.get_client().connected() with ui.column(): # HIDE app.storage.tab['count'] = app.storage.tab.get('count', 0) + 1 ui.label(f'Tab reloaded {app.storage.tab["count"]} times') From dd48496c9127b14e7c86ec935ea9c9691c4e9919 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Mon, 22 Apr 2024 17:41:24 +0200 Subject: [PATCH 17/38] try to fix flaky first number test --- tests/test_number.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_number.py b/tests/test_number.py index 3ff9699e8..68379d149 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -7,14 +7,15 @@ def test_number_input(screen: Screen): - ui.number('Number') + ui.number('Number', value=42) ui.button('Button') screen.open('/') + screen.should_contain_input('42') element = screen.selenium.find_element(By.XPATH, '//*[@aria-label="Number"]') - element.send_keys('42') + element.send_keys('00') screen.click('Button') - screen.should_contain_input('42') + screen.should_contain_input('4200') def test_apply_format_on_blur(screen: Screen): From f7c08cfd975c312dace6b4aacf2c61466e9340d6 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Mon, 22 Apr 2024 17:58:58 +0200 Subject: [PATCH 18/38] UI context properties (#2905) * provide ui.context * use ui.context instead of page injector * add `context` to `__all__` * remove unnecessary file * introduce a context class * deprecate getter methods in favor of properties * fix pytests * remove context imports and use ui.context instead * replace some outdated calls to get_client() --------- Co-authored-by: Rodja Trappe --- examples/chat_app/main.py | 2 +- examples/descope_auth/user.py | 2 +- examples/download_text_as_file/main.py | 2 +- examples/infinite_scroll/main.py | 2 +- nicegui/__init__.py | 3 +- nicegui/context.py | 50 +++++++++++++------ nicegui/element.py | 7 +-- nicegui/elements/carousel.py | 4 +- nicegui/elements/notification.py | 4 +- nicegui/elements/query.py | 4 +- nicegui/elements/stepper.py | 4 +- nicegui/elements/tabs.py | 4 +- nicegui/functions/download.py | 5 +- nicegui/functions/html.py | 6 +-- nicegui/functions/javascript.py | 4 +- nicegui/functions/navigate.py | 4 +- nicegui/functions/notify.py | 4 +- nicegui/functions/on.py | 6 +-- nicegui/functions/page_title.py | 5 +- nicegui/page_layout.py | 10 ++-- nicegui/storage.py | 11 ++-- nicegui/ui.py | 2 +- tests/test_auto_context.py | 4 +- tests/test_interactive_image.py | 2 +- tests/test_javascript.py | 2 +- tests/test_lifecycle.py | 2 +- tests/test_page.py | 18 +++---- tests/test_storage.py | 12 ++--- .../content/generic_events_documentation.py | 4 +- .../content/page_documentation.py | 4 +- .../content/query_documentation.py | 6 +-- .../content/storage_documentation.py | 2 +- website/main_page.py | 4 +- website/style.py | 4 +- 34 files changed, 118 insertions(+), 91 deletions(-) diff --git a/examples/chat_app/main.py b/examples/chat_app/main.py index cf91bab18..e62b3c6b4 100755 --- a/examples/chat_app/main.py +++ b/examples/chat_app/main.py @@ -36,7 +36,7 @@ def send() -> None: ui.markdown('simple chat app built with [NiceGUI](https://nicegui.io)') \ .classes('text-xs self-end mr-8 m-[-1em] text-primary') - await ui.context.get_client().connected() # chat_messages(...) uses run_javascript which is only possible after connecting + await ui.context.client.connected() # chat_messages(...) uses run_javascript which is only possible after connecting with ui.column().classes('w-full max-w-2xl mx-auto items-stretch'): chat_messages(user_id) diff --git a/examples/descope_auth/user.py b/examples/descope_auth/user.py index 33d26409d..fa5f6afcc 100644 --- a/examples/descope_auth/user.py +++ b/examples/descope_auth/user.py @@ -61,7 +61,7 @@ async def content(): const sessionToken = sdk.getSessionToken() ''') - await ui.context.get_client().connected() + await ui.context.client.connected() if await self._is_logged_in(): if self.path == self.LOGIN_PATH: self._refresh() diff --git a/examples/download_text_as_file/main.py b/examples/download_text_as_file/main.py index 4e9935254..9ed242b07 100755 --- a/examples/download_text_as_file/main.py +++ b/examples/download_text_as_file/main.py @@ -21,7 +21,7 @@ def download(): ui.button('Download', on_click=lambda: ui.download(download_path)) # cleanup the download route after the client disconnected - await ui.context.get_client().disconnected() + await ui.context.client.disconnected() app.routes[:] = [route for route in app.routes if route.path != download_path] ui.run() diff --git a/examples/infinite_scroll/main.py b/examples/infinite_scroll/main.py index 7f63bb1da..fd376c615 100755 --- a/examples/infinite_scroll/main.py +++ b/examples/infinite_scroll/main.py @@ -9,7 +9,7 @@ async def page(): async def check(): if await ui.run_javascript('window.pageYOffset >= document.body.offsetHeight - 2 * window.innerHeight'): ui.image(f'https://picsum.photos/640/360?{time.time()}') - await ui.context.get_client().connected() + await ui.context.client.connected() ui.timer(0.1, check) diff --git a/nicegui/__init__.py b/nicegui/__init__.py index 710da8577..9532eef86 100644 --- a/nicegui/__init__.py +++ b/nicegui/__init__.py @@ -1,7 +1,8 @@ -from . import context, elements, run, ui +from . import elements, run, ui from .api_router import APIRouter from .app.app import App from .client import Client +from .context import context from .nicegui import app from .tailwind import Tailwind from .version import __version__ diff --git a/nicegui/context.py b/nicegui/context.py index 4d9e98006..929125a66 100644 --- a/nicegui/context.py +++ b/nicegui/context.py @@ -2,27 +2,49 @@ from typing import TYPE_CHECKING, List +from .logging import log from .slot import Slot if TYPE_CHECKING: from .client import Client -def get_slot_stack() -> List[Slot]: - """Return the slot stack of the current asyncio task.""" - return Slot.get_stack() +class Context: + def get_slot_stack(self) -> List[Slot]: + """Return the slot stack of the current asyncio task. (DEPRECATED, use context.slot_stack instead)""" + log.warning('context.get_slot_stack() is deprecated, use context.slot_stack instead') + return self.slot_stack -def get_slot() -> Slot: - """Return the current slot.""" - slot_stack = get_slot_stack() - if not slot_stack: - raise RuntimeError('The current slot cannot be determined because the slot stack for this task is empty.\n' - 'This may happen if you try to create UI from a background task.\n' - 'To fix this, enter the target slot explicitly using `with container_element:`.') - return slot_stack[-1] + def get_slot(self) -> Slot: + """Return the current slot. (DEPRECATED, use context.slot instead)""" + log.warning('context.get_slot() is deprecated, use context.slot instead') + return self.slot + def get_client(self) -> Client: + """Return the current client. (DEPRECATED, use context.client instead)""" + log.warning('context.get_client() is deprecated, use context.client instead') + return self.client -def get_client() -> Client: - """Return the current client.""" - return get_slot().parent.client + @property + def slot_stack(self) -> List[Slot]: + """Return the slot stack of the current asyncio task.""" + return Slot.get_stack() + + @property + def slot(self) -> Slot: + """Return the current slot.""" + slot_stack = self.slot_stack + if not slot_stack: + raise RuntimeError('The current slot cannot be determined because the slot stack for this task is empty.\n' + 'This may happen if you try to create UI from a background task.\n' + 'To fix this, enter the target slot explicitly using `with container_element:`.') + return slot_stack[-1] + + @property + def client(self) -> Client: + """Return the current client.""" + return self.slot.parent.client + + +context = Context() diff --git a/nicegui/element.py b/nicegui/element.py index cbd7f7ade..c5556d8cf 100644 --- a/nicegui/element.py +++ b/nicegui/element.py @@ -9,8 +9,9 @@ from typing_extensions import Self -from . import context, core, events, helpers, json, storage +from . import core, events, helpers, json, storage from .awaitable_response import AwaitableResponse, NullResponse +from .context import context from .dependencies import Component, Library, register_library, register_resource, register_vue_component from .elements.mixins.visibility import Visibility from .event_listener import EventListener @@ -72,7 +73,7 @@ def __init__(self, tag: Optional[str] = None, *, _client: Optional[Client] = Non :param _client: client for this element (for internal use only) """ super().__init__() - self.client = _client or context.get_client() + self.client = _client or context.client self.id = self.client.next_element_id self.client.next_element_id += 1 self.tag = tag if tag else self.component.tag if self.component else 'div' @@ -92,7 +93,7 @@ def __init__(self, tag: Optional[str] = None, *, _client: Optional[Client] = Non self.client.elements[self.id] = self self.parent_slot: Optional[Slot] = None - slot_stack = context.get_slot_stack() + slot_stack = context.slot_stack if slot_stack: self.parent_slot = slot_stack[-1] self.parent_slot.children.append(self) diff --git a/nicegui/elements/carousel.py b/nicegui/elements/carousel.py index d1899d897..bea26c569 100644 --- a/nicegui/elements/carousel.py +++ b/nicegui/elements/carousel.py @@ -2,7 +2,7 @@ from typing import Any, Callable, Optional, Union, cast -from .. import context +from ..context import context from .mixins.disableable_element import DisableableElement from .mixins.value_element import ValueElement @@ -62,7 +62,7 @@ def __init__(self, name: Optional[str] = None) -> None: :param name: name of the slide (will be the value of the `ui.carousel` element, auto-generated if `None`) """ super().__init__(tag='q-carousel-slide') - self.carousel = cast(ValueElement, context.get_slot().parent) + self.carousel = cast(ValueElement, context.slot.parent) name = name or f'slide_{len(self.carousel.default_slot.children)}' self._props['name'] = name self._classes.append('nicegui-carousel-slide') diff --git a/nicegui/elements/notification.py b/nicegui/elements/notification.py index 41b6d9db7..54649fe80 100644 --- a/nicegui/elements/notification.py +++ b/nicegui/elements/notification.py @@ -1,6 +1,6 @@ from typing import Any, Literal, Optional, Union -from .. import context +from ..context import context from ..element import Element from .timer import Timer @@ -57,7 +57,7 @@ def __init__(self, Note: You can pass additional keyword arguments according to `Quasar's Notify API `_. """ - with context.get_client().layout: + with context.client.layout: super().__init__() self._props['options'] = { 'message': str(message), diff --git a/nicegui/elements/query.py b/nicegui/elements/query.py index 0c3893553..2c9e85a1c 100644 --- a/nicegui/elements/query.py +++ b/nicegui/elements/query.py @@ -2,7 +2,7 @@ from typing_extensions import Self -from .. import context +from ..context import context from ..element import Element @@ -64,7 +64,7 @@ def __init__(self, selector: str) -> None: :param selector: the CSS selector (e.g. "body", "#my-id", ".my-class", "div > p") """ - for element in context.get_client().elements.values(): + for element in context.client.elements.values(): if isinstance(element, QueryElement) and element._props['selector'] == selector: # pylint: disable=protected-access self.element = element break diff --git a/nicegui/elements/stepper.py b/nicegui/elements/stepper.py index 390dac973..5e9991b4e 100644 --- a/nicegui/elements/stepper.py +++ b/nicegui/elements/stepper.py @@ -2,7 +2,7 @@ from typing import Any, Callable, Optional, Union, cast -from .. import context +from ..context import context from ..element import Element from .mixins.disableable_element import DisableableElement from .mixins.value_element import ValueElement @@ -69,7 +69,7 @@ def __init__(self, name: str, title: Optional[str] = None, icon: Optional[str] = self._classes.append('nicegui-step') if icon: self._props['icon'] = icon - self.stepper = cast(ValueElement, context.get_slot().parent) + self.stepper = cast(ValueElement, context.slot.parent) if self.stepper.value is None: self.stepper.value = name diff --git a/nicegui/elements/tabs.py b/nicegui/elements/tabs.py index 337498835..204dc0b07 100644 --- a/nicegui/elements/tabs.py +++ b/nicegui/elements/tabs.py @@ -2,7 +2,7 @@ from typing import Any, Callable, Optional, Union -from .. import context +from ..context import context from .mixins.disableable_element import DisableableElement from .mixins.value_element import ValueElement @@ -44,7 +44,7 @@ def __init__(self, name: str, label: Optional[str] = None, icon: Optional[str] = self._props['label'] = label if label is not None else name if icon: self._props['icon'] = icon - self.tabs = context.get_slot().parent + self.tabs = context.slot.parent class TabPanels(ValueElement): diff --git a/nicegui/functions/download.py b/nicegui/functions/download.py index 82342e8ba..1ad1ec10e 100644 --- a/nicegui/functions/download.py +++ b/nicegui/functions/download.py @@ -1,7 +1,8 @@ from pathlib import Path from typing import Optional, Union -from .. import context, core, helpers +from .. import core, helpers +from ..context import context def download(src: Union[str, Path, bytes], filename: Optional[str] = None, media_type: str = '') -> None: @@ -18,4 +19,4 @@ def download(src: Union[str, Path, bytes], filename: Optional[str] = None, media src = core.app.add_static_file(local_file=src, single_use=True) else: src = str(src) - context.get_client().download(src, filename, media_type) + context.client.download(src, filename, media_type) diff --git a/nicegui/functions/html.py b/nicegui/functions/html.py index bebd63127..3d2d1150d 100644 --- a/nicegui/functions/html.py +++ b/nicegui/functions/html.py @@ -1,5 +1,5 @@ -from .. import context from ..client import Client +from ..context import context def add_head_html(code: str, *, shared: bool = False) -> None: @@ -11,7 +11,7 @@ def add_head_html(code: str, *, shared: bool = False) -> None: if shared: Client.shared_head_html += code + '\n' else: - client = context.get_client() + client = context.client if client.has_socket_connection: client.run_javascript(f'document.head.insertAdjacentHTML("beforeend", {code!r});') client._head_html += code + '\n' # pylint: disable=protected-access @@ -26,7 +26,7 @@ def add_body_html(code: str, *, shared: bool = False) -> None: if shared: Client.shared_body_html += code + '\n' else: - client = context.get_client() + client = context.client if client.has_socket_connection: client.run_javascript(f'document.querySelector("#app").insertAdjacentHTML("beforebegin", {code!r});') client._body_html += code + '\n' # pylint: disable=protected-access diff --git a/nicegui/functions/javascript.py b/nicegui/functions/javascript.py index 2466f890a..9ec9bec96 100644 --- a/nicegui/functions/javascript.py +++ b/nicegui/functions/javascript.py @@ -1,7 +1,7 @@ from typing import Optional -from .. import context from ..awaitable_response import AwaitableResponse +from ..context import context def run_javascript(code: str, *, @@ -21,4 +21,4 @@ def run_javascript(code: str, *, :return: AwaitableResponse that can be awaited to get the result of the JavaScript code """ - return context.get_client().run_javascript(code, respond=respond, timeout=timeout, check_interval=check_interval) + return context.client.run_javascript(code, respond=respond, timeout=timeout, check_interval=check_interval) diff --git a/nicegui/functions/navigate.py b/nicegui/functions/navigate.py index 8e15751f8..84c045488 100644 --- a/nicegui/functions/navigate.py +++ b/nicegui/functions/navigate.py @@ -1,7 +1,7 @@ from typing import Any, Callable, Union -from .. import context from ..client import Client +from ..context import context from ..element import Element from .javascript import run_javascript @@ -64,4 +64,4 @@ def to(target: Union[Callable[..., Any], str, Element], new_tab: bool = False) - path = f'#c{target.id}' elif callable(target): path = Client.page_routes[target] - context.get_client().open(path, new_tab) + context.client.open(path, new_tab) diff --git a/nicegui/functions/notify.py b/nicegui/functions/notify.py index 4aac76c7c..91522f346 100644 --- a/nicegui/functions/notify.py +++ b/nicegui/functions/notify.py @@ -1,6 +1,6 @@ from typing import Any, Literal, Optional, Union -from .. import context +from ..context import context ARG_MAP = { 'close_button': 'closeBtn', @@ -49,5 +49,5 @@ def notify(message: Any, *, options = {ARG_MAP.get(key, key): value for key, value in locals().items() if key != 'kwargs' and value is not None} options['message'] = str(message) options.update(kwargs) - client = context.get_client() + client = context.client client.outbox.enqueue_message('notify', options, client.id) diff --git a/nicegui/functions/on.py b/nicegui/functions/on.py index 1352c1fb1..5fafc3d9e 100644 --- a/nicegui/functions/on.py +++ b/nicegui/functions/on.py @@ -1,6 +1,6 @@ from typing import Any, Callable, Optional, Sequence, Union -from .. import context +from ..context import context def on(type: str, # pylint: disable=redefined-builtin @@ -19,5 +19,5 @@ def on(type: str, # pylint: disable=redefined-builtin :param leading_events: whether to trigger the event handler immediately upon the first event occurrence (default: `True`) :param trailing_events: whether to trigger the event handler after the last event occurrence (default: `True`) """ - context.get_client().layout.on(type, handler, args, - throttle=throttle, leading_events=leading_events, trailing_events=trailing_events) + context.client.layout.on(type, handler, args, + throttle=throttle, leading_events=leading_events, trailing_events=trailing_events) diff --git a/nicegui/functions/page_title.py b/nicegui/functions/page_title.py index ee406ce7f..3aae37a3b 100644 --- a/nicegui/functions/page_title.py +++ b/nicegui/functions/page_title.py @@ -1,4 +1,5 @@ -from .. import context, json +from .. import json +from ..context import context def page_title(title: str) -> None: @@ -8,7 +9,7 @@ def page_title(title: str) -> None: :param title: page title """ - client = context.get_client() + client = context.client client.title = title if client.has_socket_connection: client.run_javascript(f'document.title = {json.dumps(title)}') diff --git a/nicegui/page_layout.py b/nicegui/page_layout.py index 5e30dca46..87afd09e3 100644 --- a/nicegui/page_layout.py +++ b/nicegui/page_layout.py @@ -1,6 +1,6 @@ from typing import Literal, Optional -from . import context +from .context import context from .element import Element from .elements.mixins.value_element import ValueElement from .functions.html import add_body_html @@ -45,7 +45,7 @@ def __init__(self, *, :param add_scroll_padding: whether to automatically prevent link targets from being hidden behind the header (default: `True`) """ _check_current_slot(self) - with context.get_client().layout: + with context.client.layout: super().__init__(tag='q-header', value=value, on_value_change=None) self._classes.append('nicegui-header') self._props['bordered'] = bordered @@ -109,7 +109,7 @@ def __init__(self, :param bottom_corner: whether the drawer expands into the bottom corner (default: `False`) """ _check_current_slot(self) - with context.get_client().layout: + with context.client.layout: super().__init__('q-drawer') if value is None: self._props['show-if-above'] = True @@ -228,7 +228,7 @@ def __init__(self, *, :param wrap: whether the footer should wrap its content (default: `True`) """ _check_current_slot(self) - with context.get_client().layout: + with context.client.layout: super().__init__(tag='q-footer', value=value, on_value_change=None) self.classes('nicegui-footer') self._props['bordered'] = bordered @@ -271,7 +271,7 @@ def __init__(self, position: PageStickyPositions = 'bottom-right', x_offset: flo def _check_current_slot(element: Element) -> None: - parent = context.get_slot().parent + parent = context.slot.parent if parent != parent.client.content: log.warning(f'Found top level layout element "{element.__class__.__name__}" inside element "{parent.__class__.__name__}". ' 'Top level layout elements should not be nested but must be direct children of the page content. ' diff --git a/nicegui/storage.py b/nicegui/storage.py index 1cbdecfe8..fa717b044 100644 --- a/nicegui/storage.py +++ b/nicegui/storage.py @@ -15,7 +15,8 @@ from starlette.requests import Request from starlette.responses import Response -from . import background_tasks, context, core, json, observables +from . import background_tasks, core, json, observables +from .context import context from .logging import log from .observables import ObservableDict @@ -148,7 +149,7 @@ def user(self) -> PersistentDict: @staticmethod def _is_in_auto_index_context() -> bool: try: - return context.get_client().is_auto_index_client + return context.client.is_auto_index_client except RuntimeError: return False # no client @@ -167,7 +168,7 @@ def client(self) -> ObservableDict: if self._is_in_auto_index_context(): raise RuntimeError('app.storage.client can only be used with page builder functions ' '(https://nicegui.io/documentation/page)') - return context.get_client().storage + return context.client.storage @property def tab(self) -> observables.ObservableDict: @@ -175,7 +176,7 @@ def tab(self) -> observables.ObservableDict: if self._is_in_auto_index_context(): raise RuntimeError('app.storage.tab can only be used with page builder functions ' '(https://nicegui.io/documentation/page)') - client = context.get_client() + client = context.client if not client.has_socket_connection: raise RuntimeError('app.storage.tab can only be used with a client connection; ' 'see https://nicegui.io/documentation/page#wait_for_client_connection to await it') @@ -197,7 +198,7 @@ def clear(self) -> None: self._general.clear() self._users.clear() try: - client = context.get_client() + client = context.client except RuntimeError: pass # no client, could be a pytest else: diff --git a/nicegui/ui.py b/nicegui/ui.py index fe3faba69..76adb0dca 100644 --- a/nicegui/ui.py +++ b/nicegui/ui.py @@ -122,7 +122,7 @@ 'run_with', ] -from . import context +from .context import context from .element import Element as element from .elements.aggrid import AgGrid as aggrid from .elements.audio import Audio as audio diff --git a/tests/test_auto_context.py b/tests/test_auto_context.py index 92afc8dc0..797561e5a 100644 --- a/tests/test_auto_context.py +++ b/tests/test_auto_context.py @@ -2,7 +2,7 @@ from selenium.webdriver.common.by import By -from nicegui import Client, background_tasks, ui +from nicegui import background_tasks, ui from nicegui.testing import Screen @@ -52,7 +52,7 @@ def test_autoupdate_after_connected(screen: Screen): @ui.page('/') async def page(): ui.label('before connected') - await ui.context.get_client().connected() + await ui.context.client.connected() ui.label('after connected') await asyncio.sleep(1) ui.label('one') diff --git a/tests/test_interactive_image.py b/tests/test_interactive_image.py index facdbcef1..902bac2e5 100644 --- a/tests/test_interactive_image.py +++ b/tests/test_interactive_image.py @@ -20,7 +20,7 @@ async def page(): img = ui.interactive_image() with ui.tab_panel('B'): ui.label('Tab B') - await ui.context.get_client().connected() + await ui.context.client.connected() img.set_source('https://picsum.photos/id/29/640/360') screen.open('/') diff --git a/tests/test_javascript.py b/tests/test_javascript.py index 39eeca279..d88ecc05c 100644 --- a/tests/test_javascript.py +++ b/tests/test_javascript.py @@ -16,7 +16,7 @@ def test_run_javascript_on_value_change(screen: Screen): @ui.page('/') async def page(): ui.radio(['A', 'B'], on_change=lambda e: ui.run_javascript(f'document.title = "Page {e.value}"')) - await ui.context.get_client().connected() + await ui.context.client.connected() ui.run_javascript('document.title = "Initial Title"') screen.open('/') diff --git a/tests/test_lifecycle.py b/tests/test_lifecycle.py index bfe60728f..446b2367a 100644 --- a/tests/test_lifecycle.py +++ b/tests/test_lifecycle.py @@ -35,7 +35,7 @@ def test_connect_disconnect_is_called_for_each_client(screen: Screen): @ui.page('/', reconnect_timeout=0) def page(): - ui.label(f'client id: {ui.context.get_client().id}') + ui.label(f'client id: {ui.context.client.id}') app.on_connect(lambda: events.append('connect')) app.on_disconnect(lambda: events.append('disconnect')) diff --git a/tests/test_page.py b/tests/test_page.py index e83d0a8a3..5ea37b556 100644 --- a/tests/test_page.py +++ b/tests/test_page.py @@ -120,7 +120,7 @@ async def takes_a_while() -> None: async def page(): nonlocal label label = ui.label() - await ui.context.get_client().connected() + await ui.context.client.connected() await load() screen.open('/') @@ -132,9 +132,9 @@ def test_wait_for_disconnect(screen: Screen): @ui.page('/', reconnect_timeout=0) async def page(): - await ui.context.get_client().connected() + await ui.context.client.connected() events.append('connected') - await ui.context.get_client().disconnected() + await ui.context.client.disconnected() events.append('disconnected') screen.open('/') @@ -149,7 +149,7 @@ def test_wait_for_disconnect_without_awaiting_connected(screen: Screen): @ui.page('/', reconnect_timeout=0) async def page(): - await ui.context.get_client().disconnected() + await ui.context.client.disconnected() events.append('disconnected') screen.open('/') @@ -163,7 +163,7 @@ def test_adding_elements_after_connected(screen: Screen): @ui.page('/') async def page(): ui.label('before') - await ui.context.get_client().connected() + await ui.context.client.connected() ui.label('after') screen.open('/') @@ -185,7 +185,7 @@ def page(): def test_exception_after_connected(screen: Screen): @ui.page('/') async def page(): - await ui.context.get_client().connected() + await ui.context.client.connected() ui.label('this is shown') raise RuntimeError('some exception') @@ -207,7 +207,7 @@ def test_adding_elements_during_onconnect(screen: Screen): @ui.page('/') def page(): ui.label('Label 1') - ui.context.get_client().on_connect(lambda: ui.label('Label 2')) + ui.context.client.on_connect(lambda: ui.label('Label 2')) screen.open('/') screen.should_contain('Label 2') @@ -219,7 +219,7 @@ def page(): async def run_js(): result.text = await ui.run_javascript('41 + 1') result = ui.label() - ui.context.get_client().on_connect(run_js) + ui.context.client.on_connect(run_js) screen.open('/') screen.should_contain('42') @@ -292,7 +292,7 @@ async def page(plain: bool = False): def test_warning_about_to_late_responses(screen: Screen): @ui.page('/') async def page(): - await ui.context.get_client().connected() + await ui.context.client.connected() ui.label('NiceGUI page') return PlainTextResponse('custom response') diff --git a/tests/test_storage.py b/tests/test_storage.py index 621287454..cbe96f95f 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -4,7 +4,7 @@ import httpx import pytest -from nicegui import Client, app, background_tasks, context, ui +from nicegui import app, background_tasks, context, ui from nicegui import storage as storage_module from nicegui.testing import Screen @@ -50,7 +50,7 @@ async def page(): def test_browser_storage_modifications_after_page_load_are_forbidden(screen: Screen): @ui.page('/') async def page(): - await ui.context.get_client().connected() + await ui.context.client.connected() try: app.storage.browser['test'] = 'data' except TypeError as e: @@ -65,7 +65,7 @@ def test_user_storage_modifications(screen: Screen): @ui.page('/') async def page(delayed: bool = False): if delayed: - await ui.context.get_client().connected() + await ui.context.client.connected() app.storage.user['count'] = app.storage.user.get('count', 0) + 1 ui.label().bind_text_from(app.storage.user, 'count') @@ -170,7 +170,7 @@ def test_rapid_storage(screen: Screen): def test_tab_storage_is_local(screen: Screen): @ui.page('/') async def page(): - await context.get_client().connected() + await context.client.connected() app.storage.tab['count'] = app.storage.tab.get('count', 0) + 1 ui.label().bind_text_from(app.storage.tab, 'count') @@ -194,7 +194,7 @@ def test_tab_storage_is_auto_removed(screen: Screen): @ui.page('/') async def page(): - await context.get_client().connected() + await context.client.connected() app.storage.tab['count'] = app.storage.tab.get('count', 0) + 1 ui.label().bind_text_from(app.storage.tab, 'count') @@ -213,7 +213,7 @@ def test_clear_tab_storage(screen: Screen): @ui.page('/') async def page(): - await context.get_client().connected() + await context.client.connected() app.storage.tab['test'] = '123' ui.button('clear', on_click=app.storage.clear) diff --git a/website/documentation/content/generic_events_documentation.py b/website/documentation/content/generic_events_documentation.py index 5351b387f..c617212f3 100644 --- a/website/documentation/content/generic_events_documentation.py +++ b/website/documentation/content/generic_events_documentation.py @@ -1,4 +1,4 @@ -from nicegui import context, ui +from nicegui import ui from . import doc @@ -116,7 +116,7 @@ async def custom_events() -> None: # # ''') # END OF DEMO - await context.get_client().connected() + await ui.context.client.connected() ui.run_javascript(''' document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') { diff --git a/website/documentation/content/page_documentation.py b/website/documentation/content/page_documentation.py index 56c0d6981..c7b74c4d6 100644 --- a/website/documentation/content/page_documentation.py +++ b/website/documentation/content/page_documentation.py @@ -45,10 +45,10 @@ def wait_for_connected_demo(): @ui.page('/wait_for_connection') async def wait_for_connection(): ui.label('This text is displayed immediately.') - await ui.context.get_client().connected() + await ui.context.client.connected() 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 {ui.context.get_client().ip} was obtained from the websocket.') + ui.label(f'The IP address {ui.context.client.ip} was obtained from the websocket.') ui.link('wait for connection', wait_for_connection) diff --git a/website/documentation/content/query_documentation.py b/website/documentation/content/query_documentation.py index ab4a56343..d891d7690 100644 --- a/website/documentation/content/query_documentation.py +++ b/website/documentation/content/query_documentation.py @@ -1,4 +1,4 @@ -from nicegui import context, ui +from nicegui import ui from . import doc @@ -22,7 +22,7 @@ def set_background(color: str) -> None: def background_image(): # ui.query('body').classes('bg-gradient-to-t from-blue-400 to-blue-100') # END OF DEMO - context.get_slot_stack()[-1].parent.classes('bg-gradient-to-t from-blue-400 to-blue-100') + ui.context.slot_stack[-1].parent.classes('bg-gradient-to-t from-blue-400 to-blue-100') @doc.demo('Modify default page padding', ''' @@ -31,7 +31,7 @@ def background_image(): ''') def remove_padding(): # ui.query('.nicegui-content').classes('p-0') - context.get_slot_stack()[-1].parent.classes(remove='p-4') # HIDE + ui.context.slot_stack[-1].parent.classes(remove='p-4') # HIDE # with ui.column().classes('h-screen w-full bg-gray-400 justify-between'): with ui.column().classes('h-full w-full bg-gray-400 justify-between'): # HIDE ui.label('top left') diff --git a/website/documentation/content/storage_documentation.py b/website/documentation/content/storage_documentation.py index 56ce7590c..013e53fad 100644 --- a/website/documentation/content/storage_documentation.py +++ b/website/documentation/content/storage_documentation.py @@ -122,7 +122,7 @@ def tab_storage(): # @ui.page('/') # async def index(): - # await ui.context.get_client().connected() + # await ui.context.client.connected() with ui.column(): # HIDE app.storage.tab['count'] = app.storage.tab.get('count', 0) + 1 ui.label(f'Tab reloaded {app.storage.tab["count"]} times') diff --git a/website/main_page.py b/website/main_page.py index 147010485..309aea101 100644 --- a/website/main_page.py +++ b/website/main_page.py @@ -1,4 +1,4 @@ -from nicegui import context, ui +from nicegui import ui from . import documentation, example_card, svg from .examples import examples @@ -8,7 +8,7 @@ def create() -> None: """Create the content of the main page.""" - context.get_client().content.classes('p-0 gap-0') + ui.context.client.content.classes('p-0 gap-0') add_head_html() add_header() diff --git a/website/style.py b/website/style.py index dd29ce955..6248871c1 100644 --- a/website/style.py +++ b/website/style.py @@ -1,7 +1,7 @@ import re from typing import List, Optional -from nicegui import context, ui +from nicegui import ui from .examples import Example @@ -73,7 +73,7 @@ def subheading(text: str, *, link: Optional[str] = None, major: bool = False, an ui.label(text).classes(classes) with ui.link(target=f'#{name}').classes('absolute').style('transform: translateX(-150%)'): ui.icon('link', size='sm').classes('opacity-10 hover:opacity-80') - drawers = [element for element in context.get_client().elements.values() if isinstance(element, ui.left_drawer)] + drawers = [element for element in ui.context.client.elements.values() if isinstance(element, ui.left_drawer)] if drawers: menu = drawers[0] with menu: From efd3bd6982ab061fb1c82b0e835d10208e1ca21c Mon Sep 17 00:00:00 2001 From: CrystalWindSnake <36034954+CrystalWindSnake@users.noreply.github.com> Date: Tue, 23 Apr 2024 13:48:44 +0800 Subject: [PATCH 19/38] fix:add finished event (#2932) --- nicegui/elements/echart.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/nicegui/elements/echart.js b/nicegui/elements/echart.js index 65e958771..3dea057c9 100644 --- a/nicegui/elements/echart.js +++ b/nicegui/elements/echart.js @@ -47,8 +47,16 @@ export default { ]) { this.chart.on(event, (e) => this.$emit(`chart:${event}`, e)); } + + // Prevent interruption of chart animations due to resize operations. + // Note that it's recommended to register the callbacks for such an event before setOption + const finishedCallback = () => { + new ResizeObserver(this.chart.resize).observe(this.$el); + this.chart.off('finished', finishedCallback); + } + this.chart.on('finished', finishedCallback); + this.update_chart(); - new ResizeObserver(this.chart.resize).observe(this.$el); }, beforeDestroy() { this.chart.dispose(); From b4bc24bae3d965e0b58e21d9026ec66ba28ae64d Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Tue, 23 Apr 2024 09:23:23 +0200 Subject: [PATCH 20/38] Revert "fix:add finished event (#2932)" This reverts commit efd3bd6982ab061fb1c82b0e835d10208e1ca21c. --- nicegui/elements/echart.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/nicegui/elements/echart.js b/nicegui/elements/echart.js index 3dea057c9..65e958771 100644 --- a/nicegui/elements/echart.js +++ b/nicegui/elements/echart.js @@ -47,16 +47,8 @@ export default { ]) { this.chart.on(event, (e) => this.$emit(`chart:${event}`, e)); } - - // Prevent interruption of chart animations due to resize operations. - // Note that it's recommended to register the callbacks for such an event before setOption - const finishedCallback = () => { - new ResizeObserver(this.chart.resize).observe(this.$el); - this.chart.off('finished', finishedCallback); - } - this.chart.on('finished', finishedCallback); - this.update_chart(); + new ResizeObserver(this.chart.resize).observe(this.$el); }, beforeDestroy() { this.chart.dispose(); From cb38b0218ddfca5b822cf56b62a84483ccc2f7fb Mon Sep 17 00:00:00 2001 From: Smug <99215486+Smug246@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:09:51 +0100 Subject: [PATCH 21/38] fixed ui.download not working in native mode (#2884) * fixed ui.download not working in native mode * added settings to webview args * added settings to webview args * add app.native.settings to the documentation --------- Co-authored-by: jude Co-authored-by: Falko Schindler --- nicegui/native/native_config.py | 1 + nicegui/native/native_mode.py | 1 + .../documentation/content/section_configuration_deployment.py | 3 +++ 3 files changed, 5 insertions(+) diff --git a/nicegui/native/native_config.py b/nicegui/native/native_config.py index b6f83aff4..6c757639d 100644 --- a/nicegui/native/native_config.py +++ b/nicegui/native/native_config.py @@ -9,4 +9,5 @@ class NativeConfig: start_args: Dict[str, Any] = field(default_factory=dict) window_args: Dict[str, Any] = field(default_factory=dict) + settings: Dict[str, Any] = field(default_factory=dict) main_window: Optional[WindowProxy] = None diff --git a/nicegui/native/native_mode.py b/nicegui/native/native_mode.py index 42085227e..fde7fc36a 100644 --- a/nicegui/native/native_mode.py +++ b/nicegui/native/native_mode.py @@ -42,6 +42,7 @@ def _open_window( 'frameless': frameless, **core.app.native.window_args, } + webview.settings.update(**core.app.native.settings) window = webview.create_window(**window_kwargs) closed = Event() window.events.closed += closed.set diff --git a/website/documentation/content/section_configuration_deployment.py b/website/documentation/content/section_configuration_deployment.py index 994215c96..6e1bfd52d 100644 --- a/website/documentation/content/section_configuration_deployment.py +++ b/website/documentation/content/section_configuration_deployment.py @@ -33,6 +33,8 @@ def urls_demo(): for the `webview.create_window` and `webview.start` functions. Note that these keyword arguments will take precedence over the parameters defined in `ui.run`. + Additionally, you can change `webview.settings` via `app.native.settings`. + In native mode the `app.native.main_window` object allows you to access the underlying window. It is an async version of [`Window` from pywebview](https://pywebview.flowrl.com/guide/api.html#window-object). ''', tab=lambda: ui.label('NiceGUI')) @@ -41,6 +43,7 @@ def native_mode_demo(): app.native.window_args['resizable'] = False app.native.start_args['debug'] = True + app.native.settings['ALLOW_DOWNLOADS'] = True ui.label('app running in native mode') # ui.button('enlarge', on_click=lambda: app.native.main_window.resize(1000, 700)) From 10d8172af807437b01d007fc2647c0ebde7aaeba Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Tue, 23 Apr 2024 17:17:48 +0200 Subject: [PATCH 22/38] handle emoji favicons with \uFE0F "Variation Selector-16" (fixes #2888) --- nicegui/favicon.py | 2 +- tests/test_favicon.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/nicegui/favicon.py b/nicegui/favicon.py index 9a7178781..926df8822 100644 --- a/nicegui/favicon.py +++ b/nicegui/favicon.py @@ -66,7 +66,7 @@ def _is_remote_url(favicon: str) -> bool: def _is_char(favicon: str) -> bool: - return len(favicon) == 1 + return len(favicon) == 1 or '\ufe0f' in favicon def _is_svg(favicon: str) -> bool: diff --git a/tests/test_favicon.py b/tests/test_favicon.py index 75428d6b5..979513cae 100644 --- a/tests/test_favicon.py +++ b/tests/test_favicon.py @@ -1,6 +1,7 @@ from pathlib import Path from typing import Union +import pytest import requests from bs4 import BeautifulSoup @@ -37,13 +38,14 @@ def test_default(screen: Screen): assert_favicon(DEFAULT_FAVICON_PATH) -def test_emoji(screen: Screen): +@pytest.mark.parametrize('emoji', ['👋', '⚔️']) +def test_emoji(emoji: str, screen: Screen): ui.label('Hello, world') - screen.ui_run_kwargs['favicon'] = '👋' + screen.ui_run_kwargs['favicon'] = emoji screen.open('/') assert_favicon_url_starts_with(screen, 'data:image/svg+xml') - assert_favicon(favicon._char_to_svg('👋')) + assert_favicon(favicon._char_to_svg(emoji)) def test_data_url(screen: Screen): From e13cd6313e4cf5e72ad5e035bc7aba5fed440712 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Tue, 23 Apr 2024 17:46:40 +0200 Subject: [PATCH 23/38] Introduce camera parameters for `ui.scene` (#2897) * introduce camera parameters for `ui.scene` * code review --- nicegui/elements/scene.js | 24 +++++++++---- nicegui/elements/scene.py | 34 +++++++++++++++++-- .../content/scene_documentation.py | 14 ++++---- 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/nicegui/elements/scene.js b/nicegui/elements/scene.js index 15410b8cd..50ae6edb0 100644 --- a/nicegui/elements/scene.js +++ b/nicegui/elements/scene.js @@ -65,13 +65,24 @@ export default { window["scene_" + this.$el.id] = this.scene; // NOTE: for selenium tests only - this.look_at = new THREE.Vector3(0, 0, 0); - const aspect = this.width / this.height; if (this.camera_type === "perspective") { - this.camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000); + this.camera = new THREE.PerspectiveCamera( + this.camera_params.fov, + this.width / this.height, + this.camera_params.near, + this.camera_params.far + ); } else { - this.camera = new THREE.OrthographicCamera(-aspect, aspect, 1, -1, 0.1, 1000); + this.camera = new THREE.OrthographicCamera( + (-this.camera_params.size / 2) * (this.width / this.height), + (this.camera_params.size / 2) * (this.width / this.height), + this.camera_params.size / 2, + -this.camera_params.size / 2, + this.camera_params.near, + this.camera_params.far + ); } + this.look_at = new THREE.Vector3(0, 0, 0); this.camera.lookAt(this.look_at); this.camera.up = new THREE.Vector3(0, 0, 1); this.camera.position.set(0, -3, 5); @@ -416,8 +427,8 @@ export default { this.text3d_renderer.setSize(clientWidth, clientHeight); this.camera.aspect = clientWidth / clientHeight; if (this.camera_type === "orthographic") { - this.camera.left = -this.camera.aspect; - this.camera.right = this.camera.aspect; + this.camera.left = (-this.camera.aspect * this.camera_params.size) / 2; + this.camera.right = (this.camera.aspect * this.camera_params.size) / 2; } this.camera.updateProjectionMatrix(); }, @@ -428,6 +439,7 @@ export default { height: Number, grid: Boolean, camera_type: String, + camera_params: Object, drag_constraints: String, }, }; diff --git a/nicegui/elements/scene.py b/nicegui/elements/scene.py index 10292ba16..0ab50d6be 100644 --- a/nicegui/elements/scene.py +++ b/nicegui/elements/scene.py @@ -1,6 +1,6 @@ import asyncio from dataclasses import dataclass -from typing import Any, Callable, Dict, List, Optional, Union +from typing import Any, Callable, Dict, List, Literal, Optional, Union from typing_extensions import Self @@ -20,6 +20,8 @@ @dataclass(**KWONLY_SLOTS) class SceneCamera: + type: Literal['perspective', 'orthographic'] + params: Dict[str, float] x: float = 0 y: float = -3 z: float = 5 @@ -71,6 +73,7 @@ def __init__(self, width: int = 400, height: int = 300, grid: bool = True, + camera: Optional[SceneCamera] = None, on_click: Optional[Callable[..., Any]] = None, on_drag_start: Optional[Callable[..., Any]] = None, on_drag_end: Optional[Callable[..., Any]] = None, @@ -86,6 +89,7 @@ def __init__(self, :param width: width of the canvas :param height: height of the canvas :param grid: whether to display a grid + :param camera: camera definition, either instance of ``ui.scene.perspective_camera`` (default) or ``ui.scene.orthographic_camera`` :param on_click: callback to execute when a 3D object is clicked :param on_drag_start: callback to execute when a 3D object is dragged :param on_drag_end: callback to execute when a 3D object is dropped @@ -95,10 +99,11 @@ def __init__(self, self._props['width'] = width self._props['height'] = height self._props['grid'] = grid - self._props['camera_type'] = 'perspective' + self.camera = camera or self.perspective_camera() + self._props['camera_type'] = self.camera.type + self._props['camera_params'] = self.camera.params self.objects: Dict[str, Object3D] = {} self.stack: List[Union[Object3D, SceneObject]] = [SceneObject()] - self.camera: SceneCamera = SceneCamera() self._click_handlers = [on_click] if on_click else [] self._drag_start_handlers = [on_drag_start] if on_drag_start else [] self._drag_end_handlers = [on_drag_end] if on_drag_end else [] @@ -124,6 +129,29 @@ def on_drag_end(self, callback: Callable[..., Any]) -> Self: self._drag_end_handlers.append(callback) return self + @staticmethod + def perspective_camera(*, fov: float = 75, near: float = 0.1, far: float = 1000) -> SceneCamera: + """Create a perspective camera. + + :param fov: vertical field of view in degrees + :param near: near clipping plane + :param far: far clipping plane + """ + return SceneCamera(type='perspective', params={'fov': fov, 'near': near, 'far': far}) + + @staticmethod + def orthographic_camera(*, size: float = 10, near: float = 0.1, far: float = 1000) -> SceneCamera: + """Create a orthographic camera. + + The size defines the vertical size of the view volume, i.e. the distance between the top and bottom clipping planes. + The left and right clipping planes are set such that the aspect ratio matches the viewport. + + :param size: vertical size of the view volume + :param near: near clipping plane + :param far: far clipping plane + """ + return SceneCamera(type='orthographic', params={'size': size, 'near': near, 'far': far}) + def __enter__(self) -> Self: Object3D.current_scene = self super().__enter__() diff --git a/website/documentation/content/scene_documentation.py b/website/documentation/content/scene_documentation.py index e5a2e8356..039ed5ad8 100644 --- a/website/documentation/content/scene_documentation.py +++ b/website/documentation/content/scene_documentation.py @@ -113,12 +113,14 @@ async def wait_for_init() -> None: scene.move_camera(x=1, y=-1, z=1.5, duration=2) -# @doc.demo('Orthographic Camera', ''' -# You can use the `camera_type` argument to `ui.scene` to use an orthographic instead of a perspective camera. -# ''') -# def orthographic_camera() -> None: -# with ui.scene(camera_type='orthographic').classes('w-full h-64') as scene: -# scene.box() +@doc.demo('Camera Parameters', ''' + You can use the `camera` argument to `ui.scene` to use a custom camera. + This allows you to set the field of view of a perspective camera or the size of an orthographic camera. +''') +def orthographic_camera() -> None: + with ui.scene(camera=ui.scene.orthographic_camera(size=2)) \ + .classes('w-full h-64') as scene: + scene.box() doc.reference(ui.scene) From ec9e3bcf5d07acea3fee3aa6e0fb0075fd82662a Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Wed, 24 Apr 2024 17:04:55 +0200 Subject: [PATCH 24/38] fix min and max setter for ui.number (fixes #2950) --- nicegui/elements/number.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nicegui/elements/number.py b/nicegui/elements/number.py index 6bded2109..9f024cfe2 100644 --- a/nicegui/elements/number.py +++ b/nicegui/elements/number.py @@ -72,7 +72,7 @@ def min(self) -> float: @min.setter def min(self, value: float) -> None: - if self._props['min'] == value: + if self._props.get('min') == value: return self._props['min'] = value self.sanitize() @@ -85,7 +85,7 @@ def max(self) -> float: @max.setter def max(self, value: float) -> None: - if self._props['max'] == value: + if self._props.get('max') == value: return self._props['max'] = value self.sanitize() From 828692738ad57dd26d47d835eaf544be7b2ccfc4 Mon Sep 17 00:00:00 2001 From: Rodja Trappe Date: Thu, 25 Apr 2024 08:40:33 +0200 Subject: [PATCH 25/38] Add class-demo to modularization example and improved structure (#2944) * add class-demo to modularization example and improved structure * note that name of decorated function can be anything * code review --------- Co-authored-by: Falko Schindler --- examples/modularization/api_router_example.py | 24 +++++++++++++++++++ examples/modularization/class_example.py | 18 ++++++++++++++ examples/modularization/example_c.py | 21 ---------------- examples/modularization/example_pages.py | 17 ------------- examples/modularization/function_example.py | 12 ++++++++++ examples/modularization/home_page.py | 3 +++ examples/modularization/main.py | 18 ++++++++------ examples/modularization/theme.py | 8 ++++--- nicegui/page.py | 4 ++++ .../content/section_action_events.py | 2 +- .../section_configuration_deployment.py | 2 +- 11 files changed, 79 insertions(+), 50 deletions(-) create mode 100644 examples/modularization/api_router_example.py create mode 100644 examples/modularization/class_example.py delete mode 100644 examples/modularization/example_c.py delete mode 100644 examples/modularization/example_pages.py create mode 100644 examples/modularization/function_example.py diff --git a/examples/modularization/api_router_example.py b/examples/modularization/api_router_example.py new file mode 100644 index 000000000..ee178c4b8 --- /dev/null +++ b/examples/modularization/api_router_example.py @@ -0,0 +1,24 @@ +import theme +from message import message + +from nicegui import APIRouter, ui + +# NOTE: the APIRouter does not yet work with NiceGUI On Air (see https://github.com/zauberzeug/nicegui/discussions/2792) +router = APIRouter(prefix='/c') + + +@router.page('/') +def example_page(): + with theme.frame('- Page C -'): + message('Page C') + ui.label('This page and its subpages are created using an APIRouter.') + ui.link('Item 1', '/c/items/1').classes('text-xl text-grey-8') + ui.link('Item 2', '/c/items/2').classes('text-xl text-grey-8') + ui.link('Item 3', '/c/items/3').classes('text-xl text-grey-8') + + +@router.page('/items/{id}', dark=True) +def item(item_id: str): + with theme.frame(f'- Page C{item_id} -'): + message(f'Item #{item_id}') + ui.link('go back', router.prefix).classes('text-xl text-grey-8') diff --git a/examples/modularization/class_example.py b/examples/modularization/class_example.py new file mode 100644 index 000000000..b2f666375 --- /dev/null +++ b/examples/modularization/class_example.py @@ -0,0 +1,18 @@ +import theme +from message import message + +from nicegui import ui + + +class ClassExample: + + def __init__(self) -> None: + """The page is created as soon as the class is instantiated. + + This can obviously also be done in a method, if you want to decouple the instantiation of the object from the page creation. + """ + @ui.page('/b') + def page_b(): + with theme.frame('- Page B -'): + message('Page B') + ui.label('This page is defined in a class.') diff --git a/examples/modularization/example_c.py b/examples/modularization/example_c.py deleted file mode 100644 index a06da4de3..000000000 --- a/examples/modularization/example_c.py +++ /dev/null @@ -1,21 +0,0 @@ -import theme -from message import message - -from nicegui import APIRouter, ui - -router = APIRouter(prefix='/c') - - -@router.page('/') -def example_page(): - with theme.frame('- Example C -'): - message('Example C') - for i in range(1, 4): - ui.link(f'Item {i}', f'/c/items/{i}').classes('text-xl text-grey-8') - - -@router.page('/items/{id}', dark=True) -def item(id: str): - with theme.frame(f'- Example C{id} -'): - message(f'Item #{id}') - ui.link('go back', router.prefix).classes('text-xl text-grey-8') diff --git a/examples/modularization/example_pages.py b/examples/modularization/example_pages.py deleted file mode 100644 index 32c6cd978..000000000 --- a/examples/modularization/example_pages.py +++ /dev/null @@ -1,17 +0,0 @@ -import theme -from message import message - -from nicegui import ui - - -def create() -> None: - - @ui.page('/a') - def example_page_a(): - with theme.frame('- Example A -'): - message('Example A') - - @ui.page('/b') - def example_page_b(): - with theme.frame('- Example B -'): - message('Example B') diff --git a/examples/modularization/function_example.py b/examples/modularization/function_example.py new file mode 100644 index 000000000..52b0674cc --- /dev/null +++ b/examples/modularization/function_example.py @@ -0,0 +1,12 @@ +import theme +from message import message + +from nicegui import ui + + +def create() -> None: + @ui.page('/a') + def page_a(): + with theme.frame('- Page A -'): + message('Page A') + ui.label('This page is defined in a function.') diff --git a/examples/modularization/home_page.py b/examples/modularization/home_page.py index a4f70069d..8ccd50f29 100644 --- a/examples/modularization/home_page.py +++ b/examples/modularization/home_page.py @@ -1,5 +1,8 @@ from message import message +from nicegui import ui + def content() -> None: message('This is the home page.').classes('font-bold') + ui.label('Use the menu on the top right to navigate.') diff --git a/examples/modularization/main.py b/examples/modularization/main.py index 064abdd72..4951b16ee 100755 --- a/examples/modularization/main.py +++ b/examples/modularization/main.py @@ -1,23 +1,27 @@ #!/usr/bin/env python3 -import example_c -import example_pages +import api_router_example +import class_example +import function_example import home_page import theme from nicegui import app, ui -# here we use our custom page decorator directly and just put the content creation into a separate function +# Example 1: use a custom page decorator directly and putting the content creation into a separate function @ui.page('/') def index_page() -> None: with theme.frame('Homepage'): home_page.content() -# this call shows that you can also move the whole page creation into a separate file -example_pages.create() +# Example 2: use a function to move the whole page creation into a separate file +function_example.create() -# we can also use the APIRouter as described in https://nicegui.io/documentation/page#modularize_with_apirouter -app.include_router(example_c.router) +# Example 3: use a class to move the whole page creation into a separate file +class_example.ClassExample() + +# Example 4: use APIRouter as described in https://nicegui.io/documentation/page#modularize_with_apirouter +app.include_router(api_router_example.router) ui.run(title='Modularization Example') diff --git a/examples/modularization/theme.py b/examples/modularization/theme.py index e616a4c0b..ad343cc07 100644 --- a/examples/modularization/theme.py +++ b/examples/modularization/theme.py @@ -6,12 +6,14 @@ @contextmanager -def frame(navtitle: str): +def frame(navigation_title: str): """Custom page frame to share the same styling and behavior across all pages""" ui.colors(primary='#6E93D6', secondary='#53B689', accent='#111B1E', positive='#53B689') - with ui.header().classes('justify-between text-white'): + with ui.header(): ui.label('Modularization Example').classes('font-bold') - ui.label(navtitle) + ui.space() + ui.label(navigation_title) + ui.space() with ui.row(): menu() with ui.column().classes('absolute-center items-center'): diff --git a/nicegui/page.py b/nicegui/page.py index 253fbb98c..b89b51a84 100644 --- a/nicegui/page.py +++ b/nicegui/page.py @@ -40,6 +40,10 @@ def __init__(self, This means it is private to the user and not shared with others (as it is done `when placing elements outside of a page decorator `_). + Note: + The name of the decorated function is unused and can be anything. + The page route is determined by the `path` argument and registered globally. + :param path: route of the new page (path must start with '/') :param title: optional page title :param viewport: optional viewport meta tag content diff --git a/website/documentation/content/section_action_events.py b/website/documentation/content/section_action_events.py index 499076543..7f00e829a 100644 --- a/website/documentation/content/section_action_events.py +++ b/website/documentation/content/section_action_events.py @@ -72,7 +72,7 @@ async def async_task(): This is useful for long-running computations that would otherwise block the event loop and make the UI unresponsive. The function returns a future that can be awaited. - **Note:** + Note: The function needs to transfer the whole state of the passed function to the process, which is done with pickle. It is encouraged to create free functions or static methods which get all the data as simple parameters (i.e. no class or UI logic) and return the result, instead of writing it in class properties or global variables. diff --git a/website/documentation/content/section_configuration_deployment.py b/website/documentation/content/section_configuration_deployment.py index 6e1bfd52d..a3d74ea4a 100644 --- a/website/documentation/content/section_configuration_deployment.py +++ b/website/documentation/content/section_configuration_deployment.py @@ -243,7 +243,7 @@ def install_pyinstaller(): doc.text('', ''' - **Note:** + Note: If you're getting an error "TypeError: a bytes-like object is required, not 'str'", try adding the following lines to the top of your `main.py` file: ```py import sys From 64b9f40b44492bca7718e42d4b5ae9dcefd193ef Mon Sep 17 00:00:00 2001 From: Keenan Johnson Date: Thu, 25 Apr 2024 02:51:14 -0700 Subject: [PATCH 26/38] Example: Add zeromq example (#2941) * Example: Add zeromq example This change adds a basic zeromq implementation with nicegui. In order to do this, the zmq python library is used to create a publisher and a subscriber. The main interesting aspect is that the zmq.async library is used to create a subscriber that can be used in an asyncio loop, which is necessary to run the NiceGUI server. * code review * fix end of file --------- Co-authored-by: Falko Schindler --- examples/zeromq/README.md | 37 +++++++++++++++++++++++++++++++ examples/zeromq/images/plot.png | Bin 0 -> 238772 bytes examples/zeromq/main.py | 30 +++++++++++++++++++++++++ examples/zeromq/requirements.txt | 1 + examples/zeromq/zmq-server.py | 21 ++++++++++++++++++ website/examples.py | 1 + 6 files changed, 90 insertions(+) create mode 100644 examples/zeromq/README.md create mode 100644 examples/zeromq/images/plot.png create mode 100755 examples/zeromq/main.py create mode 100644 examples/zeromq/requirements.txt create mode 100755 examples/zeromq/zmq-server.py diff --git a/examples/zeromq/README.md b/examples/zeromq/README.md new file mode 100644 index 000000000..60d4124ae --- /dev/null +++ b/examples/zeromq/README.md @@ -0,0 +1,37 @@ +# Zeromq Example + +This example is a basic Zeromq implementation with NiceGUI. +It shows how to stream data from a ZeroMQ socket to a NiceGUI plot. + +In order to do this, the zmq Python library is used to create a publisher and a subscriber. +The main interesting aspect is that the zmq.async library is used to create a subscriber that can be used in an asyncio loop, which is necessary to run the NiceGUI server. + +## Running the example + +There are two components to this example: the publisher and the NiceGUI server. + +In addition to the normal NiceGUI dependencies, the zmq library must be installed (see requirements.txt). + +### Running the publisher + +The publisher is a simple Python script that sends random data to a ZeroMQ socket. +To run it, simply execute the following command: + +```bash +python zmq-server.py +``` + +### Running the NiceGUI server + +The NiceGUI server is a Python script that creates a plot and updates it with data from the ZeroMQ socket. +To run it, execute the following command: + +```bash +python main.py +``` + +### Results + +Once both the publisher and GUI server are running, you will see an updating plot on the UI. + +![plot](images/plot.png) diff --git a/examples/zeromq/images/plot.png b/examples/zeromq/images/plot.png new file mode 100644 index 0000000000000000000000000000000000000000..9ff8458cadadb259cf671ed90db96ba5baee47c4 GIT binary patch literal 238772 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�$ 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

-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°rN~QFo>)a?NTRm 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

iP|`+xkc5oSD9tDn7?y;J~xn^k`{bQEid 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 V;_ok3*#Q15&RL(WG`)83zW{+!yKw*j literal 0 HcmV?d00001 diff --git a/examples/zeromq/main.py b/examples/zeromq/main.py new file mode 100755 index 000000000..44aff8e1d --- /dev/null +++ b/examples/zeromq/main.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +from datetime import datetime + +import zmq +import zmq.asyncio + +from nicegui import app, ui + +context = zmq.asyncio.Context() +socket = context.socket(zmq.PULL) +socket.connect('tcp://localhost:5555') + +poller = zmq.asyncio.Poller() +poller.register(socket, zmq.POLLIN) + + +async def read_loop() -> None: + while not app.is_stopped: + events = await poller.poll() + if socket in dict(events): + data = await socket.recv() + number = float(data) + print(f'Received number {number}') + line_plot.push([datetime.now()], [[number]]) + +line_plot = ui.line_plot(n=1, limit=100, figsize=(10, 4)) + +app.on_startup(read_loop) + +ui.run() diff --git a/examples/zeromq/requirements.txt b/examples/zeromq/requirements.txt new file mode 100644 index 000000000..70e4087a1 --- /dev/null +++ b/examples/zeromq/requirements.txt @@ -0,0 +1 @@ +pyzmq >= 26.0 diff --git a/examples/zeromq/zmq-server.py b/examples/zeromq/zmq-server.py new file mode 100755 index 000000000..96b8b167b --- /dev/null +++ b/examples/zeromq/zmq-server.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +import asyncio +import random + +import zmq +import zmq.asyncio + +context = zmq.asyncio.Context() +socket = context.socket(zmq.PUSH) +socket.bind('tcp://localhost:5555') + + +async def send_loop(): + while True: + number = random.randint(0, 100) + print(f'Sending number {number}') + await socket.send(str(number).encode('ascii')) + await asyncio.sleep(0.1) + + +asyncio.run(send_loop()) diff --git a/website/examples.py b/website/examples.py index 86f83adf5..f263bb185 100644 --- a/website/examples.py +++ b/website/examples.py @@ -65,4 +65,5 @@ def __post_init__(self) -> None: Example('Webserial', 'communicate with a serial device using the WebSerial API'), Example('Websockets', 'use [websockets library](https://websockets.readthedocs.io/) to start a websocket server'), Example('Audio Recorder', 'Record audio, play it back or download it'), + Example('ZeroMQ', 'Simple ZeroMQ PUSH/PULL server and client'), ] From 5d61a0ee3b85c4bf1e1e0e4c6bdbe04c35f9ae85 Mon Sep 17 00:00:00 2001 From: Aleksandar 'Alex' Gotev Date: Thu, 25 Apr 2024 15:34:50 +0200 Subject: [PATCH 27/38] #2549 feat: added build package script (#2789) * feat: added build package script * code review and refactoring * fix data path * always print the PyInstaller command * fix add-data format * add more description and help text --------- Co-authored-by: Falko Schindler --- nicegui/scripts/pack.py | 71 ++++++++ poetry.lock | 370 ++++++++++++++++++++-------------------- pyproject.toml | 3 + 3 files changed, 259 insertions(+), 185 deletions(-) create mode 100755 nicegui/scripts/pack.py diff --git a/nicegui/scripts/pack.py b/nicegui/scripts/pack.py new file mode 100755 index 000000000..7bb87e01f --- /dev/null +++ b/nicegui/scripts/pack.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +import argparse +import os +import platform +import subprocess +from pathlib import Path + +import nicegui + +DESCRIPTION = ''' +Build a package of your NiceGUI app +----------------------------------- + +NiceGUI apps can be bundled into an executable with PyInstaller. +This allows you to distribute your app as a single file that can be executed on any computer. +Use this script as a starting point to create a package for your app. + +Important: Make sure to run your main script with + + ui.run(reload=False, port=native.find_open_port(), ...) + +to disable the reload server and to automatically find an open port. + +For more information and packaging tips, have a look into the NiceGUI documentation: +https://nicegui.io/documentation/section_configuration_deployment#package_for_installation. +'''.strip() + + +def main() -> None: + parser = argparse.ArgumentParser(description=DESCRIPTION, formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('--name', type=str, default='Your App Name', help='Name of your app.') + parser.add_argument('--windowed', action='store_true', default=False, help=( + 'Prevent a terminal console from appearing.\n' + 'Only use with `ui.run(native=True, ...)`.\n' + 'It will create an `.app` file on Mac which runs without showing any console output.' + )) + parser.add_argument('--onefile', action='store_true', default=False, help=( + 'Create a single executable file.\n' + 'Whilst convenient for distribution, it will be slower to start up.' + )) + parser.add_argument('--add-data', type=str, action='append', default=[ + f'{Path(nicegui.__file__).parent}{os.pathsep}nicegui', + ], help='Include additional data.') + parser.add_argument('--dry-run', action='store_true', help='Dry run', default=False) + parser.add_argument('main', default='main.py', help='Main file which calls `ui.run()`.') + args = parser.parse_args() + + for directory in ['build', 'dist']: + if Path(directory).exists(): + Path(directory).rmdir() + + command = ['pyinstaller'] if platform.system() == 'Windows' else ['python', '-m', 'PyInstaller'] + command.extend(['--name', args.name]) + if args.windowed: + command.append('--windowed') + if args.onefile: + command.append('--onefile') + for data in args.add_data: + command.extend(['--add-data', data]) + command.extend([args.main]) + + print('PyInstaller command:') + print(' ', ' '.join(command)) + if args.dry_run: + return + + subprocess.call(command) + + +if __name__ == '__main__': + main() diff --git a/poetry.lock b/poetry.lock index d0b3f8621..470ef6000 100644 --- a/poetry.lock +++ b/poetry.lock @@ -13,87 +13,87 @@ files = [ [[package]] name = "aiohttp" -version = "3.9.3" +version = "3.9.4" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, - {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, - {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, - {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, - {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, - {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, - {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, - {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, - {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, - {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, - {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, - {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, + {file = "aiohttp-3.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:76d32588ef7e4a3f3adff1956a0ba96faabbdee58f2407c122dd45aa6e34f372"}, + {file = "aiohttp-3.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:56181093c10dbc6ceb8a29dfeea1e815e1dfdc020169203d87fd8d37616f73f9"}, + {file = "aiohttp-3.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7a5b676d3c65e88b3aca41816bf72831898fcd73f0cbb2680e9d88e819d1e4d"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1df528a85fb404899d4207a8d9934cfd6be626e30e5d3a5544a83dbae6d8a7e"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f595db1bceabd71c82e92df212dd9525a8a2c6947d39e3c994c4f27d2fe15b11"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c0b09d76e5a4caac3d27752027fbd43dc987b95f3748fad2b924a03fe8632ad"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:689eb4356649ec9535b3686200b231876fb4cab4aca54e3bece71d37f50c1d13"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3666cf4182efdb44d73602379a66f5fdfd5da0db5e4520f0ac0dcca644a3497"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b65b0f8747b013570eea2f75726046fa54fa8e0c5db60f3b98dd5d161052004a"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1885d2470955f70dfdd33a02e1749613c5a9c5ab855f6db38e0b9389453dce7"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0593822dcdb9483d41f12041ff7c90d4d1033ec0e880bcfaf102919b715f47f1"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:47f6eb74e1ecb5e19a78f4a4228aa24df7fbab3b62d4a625d3f41194a08bd54f"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c8b04a3dbd54de6ccb7604242fe3ad67f2f3ca558f2d33fe19d4b08d90701a89"}, + {file = "aiohttp-3.9.4-cp310-cp310-win32.whl", hash = "sha256:8a78dfb198a328bfb38e4308ca8167028920fb747ddcf086ce706fbdd23b2926"}, + {file = "aiohttp-3.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:e78da6b55275987cbc89141a1d8e75f5070e577c482dd48bd9123a76a96f0bbb"}, + {file = "aiohttp-3.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c111b3c69060d2bafc446917534150fd049e7aedd6cbf21ba526a5a97b4402a5"}, + {file = "aiohttp-3.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:efbdd51872cf170093998c87ccdf3cb5993add3559341a8e5708bcb311934c94"}, + {file = "aiohttp-3.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bfdb41dc6e85d8535b00d73947548a748e9534e8e4fddd2638109ff3fb081df"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bd9d334412961125e9f68d5b73c1d0ab9ea3f74a58a475e6b119f5293eee7ba"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35d78076736f4a668d57ade00c65d30a8ce28719d8a42471b2a06ccd1a2e3063"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:824dff4f9f4d0f59d0fa3577932ee9a20e09edec8a2f813e1d6b9f89ced8293f"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52b8b4e06fc15519019e128abedaeb56412b106ab88b3c452188ca47a25c4093"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eae569fb1e7559d4f3919965617bb39f9e753967fae55ce13454bec2d1c54f09"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:69b97aa5792428f321f72aeb2f118e56893371f27e0b7d05750bcad06fc42ca1"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4d79aad0ad4b980663316f26d9a492e8fab2af77c69c0f33780a56843ad2f89e"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:d6577140cd7db19e430661e4b2653680194ea8c22c994bc65b7a19d8ec834403"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:9860d455847cd98eb67897f5957b7cd69fbcb436dd3f06099230f16a66e66f79"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:69ff36d3f8f5652994e08bd22f093e11cfd0444cea310f92e01b45a4e46b624e"}, + {file = "aiohttp-3.9.4-cp311-cp311-win32.whl", hash = "sha256:e27d3b5ed2c2013bce66ad67ee57cbf614288bda8cdf426c8d8fe548316f1b5f"}, + {file = "aiohttp-3.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d6a67e26daa686a6fbdb600a9af8619c80a332556245fa8e86c747d226ab1a1e"}, + {file = "aiohttp-3.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c5ff8ff44825736a4065d8544b43b43ee4c6dd1530f3a08e6c0578a813b0aa35"}, + {file = "aiohttp-3.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d12a244627eba4e9dc52cbf924edef905ddd6cafc6513849b4876076a6f38b0e"}, + {file = "aiohttp-3.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dcad56c8d8348e7e468899d2fb3b309b9bc59d94e6db08710555f7436156097f"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7e69a7fd4b5ce419238388e55abd220336bd32212c673ceabc57ccf3d05b55"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4870cb049f10d7680c239b55428916d84158798eb8f353e74fa2c98980dcc0b"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2feaf1b7031ede1bc0880cec4b0776fd347259a723d625357bb4b82f62687b"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939393e8c3f0a5bcd33ef7ace67680c318dc2ae406f15e381c0054dd658397de"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d2334e387b2adcc944680bebcf412743f2caf4eeebd550f67249c1c3696be04"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e0198ea897680e480845ec0ffc5a14e8b694e25b3f104f63676d55bf76a82f1a"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e40d2cd22914d67c84824045861a5bb0fb46586b15dfe4f046c7495bf08306b2"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:aba80e77c227f4234aa34a5ff2b6ff30c5d6a827a91d22ff6b999de9175d71bd"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:fb68dc73bc8ac322d2e392a59a9e396c4f35cb6fdbdd749e139d1d6c985f2527"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f3460a92638dce7e47062cf088d6e7663adb135e936cb117be88d5e6c48c9d53"}, + {file = "aiohttp-3.9.4-cp312-cp312-win32.whl", hash = "sha256:32dc814ddbb254f6170bca198fe307920f6c1308a5492f049f7f63554b88ef36"}, + {file = "aiohttp-3.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:63f41a909d182d2b78fe3abef557fcc14da50c7852f70ae3be60e83ff64edba5"}, + {file = "aiohttp-3.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c3770365675f6be220032f6609a8fbad994d6dcf3ef7dbcf295c7ee70884c9af"}, + {file = "aiohttp-3.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:305edae1dea368ce09bcb858cf5a63a064f3bff4767dec6fa60a0cc0e805a1d3"}, + {file = "aiohttp-3.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f121900131d116e4a93b55ab0d12ad72573f967b100e49086e496a9b24523ea"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b71e614c1ae35c3d62a293b19eface83d5e4d194e3eb2fabb10059d33e6e8cbf"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:419f009fa4cfde4d16a7fc070d64f36d70a8d35a90d71aa27670bba2be4fd039"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b39476ee69cfe64061fd77a73bf692c40021f8547cda617a3466530ef63f947"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b33f34c9c7decdb2ab99c74be6443942b730b56d9c5ee48fb7df2c86492f293c"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c78700130ce2dcebb1a8103202ae795be2fa8c9351d0dd22338fe3dac74847d9"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:268ba22d917655d1259af2d5659072b7dc11b4e1dc2cb9662fdd867d75afc6a4"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:17e7c051f53a0d2ebf33013a9cbf020bb4e098c4bc5bce6f7b0c962108d97eab"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:7be99f4abb008cb38e144f85f515598f4c2c8932bf11b65add0ff59c9c876d99"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:d58a54d6ff08d2547656356eea8572b224e6f9bbc0cf55fa9966bcaac4ddfb10"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7673a76772bda15d0d10d1aa881b7911d0580c980dbd16e59d7ba1422b2d83cd"}, + {file = "aiohttp-3.9.4-cp38-cp38-win32.whl", hash = "sha256:e4370dda04dc8951012f30e1ce7956a0a226ac0714a7b6c389fb2f43f22a250e"}, + {file = "aiohttp-3.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:eb30c4510a691bb87081192a394fb661860e75ca3896c01c6d186febe7c88530"}, + {file = "aiohttp-3.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:84e90494db7df3be5e056f91412f9fa9e611fbe8ce4aaef70647297f5943b276"}, + {file = "aiohttp-3.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7d4845f8501ab28ebfdbeab980a50a273b415cf69e96e4e674d43d86a464df9d"}, + {file = "aiohttp-3.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:69046cd9a2a17245c4ce3c1f1a4ff8c70c7701ef222fce3d1d8435f09042bba1"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b73a06bafc8dcc508420db43b4dd5850e41e69de99009d0351c4f3007960019"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:418bb0038dfafeac923823c2e63226179976c76f981a2aaad0ad5d51f2229bca"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71a8f241456b6c2668374d5d28398f8e8cdae4cce568aaea54e0f39359cd928d"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:935c369bf8acc2dc26f6eeb5222768aa7c62917c3554f7215f2ead7386b33748"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74e4e48c8752d14ecfb36d2ebb3d76d614320570e14de0a3aa7a726ff150a03c"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:916b0417aeddf2c8c61291238ce25286f391a6acb6f28005dd9ce282bd6311b6"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9b6787b6d0b3518b2ee4cbeadd24a507756ee703adbac1ab6dc7c4434b8c572a"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:221204dbda5ef350e8db6287937621cf75e85778b296c9c52260b522231940ed"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:10afd99b8251022ddf81eaed1d90f5a988e349ee7d779eb429fb07b670751e8c"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2506d9f7a9b91033201be9ffe7d89c6a54150b0578803cce5cb84a943d075bc3"}, + {file = "aiohttp-3.9.4-cp39-cp39-win32.whl", hash = "sha256:e571fdd9efd65e86c6af2f332e0e95dad259bfe6beb5d15b3c3eca3a6eb5d87b"}, + {file = "aiohttp-3.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:7d29dd5319d20aa3b7749719ac9685fbd926f71ac8c77b2477272725f882072d"}, + {file = "aiohttp-3.9.4.tar.gz", hash = "sha256:6ff71ede6d9a5a58cfb7b6fffc83ab5d4a63138276c771ac91ceaaddf5459644"}, ] [package.dependencies] @@ -1954,18 +1954,18 @@ files = [ [[package]] name = "pydantic" -version = "2.6.4" +version = "2.7.0" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"}, - {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"}, + {file = "pydantic-2.7.0-py3-none-any.whl", hash = "sha256:9dee74a271705f14f9a1567671d144a851c675b072736f0a7b2608fd9e495352"}, + {file = "pydantic-2.7.0.tar.gz", hash = "sha256:b5ecdd42262ca2462e2624793551e80911a1e989f462910bb81aef974b4bb383"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.16.3" +pydantic-core = "2.18.1" typing-extensions = ">=4.6.1" [package.extras] @@ -1973,90 +1973,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.16.3" -description = "" +version = "2.18.1" +description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, - {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, - {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, - {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, - {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, - {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, - {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, - {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, - {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, - {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, - {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, - {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, - {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, - {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ee9cf33e7fe14243f5ca6977658eb7d1042caaa66847daacbd2117adb258b226"}, + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b7bbb97d82659ac8b37450c60ff2e9f97e4eb0f8a8a3645a5568b9334b08b50"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4249b579e75094f7e9bb4bd28231acf55e308bf686b952f43100a5a0be394c"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0491006a6ad20507aec2be72e7831a42efc93193d2402018007ff827dc62926"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ae80f72bb7a3e397ab37b53a2b49c62cc5496412e71bc4f1277620a7ce3f52b"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58aca931bef83217fca7a390e0486ae327c4af9c3e941adb75f8772f8eeb03a1"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be91ad664fc9245404a789d60cba1e91c26b1454ba136d2a1bf0c2ac0c0505a"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:667880321e916a8920ef49f5d50e7983792cf59f3b6079f3c9dac2b88a311d17"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7054fdc556f5421f01e39cbb767d5ec5c1139ea98c3e5b350e02e62201740c7"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:030e4f9516f9947f38179249778709a460a3adb516bf39b5eb9066fcfe43d0e6"}, + {file = "pydantic_core-2.18.1-cp310-none-win32.whl", hash = "sha256:2e91711e36e229978d92642bfc3546333a9127ecebb3f2761372e096395fc649"}, + {file = "pydantic_core-2.18.1-cp310-none-win_amd64.whl", hash = "sha256:9a29726f91c6cb390b3c2338f0df5cd3e216ad7a938762d11c994bb37552edb0"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9ece8a49696669d483d206b4474c367852c44815fca23ac4e48b72b339807f80"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5d83efc109ceddb99abd2c1316298ced2adb4570410defe766851a804fcd5b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7973c381283783cd1043a8c8f61ea5ce7a3a58b0369f0ee0ee975eaf2f2a1b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54c7375c62190a7845091f521add19b0f026bcf6ae674bdb89f296972272e86d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd63cec4e26e790b70544ae5cc48d11b515b09e05fdd5eff12e3195f54b8a586"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:561cf62c8a3498406495cfc49eee086ed2bb186d08bcc65812b75fda42c38294"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68717c38a68e37af87c4da20e08f3e27d7e4212e99e96c3d875fbf3f4812abfc"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d5728e93d28a3c63ee513d9ffbac9c5989de8c76e049dbcb5bfe4b923a9739d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f0f17814c505f07806e22b28856c59ac80cee7dd0fbb152aed273e116378f519"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d816f44a51ba5175394bc6c7879ca0bd2be560b2c9e9f3411ef3a4cbe644c2e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win32.whl", hash = "sha256:09f03dfc0ef8c22622eaa8608caa4a1e189cfb83ce847045eca34f690895eccb"}, + {file = "pydantic_core-2.18.1-cp311-none-win_amd64.whl", hash = "sha256:27f1009dc292f3b7ca77feb3571c537276b9aad5dd4efb471ac88a8bd09024e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win_arm64.whl", hash = "sha256:48dd883db92e92519201f2b01cafa881e5f7125666141a49ffba8b9facc072b0"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b6b0e4912030c6f28bcb72b9ebe4989d6dc2eebcd2a9cdc35fefc38052dd4fe8"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3202a429fe825b699c57892d4371c74cc3456d8d71b7f35d6028c96dfecad31"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3982b0a32d0a88b3907e4b0dc36809fda477f0757c59a505d4e9b455f384b8b"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25595ac311f20e5324d1941909b0d12933f1fd2171075fcff763e90f43e92a0d"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14fe73881cf8e4cbdaded8ca0aa671635b597e42447fec7060d0868b52d074e6"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca976884ce34070799e4dfc6fbd68cb1d181db1eefe4a3a94798ddfb34b8867f"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684d840d2c9ec5de9cb397fcb3f36d5ebb6fa0d94734f9886032dd796c1ead06"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:54764c083bbe0264f0f746cefcded6cb08fbbaaf1ad1d78fb8a4c30cff999a90"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:201713f2f462e5c015b343e86e68bd8a530a4f76609b33d8f0ec65d2b921712a"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd1a9edb9dd9d79fbeac1ea1f9a8dd527a6113b18d2e9bcc0d541d308dae639b"}, + {file = "pydantic_core-2.18.1-cp312-none-win32.whl", hash = "sha256:d5e6b7155b8197b329dc787356cfd2684c9d6a6b1a197f6bbf45f5555a98d411"}, + {file = "pydantic_core-2.18.1-cp312-none-win_amd64.whl", hash = "sha256:9376d83d686ec62e8b19c0ac3bf8d28d8a5981d0df290196fb6ef24d8a26f0d6"}, + {file = "pydantic_core-2.18.1-cp312-none-win_arm64.whl", hash = "sha256:c562b49c96906b4029b5685075fe1ebd3b5cc2601dfa0b9e16c2c09d6cbce048"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3e352f0191d99fe617371096845070dee295444979efb8f27ad941227de6ad09"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0295d52b012cbe0d3059b1dba99159c3be55e632aae1999ab74ae2bd86a33d7"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56823a92075780582d1ffd4489a2e61d56fd3ebb4b40b713d63f96dd92d28144"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd3f79e17b56741b5177bcc36307750d50ea0698df6aa82f69c7db32d968c1c2"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38a5024de321d672a132b1834a66eeb7931959c59964b777e8f32dbe9523f6b1"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ce426ee691319d4767748c8e0895cfc56593d725594e415f274059bcf3cb76"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2adaeea59849ec0939af5c5d476935f2bab4b7f0335b0110f0f069a41024278e"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b6431559676a1079eac0f52d6d0721fb8e3c5ba43c37bc537c8c83724031feb"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85233abb44bc18d16e72dc05bf13848a36f363f83757541f1a97db2f8d58cfd9"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:641a018af4fe48be57a2b3d7a1f0f5dbca07c1d00951d3d7463f0ac9dac66622"}, + {file = "pydantic_core-2.18.1-cp38-none-win32.whl", hash = "sha256:63d7523cd95d2fde0d28dc42968ac731b5bb1e516cc56b93a50ab293f4daeaad"}, + {file = "pydantic_core-2.18.1-cp38-none-win_amd64.whl", hash = "sha256:907a4d7720abfcb1c81619863efd47c8a85d26a257a2dbebdb87c3b847df0278"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aad17e462f42ddbef5984d70c40bfc4146c322a2da79715932cd8976317054de"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:94b9769ba435b598b547c762184bcfc4783d0d4c7771b04a3b45775c3589ca44"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80e0e57cc704a52fb1b48f16d5b2c8818da087dbee6f98d9bf19546930dc64b5"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76b86e24039c35280ceee6dce7e62945eb93a5175d43689ba98360ab31eebc4a"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a05db5013ec0ca4a32cc6433f53faa2a014ec364031408540ba858c2172bb0"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:250ae39445cb5475e483a36b1061af1bc233de3e9ad0f4f76a71b66231b07f88"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32204489259786a923e02990249c65b0f17235073149d0033efcebe80095570"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6395a4435fa26519fd96fdccb77e9d00ddae9dd6c742309bd0b5610609ad7fb2"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2533ad2883f001efa72f3d0e733fb846710c3af6dcdd544fe5bf14fa5fe2d7db"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b560b72ed4816aee52783c66854d96157fd8175631f01ef58e894cc57c84f0f6"}, + {file = "pydantic_core-2.18.1-cp39-none-win32.whl", hash = "sha256:582cf2cead97c9e382a7f4d3b744cf0ef1a6e815e44d3aa81af3ad98762f5a9b"}, + {file = "pydantic_core-2.18.1-cp39-none-win_amd64.whl", hash = "sha256:ca71d501629d1fa50ea7fa3b08ba884fe10cefc559f5c6c8dfe9036c16e8ae89"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e178e5b66a06ec5bf51668ec0d4ac8cfb2bdcb553b2c207d58148340efd00143"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:72722ce529a76a4637a60be18bd789d8fb871e84472490ed7ddff62d5fed620d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fe0c1ce5b129455e43f941f7a46f61f3d3861e571f2905d55cdbb8b5c6f5e2c"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4284c621f06a72ce2cb55f74ea3150113d926a6eb78ab38340c08f770eb9b4d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a0c3e718f4e064efde68092d9d974e39572c14e56726ecfaeebbe6544521f47"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2027493cc44c23b598cfaf200936110433d9caa84e2c6cf487a83999638a96ac"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76909849d1a6bffa5a07742294f3fa1d357dc917cb1fe7b470afbc3a7579d539"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ee7ccc7fb7e921d767f853b47814c3048c7de536663e82fbc37f5eb0d532224b"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee2794111c188548a4547eccc73a6a8527fe2af6cf25e1a4ebda2fd01cdd2e60"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a139fe9f298dc097349fb4f28c8b81cc7a202dbfba66af0e14be5cfca4ef7ce5"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d074b07a10c391fc5bbdcb37b2f16f20fcd9e51e10d01652ab298c0d07908ee2"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c69567ddbac186e8c0aadc1f324a60a564cfe25e43ef2ce81bcc4b8c3abffbae"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf1c7b78cddb5af00971ad5294a4583188bda1495b13760d9f03c9483bb6203"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2684a94fdfd1b146ff10689c6e4e815f6a01141781c493b97342cdc5b06f4d5d"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:73c1bc8a86a5c9e8721a088df234265317692d0b5cd9e86e975ce3bc3db62a59"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e60defc3c15defb70bb38dd605ff7e0fae5f6c9c7cbfe0ad7868582cb7e844a6"}, + {file = "pydantic_core-2.18.1.tar.gz", hash = "sha256:de9d3e8717560eb05e28739d1b35e4eac2e458553a52a301e51352a7ffc86a35"}, ] [package.dependencies] @@ -2570,28 +2570,28 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.3.6" +version = "0.3.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.3.6-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:732ef99984275534f9466fbc01121523caf72aa8c2bdeb36fd2edf2bc294a992"}, - {file = "ruff-0.3.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:93699d61116807edc5ca1cdf9d2d22cf8d93335d59e3ff0ca7aee62c1818a736"}, - {file = "ruff-0.3.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc4006cbc6c11fefc25f122d2eb4731d7a3d815dc74d67c54991cc3f99c90177"}, - {file = "ruff-0.3.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:878ef1a55ce931f3ca23b690b159cd0659f495a4c231a847b00ca55e4c688baf"}, - {file = "ruff-0.3.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecb87788284af96725643eae9ab3ac746d8cc09aad140268523b019f7ac3cd98"}, - {file = "ruff-0.3.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b2e79f8e1b6bd5411d7ddad3f2abff3f9d371beda29daef86400d416dedb7e02"}, - {file = "ruff-0.3.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf48ec2c4bfae7837dc325c431a2932dc23a1485e71c59591c1df471ba234e0e"}, - {file = "ruff-0.3.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c466a52c522e6a08df0af018f550902f154f5649ad09e7f0d43da766e7399ebc"}, - {file = "ruff-0.3.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28ccf3fb6d1162a73cd286c63a5e4d885f46a1f99f0b392924bc95ccbd18ea8f"}, - {file = "ruff-0.3.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b11e09439d9df6cc12d9f622065834654417c40216d271f639512d80e80e3e53"}, - {file = "ruff-0.3.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:647f1fb5128a3e24ce68878b8050bb55044c45bb3f3ae4710d4da9ca96ede5cb"}, - {file = "ruff-0.3.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2b0c4c70578ef1871a9ac5c85ed7a8c33470e976c73ba9211a111d2771b5f787"}, - {file = "ruff-0.3.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e3da499ded004d0b956ab04248b2ae17e54a67ffc81353514ac583af5959a255"}, - {file = "ruff-0.3.6-py3-none-win32.whl", hash = "sha256:4056480f5cf38ad278667c31b0ef334c29acdfcea617cb89c4ccbc7d96f1637f"}, - {file = "ruff-0.3.6-py3-none-win_amd64.whl", hash = "sha256:f1aa621beed533f46e9c7d6fe00e7f6e4570155b61d8f020387b72ace2b42e04"}, - {file = "ruff-0.3.6-py3-none-win_arm64.whl", hash = "sha256:7c8a2a0e0cab077a07465259ffe3b3c090e747ca8097c5dc4c36ca0fdaaac90d"}, - {file = "ruff-0.3.6.tar.gz", hash = "sha256:26071fb530038602b984e3bbe1443ef82a38450c4dcb1344a9caf67234ff9756"}, + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e8377cccb2f07abd25e84fc5b2cbe48eeb0fea9f1719cad7caedb061d70e5ce"}, + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:15a4d1cc1e64e556fa0d67bfd388fed416b7f3b26d5d1c3e7d192c897e39ba4b"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28bdf3d7dc71dd46929fafeec98ba89b7c3550c3f0978e36389b5631b793663"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:379b67d4f49774ba679593b232dcd90d9e10f04d96e3c8ce4a28037ae473f7bb"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c060aea8ad5ef21cdfbbe05475ab5104ce7827b639a78dd55383a6e9895b7c51"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ebf8f615dde968272d70502c083ebf963b6781aacd3079081e03b32adfe4d58a"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48098bd8f5c38897b03604f5428901b65e3c97d40b3952e38637b5404b739a2"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da8a4fda219bf9024692b1bc68c9cff4b80507879ada8769dc7e985755d662ea"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c44e0149f1d8b48c4d5c33d88c677a4aa22fd09b1683d6a7ff55b816b5d074f"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3050ec0af72b709a62ecc2aca941b9cd479a7bf2b36cc4562f0033d688e44fa1"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a29cc38e4c1ab00da18a3f6777f8b50099d73326981bb7d182e54a9a21bb4ff7"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b15cc59c19edca917f51b1956637db47e200b0fc5e6e1878233d3a938384b0b"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e491045781b1e38b72c91247cf4634f040f8d0cb3e6d3d64d38dcf43616650b4"}, + {file = "ruff-0.3.7-py3-none-win32.whl", hash = "sha256:bc931de87593d64fad3a22e201e55ad76271f1d5bfc44e1a1887edd0903c7d9f"}, + {file = "ruff-0.3.7-py3-none-win_amd64.whl", hash = "sha256:5ef0e501e1e39f35e03c2acb1d1238c595b8bb36cf7a170e7c1df1b73da00e74"}, + {file = "ruff-0.3.7-py3-none-win_arm64.whl", hash = "sha256:789e144f6dc7019d1f92a812891c645274ed08af6037d11fc65fcbc183b7d59f"}, + {file = "ruff-0.3.7.tar.gz", hash = "sha256:d5c1aebee5162c2226784800ae031f660c350e7a3402c4d1f8ea4e97e232e3ba"}, ] [[package]] @@ -2625,18 +2625,18 @@ urllib3 = {version = ">=1.26,<3", extras = ["socks"]} [[package]] name = "setuptools" -version = "69.2.0" +version = "69.5.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c"}, - {file = "setuptools-69.2.0.tar.gz", hash = "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e"}, + {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"}, + {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] diff --git a/pyproject.toml b/pyproject.toml index a0072f4ea..13249f817 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,9 @@ pyecharts = "^2.0.4" ruff = ">=0.3.5" pre-commit = ">=3.5.0" +[tool.poetry.scripts] +nicegui-pack = "nicegui.scripts.pack:main" + [build-system] requires = [ "setuptools>=30.3.0,<50", From 3fcfac637273ebcd051cd09c1ee5d7745863d044 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:56:05 +0000 Subject: [PATCH 28/38] Update citation.cff and pyproject.toml --- CITATION.cff | 6 +++--- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index bd9bb1ad0..674ea0f2f 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -8,7 +8,7 @@ authors: given-names: Rodja orcid: https://orcid.org/0009-0009-4735-6227 title: 'NiceGUI: Web-based user interfaces with Python. The nice way.' -version: v1.4.22 -date-released: '2024-04-15' +version: v1.4.23 +date-released: '2024-04-25' url: https://github.com/zauberzeug/nicegui -doi: 10.5281/zenodo.10973178 +doi: 10.5281/zenodo.11068110 diff --git a/pyproject.toml b/pyproject.toml index 13249f817..935b78e2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nicegui" -version = "1.4.22-dev" +version = "1.4.23-dev" description = "Create web-based user interfaces with Python. The nice way." authors = ["Zauberzeug GmbH "] license = "MIT" From 2303e95ca76d0433da031af5de09b5c3f5712a78 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Mon, 29 Apr 2024 10:07:22 +0200 Subject: [PATCH 29/38] fix parameter name in modularization example --- examples/modularization/api_router_example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/modularization/api_router_example.py b/examples/modularization/api_router_example.py index ee178c4b8..077fc2006 100644 --- a/examples/modularization/api_router_example.py +++ b/examples/modularization/api_router_example.py @@ -17,7 +17,7 @@ def example_page(): ui.link('Item 3', '/c/items/3').classes('text-xl text-grey-8') -@router.page('/items/{id}', dark=True) +@router.page('/items/{item_id}', dark=True) def item(item_id: str): with theme.frame(f'- Page C{item_id} -'): message(f'Item #{item_id}') From 44e4e2a5bb1f741cc798853f3d6d759ad3ff66c4 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Mon, 29 Apr 2024 11:11:55 +0200 Subject: [PATCH 30/38] Try to fix Plotly layout issues (#2957) * try to fix Plotly layout issues * avoid re-rendering when replacing undefined attributes * reorder attributes to clean up the diff --- nicegui/elements/plotly.vue | 19 +++++++++++++++---- nicegui/static/nicegui.js | 30 +++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/nicegui/elements/plotly.vue b/nicegui/elements/plotly.vue index aaef3509c..889045aa5 100644 --- a/nicegui/elements/plotly.vue +++ b/nicegui/elements/plotly.vue @@ -7,7 +7,6 @@ export default { async mounted() { await this.$nextTick(); this.update(); - this.set_handlers(); }, updated() { this.update(); @@ -19,9 +18,16 @@ export default { if (options.config === undefined) options.config = { responsive: true }; if (options.config.responsive === undefined) options.config.responsive = true; - // Plotly.react can be used to create a new plot and to update it efficiently - // https://plotly.com/javascript/plotlyjs-function-reference/#plotlyreact - Plotly.react(this.$el.id, this.options.data, this.options.layout, options.config); + // re-use plotly instance if config is the same + if (JSON.stringify(options.config) == JSON.stringify(this.last_options.config)) { + Plotly.react(this.$el.id, this.options.data, this.options.layout); + } else { + Plotly.newPlot(this.$el.id, this.options.data, this.options.layout, options.config); + this.set_handlers(); + } + + // store last options + this.last_options = options; }, set_handlers() { // forward events @@ -61,6 +67,11 @@ export default { } }, }, + data() { + return { + last_options: {}, + }; + }, props: { options: Object, }, diff --git a/nicegui/static/nicegui.js b/nicegui/static/nicegui.js index c87474a59..40960e37f 100644 --- a/nicegui/static/nicegui.js +++ b/nicegui/static/nicegui.js @@ -19,6 +19,25 @@ function parseElements(raw_elements) { ); } +function replaceUndefinedAttributes(elements, id) { + const element = elements[id]; + if (element === undefined) { + return; + } + element.class ??= []; + element.style ??= {}; + element.props ??= {}; + element.text ??= null; + element.events ??= []; + element.component ??= null; + element.libraries ??= []; + element.slots = { + default: { ids: element.children || [] }, + ...(element.slots ?? {}), + }; + Object.values(element.slots).forEach((slot) => slot.ids.forEach((id) => replaceUndefinedAttributes(elements, id))); +} + function getElement(id) { const _id = id instanceof HTMLElement ? id.id : id; return mounted_app.$refs["r" + _id]; @@ -111,15 +130,6 @@ function renderRecursively(elements, id) { return; } - element.class ??= []; - element.style ??= {}; - element.props ??= {}; - element.text ??= null; - element.slots ??= {}; - element.events ??= []; - element.component ??= null; - element.libraries ??= []; - // @todo: Try avoid this with better handling of initial page load. if (element.component) loaded_components.add(element.component.name); element.libraries.forEach((library) => loaded_libraries.add(library.name)); @@ -264,6 +274,7 @@ function createRandomUUID() { } function createApp(elements, options) { + replaceUndefinedAttributes(elements, 0); return (app = Vue.createApp({ data() { return { @@ -324,6 +335,7 @@ function createApp(elements, options) { await loadDependencies(element, options.prefix, options.version); } this.elements[id] = element; + replaceUndefinedAttributes(this.elements, id); } }, run_javascript: (msg) => runJavascript(msg["code"], msg["request_id"]), From 35b23ae6c352c603d4537c26828c1108c81402ed Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Mon, 29 Apr 2024 11:25:37 +0200 Subject: [PATCH 31/38] handle timeout errors for infinite scroll example (fixes #2966) --- examples/infinite_scroll/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/infinite_scroll/main.py b/examples/infinite_scroll/main.py index fd376c615..8884b8a79 100755 --- a/examples/infinite_scroll/main.py +++ b/examples/infinite_scroll/main.py @@ -7,8 +7,11 @@ @ui.page('/') async def page(): async def check(): - if await ui.run_javascript('window.pageYOffset >= document.body.offsetHeight - 2 * window.innerHeight'): - ui.image(f'https://picsum.photos/640/360?{time.time()}') + try: + if await ui.run_javascript('window.pageYOffset >= document.body.offsetHeight - 2 * window.innerHeight'): + ui.image(f'https://picsum.photos/640/360?{time.time()}') + except TimeoutError: + pass # the client might have disconnected await ui.context.client.connected() ui.timer(0.1, check) From fa38aff25d42abb5a98d950585acb2d870f38a05 Mon Sep 17 00:00:00 2001 From: Christoph Schorn Date: Mon, 29 Apr 2024 13:30:37 +0200 Subject: [PATCH 32/38] Add 'clear_color' attribute to ui.scene (#2963) * Add 'clear_color' attribute to ui.scene * Rename parameter to 'background_color' * code review --------- Co-authored-by: Falko Schindler --- nicegui/elements/scene.js | 8 ++++++-- nicegui/elements/scene.py | 3 +++ website/documentation/content/scene_documentation.py | 8 ++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/nicegui/elements/scene.js b/nicegui/elements/scene.js index 50ae6edb0..af509adc4 100644 --- a/nicegui/elements/scene.js +++ b/nicegui/elements/scene.js @@ -107,7 +107,7 @@ export default { this.$el.style.border = "1px solid silver"; return; } - this.renderer.setClearColor("#eee"); + this.renderer.setClearColor(this.background_color); this.renderer.setSize(this.width, this.height); this.text_renderer = new CSS2DRenderer({ @@ -124,7 +124,10 @@ export default { window.addEventListener("resize", this.resize, false); if (this.grid) { - const ground = new THREE.Mesh(new THREE.PlaneGeometry(100, 100), new THREE.MeshPhongMaterial({ color: "#eee" })); + const ground = new THREE.Mesh( + new THREE.PlaneGeometry(100, 100), + new THREE.MeshPhongMaterial({ color: this.background_color }) + ); ground.translateZ(-0.01); ground.object_id = "ground"; this.scene.add(ground); @@ -441,5 +444,6 @@ export default { camera_type: String, camera_params: Object, drag_constraints: String, + background_color: String, }, }; diff --git a/nicegui/elements/scene.py b/nicegui/elements/scene.py index 0ab50d6be..38abd30ad 100644 --- a/nicegui/elements/scene.py +++ b/nicegui/elements/scene.py @@ -78,6 +78,7 @@ def __init__(self, on_drag_start: Optional[Callable[..., Any]] = None, on_drag_end: Optional[Callable[..., Any]] = None, drag_constraints: str = '', + background_color: str = '#eee', ) -> None: """3D Scene @@ -94,11 +95,13 @@ def __init__(self, :param on_drag_start: callback to execute when a 3D object is dragged :param on_drag_end: callback to execute when a 3D object is dropped :param drag_constraints: comma-separated JavaScript expression for constraining positions of dragged objects (e.g. ``'x = 0, z = y / 2'``) + :param background_color: background color of the scene (default: "#eee") """ super().__init__() self._props['width'] = width self._props['height'] = height self._props['grid'] = grid + self._props['background_color'] = background_color self.camera = camera or self.perspective_camera() self._props['camera_type'] = self.camera.type self._props['camera_params'] = self.camera.params diff --git a/website/documentation/content/scene_documentation.py b/website/documentation/content/scene_documentation.py index 039ed5ad8..b9cebabac 100644 --- a/website/documentation/content/scene_documentation.py +++ b/website/documentation/content/scene_documentation.py @@ -123,4 +123,12 @@ def orthographic_camera() -> None: scene.box() +@doc.demo('Custom Background', ''' + You can set a custom background color using the `background_color` parameter of `ui.scene`. +''') +def custom_background() -> None: + with ui.scene(background_color='#222').classes('w-full h-64') as scene: + scene.box() + + doc.reference(ui.scene) From 64eb3aeaff181d9b00b6c25afde3398436b14155 Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Mon, 29 Apr 2024 13:37:34 +0200 Subject: [PATCH 33/38] don't repeat UI updates from HTTP response (fixes #2926) --- nicegui/client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nicegui/client.py b/nicegui/client.py index 3bd015a90..0eea0c080 100644 --- a/nicegui/client.py +++ b/nicegui/client.py @@ -115,6 +115,7 @@ def __exit__(self, *_) -> None: def build_response(self, request: Request, status_code: int = 200) -> Response: """Build a FastAPI response for the client.""" + self.outbox.updates.clear() prefix = request.headers.get('X-Forwarded-Prefix', request.scope.get('root_path', '')) elements = json.dumps({ id: element._to_dict() for id, element in self.elements.items() # pylint: disable=protected-access From b7e8bcbe9a494e50e8598e7fc28ddad551d853de Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Tue, 30 Apr 2024 09:30:30 +0200 Subject: [PATCH 34/38] fix pre-commit warning --- .pre-commit-config.yaml | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9f4431e52..5e28c38e5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,22 +3,6 @@ default_language_version: default_install_hook_types: [pre-commit, pre-push] default_stages: [commit] -exclusions: &exclusions - exclude: | - (?x)^( - nicegui/elements/lib/.*| - nicegui/static/es-module-shims\.js| - nicegui/static/fonts/.*| - nicegui/static/fonts\.css| - nicegui/static/lang/.*| - nicegui/static/quasar\..*| - nicegui/static/socket\..*| - nicegui/static/tailwindcss\..*| - nicegui/static/vue\..*| - website/static/fuse\.js\@.*| - examples/fullcalendar/lib/.* - )$ - repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.3.5 @@ -29,7 +13,20 @@ repos: rev: v4.6.0 hooks: - id: trailing-whitespace - <<: *exclusions + exclude: &exclusions | + (?x)^( + nicegui/elements/lib/.*| + nicegui/static/es-module-shims\.js| + nicegui/static/fonts/.*| + nicegui/static/fonts\.css| + nicegui/static/lang/.*| + nicegui/static/quasar\..*| + nicegui/static/socket\..*| + nicegui/static/tailwindcss\..*| + nicegui/static/vue\..*| + website/static/fuse\.js\@.*| + examples/fullcalendar/lib/.* + )$ - id: end-of-file-fixer - <<: *exclusions + exclude: *exclusions - id: double-quote-string-fixer From 1bce2bad367d5baf842badb51a0d78c8543a49ef Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Tue, 30 Apr 2024 09:40:55 +0200 Subject: [PATCH 35/38] let SourceElement work with Any source type to fix mypy issues with ui.image and ui.interactive_image --- nicegui/elements/audio.py | 3 +++ nicegui/elements/image.py | 3 +++ nicegui/elements/interactive_image.py | 3 +++ nicegui/elements/mixins/source_element.py | 11 +++++------ nicegui/elements/video.py | 3 +++ 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/nicegui/elements/audio.py b/nicegui/elements/audio.py index 7c2c03e07..2424dd600 100644 --- a/nicegui/elements/audio.py +++ b/nicegui/elements/audio.py @@ -32,6 +32,9 @@ def __init__(self, src: Union[str, Path], *, self._props['muted'] = muted self._props['loop'] = loop + def set_source(self, source: Union[str, Path]) -> None: + return super().set_source(source) + def seek(self, seconds: float) -> None: """Seek to a specific position in the audio. diff --git a/nicegui/elements/image.py b/nicegui/elements/image.py index dae0045df..6a7196658 100644 --- a/nicegui/elements/image.py +++ b/nicegui/elements/image.py @@ -27,6 +27,9 @@ def __init__(self, source: Union[str, Path, 'PIL_Image'] = '') -> None: """ super().__init__(source=source) + def set_source(self, source: Union[str, Path, 'PIL_Image']) -> None: + return super().set_source(source) + def _set_props(self, source: Union[str, Path, 'PIL_Image']) -> None: if optional_features.has('pillow') and isinstance(source, PIL_Image): source = pil_to_base64(source, self.PIL_CONVERT_FORMAT) diff --git a/nicegui/elements/interactive_image.py b/nicegui/elements/interactive_image.py index b0a6a542f..17a1dc95a 100644 --- a/nicegui/elements/interactive_image.py +++ b/nicegui/elements/interactive_image.py @@ -65,6 +65,9 @@ def __init__(self, if on_mouse: self.on_mouse(on_mouse) + def set_source(self, source: Union[str, Path, 'PIL_Image']) -> None: # noqa: UP037 + return super().set_source(source) + def on_mouse(self, on_mouse: Callable[..., Any]) -> Self: """Add a callback to be invoked when a mouse event occurs.""" def handle_mouse(e: GenericEventArguments) -> None: diff --git a/nicegui/elements/mixins/source_element.py b/nicegui/elements/mixins/source_element.py index d453ac68a..5d9add5ce 100644 --- a/nicegui/elements/mixins/source_element.py +++ b/nicegui/elements/mixins/source_element.py @@ -1,5 +1,4 @@ -from pathlib import Path -from typing import Any, Callable, Optional, Union, cast +from typing import Any, Callable, Optional, cast from typing_extensions import Self @@ -15,7 +14,7 @@ class SourceElement(Element): SOURCE_IS_MEDIA_FILE: bool = False - def __init__(self, *, source: Union[str, Path], **kwargs: Any) -> None: + def __init__(self, *, source: Any, **kwargs: Any) -> None: super().__init__(**kwargs) self.auto_route: Optional[str] = None self.source = source @@ -75,14 +74,14 @@ def bind_source(self, bind(self, 'source', target_object, target_name, forward=forward, backward=backward) return self - def set_source(self, source: Union[str, Path]) -> None: + def set_source(self, source: Any) -> None: """Set the source of this element. :param source: The new source. """ self.source = source - def _handle_source_change(self, source: Union[str, Path]) -> None: + def _handle_source_change(self, source: Any) -> None: """Called when the source of this element changes. :param source: The new source. @@ -90,7 +89,7 @@ def _handle_source_change(self, source: Union[str, Path]) -> None: self._set_props(source) self.update() - def _set_props(self, source: Union[str, Path]) -> None: + def _set_props(self, source: Any) -> None: if is_file(source): if self.auto_route: core.app.remove_route(self.auto_route) diff --git a/nicegui/elements/video.py b/nicegui/elements/video.py index 5b0a14c65..18d2c58aa 100644 --- a/nicegui/elements/video.py +++ b/nicegui/elements/video.py @@ -32,6 +32,9 @@ def __init__(self, src: Union[str, Path], *, self._props['muted'] = muted self._props['loop'] = loop + def set_source(self, source: Union[str, Path]) -> None: + return super().set_source(source) + def seek(self, seconds: float) -> None: """Seek to a specific position in the video. From 54c644f3933ee20357de4d3ff42ea0bc5b9770ae Mon Sep 17 00:00:00 2001 From: Christoph Schorn Date: Thu, 2 May 2024 13:11:56 +0200 Subject: [PATCH 36/38] Add chip element (#2942) * Add chip element * Remove 'on_enter' * automatically make `ui.chip` clickable via on_click callback (like `ui.item`) * remove `clicked()` method * use event args for selection handler * improve pytests * simplify demos a bit * move selection feature into a separate mixin * fix pytest --------- Co-authored-by: Falko Schindler --- .vscode/settings.json | 1 + nicegui/elements/chip.py | 61 ++++++++++ nicegui/elements/mixins/selectable_element.py | 109 ++++++++++++++++++ nicegui/ui.py | 2 + tests/test_chip.py | 27 +++++ .../content/chip_documentation.py | 39 +++++++ .../documentation/content/section_controls.py | 2 + 7 files changed, 241 insertions(+) create mode 100644 nicegui/elements/chip.py create mode 100644 nicegui/elements/mixins/selectable_element.py create mode 100644 tests/test_chip.py create mode 100644 website/documentation/content/chip_documentation.py diff --git a/.vscode/settings.json b/.vscode/settings.json index 89de52cf6..18a52e3b6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,7 @@ "--disable=C0301", // Line too long (exceeds character limit) "--disable=C0302", // Too many lines in module "--disable=R0801", // Similar lines in files + "--disable=R0901", // Too many ancestors "--disable=R0902", // Too many instance attributes "--disable=R0903", // Too few public methods "--disable=R0904", // Too many public methods diff --git a/nicegui/elements/chip.py b/nicegui/elements/chip.py new file mode 100644 index 000000000..0c40ed016 --- /dev/null +++ b/nicegui/elements/chip.py @@ -0,0 +1,61 @@ +from typing import Any, Callable, Optional + +from typing_extensions import Self + +from ..events import ClickEventArguments, handle_event +from .mixins.color_elements import BackgroundColorElement, TextColorElement +from .mixins.disableable_element import DisableableElement +from .mixins.selectable_element import SelectableElement +from .mixins.text_element import TextElement +from .mixins.value_element import ValueElement + + +class Chip(ValueElement, TextElement, BackgroundColorElement, TextColorElement, DisableableElement, SelectableElement): + TEXT_COLOR_PROP = 'text-color' + + def __init__(self, + text: str = '', + *, + icon: Optional[str] = None, + color: Optional[str] = 'primary', + text_color: Optional[str] = None, + on_click: Optional[Callable[..., Any]] = None, + selectable: bool = False, + selected: bool = False, + on_selection_change: Optional[Callable[..., Any]] = None, + removable: bool = False, + on_value_change: Optional[Callable[..., Any]] = None, + ) -> None: + """Chip + + A chip element wrapping Quasar's `QChip `_ component. + It can be clickable, selectable and removable. + + :param text: the initial value of the text field (default: "") + :param icon: the name of an icon to be displayed on the chip (default: `None`) + :param color: the color name for component (either a Quasar, Tailwind, or CSS color or `None`, default: "primary") + :param text_color: text color (either a Quasar, Tailwind, or CSS color or `None`, default: `None`) + :param on_click: callback which is invoked when chip is clicked. Makes the chip clickable if set + :param selectable: whether the chip is selectable (default: `False`) + :param selected: whether the chip is selected (default: `False`) + :param on_selection_change: callback which is invoked when the chip's selection state is changed + :param removable: whether the chip is removable. Shows a small "x" button if True (default: `False`) + :param on_value_change: callback which is invoked when the chip is removed or unremoved + """ + super().__init__(tag='q-chip', value=True, on_value_change=on_value_change, + text=text, text_color=text_color, background_color=color, + selectable=selectable, selected=selected, on_selection_change=on_selection_change) + if icon: + self._props['icon'] = icon + + self._props['removable'] = removable + + if on_click: + self.on_click(on_click) + + def on_click(self, callback: Callable[..., Any]) -> Self: + """Add a callback to be invoked when the chip is clicked.""" + self._props['clickable'] = True + self.update() + self.on('click', lambda _: handle_event(callback, ClickEventArguments(sender=self, client=self.client)), []) + return self diff --git a/nicegui/elements/mixins/selectable_element.py b/nicegui/elements/mixins/selectable_element.py new file mode 100644 index 000000000..e5f01f14f --- /dev/null +++ b/nicegui/elements/mixins/selectable_element.py @@ -0,0 +1,109 @@ +from typing import Any, Callable, List, Optional, cast + +from typing_extensions import Self + +from ...binding import BindableProperty, bind, bind_from, bind_to +from ...element import Element +from ...events import ValueChangeEventArguments, handle_event + + +class SelectableElement(Element): + selected = BindableProperty( + on_change=lambda sender, selected: cast(Self, sender)._handle_selection_change(selected)) # pylint: disable=protected-access + + def __init__(self, *, + selectable: bool, + selected: bool, + on_selection_change: Optional[Callable[..., Any]], + **kwargs: Any) -> None: + super().__init__(**kwargs) + if not selectable: + return + + self._props['selectable'] = selectable + + self.selected = selected + self._props['selected'] = selected + self.set_selected(selected) + self.on('update:selected', lambda e: self.set_selected(e.args)) + + self._selection_change_handlers: List[Callable[..., Any]] = [] + if on_selection_change: + self.on_selection_change(on_selection_change) + + def on_selection_change(self, callback: Callable[..., Any]) -> Self: + """Add a callback to be invoked when the selection state changes.""" + self._selection_change_handlers.append(callback) + return self + + def bind_selected_to(self, + target_object: Any, + target_name: str = 'selected', + forward: Callable[..., Any] = lambda x: x, + ) -> Self: + """Bind the selection state of this element to the target object's target_name property. + + The binding works one way only, from this element to the target. + The update happens immediately and whenever a value changes. + + :param target_object: The object to bind to. + :param target_name: The name of the property to bind to. + :param forward: A function to apply to the value before applying it to the target. + """ + bind_to(self, 'selected', target_object, target_name, forward) + return self + + def bind_selected_from(self, + target_object: Any, + target_name: str = 'selected', + backward: Callable[..., Any] = lambda x: x, + ) -> Self: + """Bind the selection state of this element from the target object's target_name property. + + The binding works one way only, from the target to this element. + The update happens immediately and whenever a value changes. + + :param target_object: The object to bind from. + :param target_name: The name of the property to bind from. + :param backward: A function to apply to the value before applying it to this element. + """ + bind_from(self, 'selected', target_object, target_name, backward) + return self + + def bind_selected(self, + target_object: Any, + target_name: str = 'selected', *, + forward: Callable[..., Any] = lambda x: x, + backward: Callable[..., Any] = lambda x: x, + ) -> Self: + """Bind the selection state of this element to the target object's target_name property. + + The binding works both ways, from this element to the target and from the target to this element. + The update happens immediately and whenever a value changes. + The backward binding takes precedence for the initial synchronization. + + :param target_object: The object to bind to. + :param target_name: The name of the property to bind to. + :param forward: A function to apply to the value before applying it to the target. + :param backward: A function to apply to the value before applying it to this element. + """ + bind(self, 'selected', target_object, target_name, forward=forward, backward=backward) + return self + + def set_selected(self, selected: bool) -> None: + """Set the selection state of this element. + + :param selected: The new selection state. + """ + self.selected = selected + + def _handle_selection_change(self, selected: bool) -> None: + """Called when the selection state of this element changes. + + :param selected: The new selection state. + """ + self._props['selected'] = selected + self.update() + args = ValueChangeEventArguments(sender=self, client=self.client, value=self._props['selected']) + for handler in self._selection_change_handlers: + handle_event(handler, args) diff --git a/nicegui/ui.py b/nicegui/ui.py index 76adb0dca..267aafaaf 100644 --- a/nicegui/ui.py +++ b/nicegui/ui.py @@ -14,6 +14,7 @@ 'chart', 'chat_message', 'checkbox', + 'chip', 'clipboard', 'code', 'color_input', @@ -139,6 +140,7 @@ from .elements.chart import chart from .elements.chat_message import ChatMessage as chat_message from .elements.checkbox import Checkbox as checkbox +from .elements.chip import Chip as chip from .elements.code import Code as code from .elements.color_input import ColorInput as color_input from .elements.color_picker import ColorPicker as color_picker diff --git a/tests/test_chip.py b/tests/test_chip.py new file mode 100644 index 000000000..bb098801c --- /dev/null +++ b/tests/test_chip.py @@ -0,0 +1,27 @@ +from nicegui import ui +from nicegui.testing import Screen + + +def test_removable_chip(screen: Screen): + chip = ui.chip('Chip', removable=True) + + screen.open('/') + screen.should_contain('Chip') + + chip.set_value(False) + screen.wait(0.5) + screen.should_not_contain('Chip') + + +def test_selectable_chip(screen: Screen): + chip = ui.chip('Chip', selectable=True) + ui.label().bind_text_from(chip, 'selected', lambda s: f'Selected: {s}') + + screen.open('/') + screen.should_contain('Selected: False') + + screen.click('Chip') + screen.should_contain('Selected: True') + + screen.click('Chip') + screen.should_contain('Selected: False') diff --git a/website/documentation/content/chip_documentation.py b/website/documentation/content/chip_documentation.py new file mode 100644 index 000000000..c9ce43960 --- /dev/null +++ b/website/documentation/content/chip_documentation.py @@ -0,0 +1,39 @@ +from nicegui import ui + +from . import doc + + +@doc.demo(ui.chip) +def main_demo() -> None: + with ui.row().classes('gap-1'): + ui.chip('Click me', icon='ads_click', on_click=lambda: ui.notify('Clicked')) + ui.chip('Selectable', selectable=True, icon='bookmark', color='orange') + ui.chip('Removable', removable=True, icon='label', color='indigo-3') + ui.chip('Styled', icon='star', color='green').props('outline square') + ui.chip('Disabled', icon='block', color='red').set_enabled(False) + + +@doc.demo('Dynamic chip elements as labels/tags', ''' + This demo shows how to implement a dynamic list of chips as labels or tags. + You can add new chips by typing a label and pressing Enter or pressing the plus button. + Removed chips still exist, but their value is set to `False`. +''') +def labels(): + def add_chip(): + with chips: + ui.chip(label_input.value, icon='label', color='silver', removable=True) + label_input.value = '' + + label_input = ui.input('Add label').on('keydown.enter', add_chip) + with label_input.add_slot('append'): + ui.button(icon='add', on_click=add_chip).props('round dense flat') + + with ui.row().classes('gap-0') as chips: + ui.chip('Label 1', icon='label', color='silver', removable=True) + + ui.button('Restore removed chips', icon='unarchive', + on_click=lambda: [chip.set_value(True) for chip in chips]) \ + .props('flat') + + +doc.reference(ui.chip) diff --git a/website/documentation/content/section_controls.py b/website/documentation/content/section_controls.py index 6851fcc6d..31488eb9f 100644 --- a/website/documentation/content/section_controls.py +++ b/website/documentation/content/section_controls.py @@ -4,6 +4,7 @@ button_dropdown_documentation, button_group_documentation, checkbox_documentation, + chip_documentation, color_input_documentation, color_picker_documentation, date_documentation, @@ -29,6 +30,7 @@ doc.intro(button_group_documentation) doc.intro(button_dropdown_documentation) doc.intro(badge_documentation) +doc.intro(chip_documentation) doc.intro(toggle_documentation) doc.intro(radio_documentation) doc.intro(select_documentation) From 200dea9acb83f4c0914e8606b410a7454c36727f Mon Sep 17 00:00:00 2001 From: Falko Schindler Date: Thu, 2 May 2024 13:47:50 +0200 Subject: [PATCH 37/38] use more reliable tab ID as connection indicator (might fix #2915) --- nicegui/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nicegui/client.py b/nicegui/client.py index 0eea0c080..a552423fb 100644 --- a/nicegui/client.py +++ b/nicegui/client.py @@ -94,7 +94,7 @@ def ip(self) -> Optional[str]: @property def has_socket_connection(self) -> bool: """Return True if the client is connected, False otherwise.""" - return self.environ is not None + return self.tab_id is not None @property def head_html(self) -> str: From 4a225aad250ab3ae6061251c1614a7d705f53f46 Mon Sep 17 00:00:00 2001 From: Dronakurl <76913264+Dronakurl@users.noreply.github.com> Date: Thu, 2 May 2024 16:40:31 +0200 Subject: [PATCH 38/38] Documentation: Fix a broken link on the ui.page documentation (#2990) * Documentation: Fix a broken link on the ui.page documentation * preserve the original name of the example --------- Co-authored-by: Falko Schindler --- website/documentation/content/page_documentation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/documentation/content/page_documentation.py b/website/documentation/content/page_documentation.py index c7b74c4d6..5a39bedd8 100644 --- a/website/documentation/content/page_documentation.py +++ b/website/documentation/content/page_documentation.py @@ -60,8 +60,8 @@ async def wait_for_connection(): This is especially useful if you want to reuse the same prefix for multiple pages. The router and its pages can be neatly tugged away in a separate module (e.g. file) and the router is simply imported and included in the main app. - See our [modularization example](https://github.com/zauberzeug/nicegui/blob/main/examples/modularization/example_c.py) - for a multi-file app structure. + See our [modularization example](https://github.com/zauberzeug/nicegui/blob/main/examples/modularization/api_router_example.py) + for a multi-file app structure using an API router. ''', tab='/sub-path') def api_router_demo(): # from nicegui import APIRouter, app