Prechádzať zdrojové kódy

fix "dictionary changed size during iteration"

Falko Schindler 1 rok pred
rodič
commit
9956ab5c2a
3 zmenil súbory, kde vykonal 22 pridanie a 19 odobranie
  1. 16 2
      nicegui/client.py
  2. 5 13
      nicegui/element.py
  3. 1 4
      nicegui/nicegui.py

+ 16 - 2
nicegui/client.py

@@ -4,7 +4,7 @@ import asyncio
 import time
 import uuid
 from pathlib import Path
-from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, List, Optional, Union
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Iterable, List, Optional, Union
 
 from fastapi import Request
 from fastapi.responses import Response
@@ -12,7 +12,7 @@ from fastapi.templating import Jinja2Templates
 
 from nicegui import json
 
-from . import globals, outbox  # pylint: disable=redefined-builtin
+from . import binding, globals, outbox  # pylint: disable=redefined-builtin
 from .dependencies import generate_resources
 from .element import Element
 from .favicon import get_favicon_url
@@ -162,3 +162,17 @@ class Client:
     def on_disconnect(self, handler: Union[Callable[..., Any], Awaitable]) -> None:
         """Register a callback to be called when the client disconnects."""
         self.disconnect_handlers.append(handler)
+
+    def remove_elements(self, elements: Iterable[Element]) -> None:
+        """Remove the given elements from the client."""
+        binding.remove(elements, Element)
+        element_ids = [element.id for element in elements]
+        for element_id in element_ids:
+            del self.elements[element_id]
+        for element in elements:
+            element._deleted = True  # pylint: disable=protected-access
+            outbox.enqueue_delete(element)
+
+    def remove_all_elements(self) -> None:
+        """Remove all elements from the client."""
+        self.remove_elements(self.elements.values())

+ 5 - 13
nicegui/element.py

@@ -4,13 +4,13 @@ import inspect
 import re
 from copy import copy, deepcopy
 from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Union
+from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, List, Optional, Sequence, Union
 
 from typing_extensions import Self
 
 from nicegui import json
 
-from . import binding, events, globals, outbox, storage  # pylint: disable=redefined-builtin
+from . import events, globals, outbox, storage  # pylint: disable=redefined-builtin
 from .dependencies import Component, Library, register_library, register_vue_component
 from .elements.mixins.visibility import Visibility
 from .event_listener import EventListener
@@ -310,18 +310,10 @@ class Element(Visibility):
             elements.extend(child._collect_descendants(include_self=True))  # pylint: disable=protected-access
         return elements
 
-    @staticmethod
-    def _delete_elements(elements: Iterable[Element]) -> None:
-        binding.remove(elements, Element)
-        for element in elements:
-            element._deleted = True  # pylint: disable=protected-access
-            del element.client.elements[element.id]
-            outbox.enqueue_delete(element)
-
     def clear(self) -> None:
         """Remove all child elements."""
         descendants = self._collect_descendants()
-        self._delete_elements(descendants)
+        self.client.remove_elements(descendants)
         for slot in self.slots.values():
             slot.children.clear()
         self.update()
@@ -350,14 +342,14 @@ class Element(Visibility):
             children = list(self)
             element = children[element]
         elements = element._collect_descendants(include_self=True)  # pylint: disable=protected-access
-        self._delete_elements(elements)
+        self.client.remove_elements(elements)
         assert element.parent_slot is not None
         element.parent_slot.children.remove(element)
         self.update()
 
     def delete(self) -> None:
         """Delete the element."""
-        self._delete_elements([self])
+        self.client.remove_elements([self])
         assert self.parent_slot is not None
         self.parent_slot.children.remove(self)
 

+ 1 - 4
nicegui/nicegui.py

@@ -14,7 +14,6 @@ from . import background_tasks, binding, favicon, globals, json, outbox, welcome
 from .app import App
 from .client import Client
 from .dependencies import js_components, libraries
-from .element import Element
 from .error import error_content
 from .helpers import is_file, safe_invoke
 from .json import NiceGUIJSONResponse
@@ -229,6 +228,4 @@ async def prune_slot_stacks() -> None:
 
 
 def delete_client(client_id: str) -> None:
-    elements = globals.clients[client_id].elements.values()
-    Element._delete_elements(elements)  # pylint: disable=protected-access
-    del globals.clients[client_id]
+    globals.clients.pop(client_id).remove_all_elements()