Преглед изворни кода

Remove ui.timer objects from hierarchy (#3647)

* remove timer objects from hierarchy

* only remove if client still exists

* only remove elements if they are still there

* add test to ensure cleanup of timer elements

* code review

---------

Co-authored-by: Falko Schindler <falko@zauberzeug.com>
Rodja Trappe пре 8 месеци
родитељ
комит
d31c60d26f
3 измењених фајлова са 21 додато и 2 уклоњено
  1. 1 1
      nicegui/client.py
  2. 3 0
      nicegui/elements/timer.py
  3. 17 1
      tests/test_timer.py

+ 1 - 1
nicegui/client.py

@@ -295,7 +295,7 @@ class Client:
             element._handle_delete()  # pylint: disable=protected-access
             element._deleted = True  # pylint: disable=protected-access
             self.outbox.enqueue_delete(element)
-            del self.elements[element.id]
+            self.elements.pop(element.id, None)
 
     def remove_all_elements(self) -> None:
         """Remove all elements from the client."""

+ 3 - 0
nicegui/elements/timer.py

@@ -125,3 +125,6 @@ class Timer(Element, component='timer.js'):
 
     def _cleanup(self) -> None:
         self.callback = None
+        if not self.client._deleted:  # pylint: disable=protected-access
+            assert self.parent_slot
+            self.parent_slot.parent.remove(self)

+ 17 - 1
tests/test_timer.py

@@ -1,9 +1,10 @@
 import asyncio
+import gc
 
 import pytest
 
 from nicegui import ui
-from nicegui.testing import Screen
+from nicegui.testing import Screen, User
 
 
 class Counter:
@@ -129,3 +130,18 @@ def test_different_callbacks(screen: Screen):
     screen.should_contain('an asynchronous function')
     screen.should_contain('a synchronous lambda')
     screen.should_contain('an asynchronous lambda: Hi!')
+
+
+async def test_cleanup(user: User):
+    def update():
+        ui.timer(0.01, update, once=True)
+    ui.timer(0, update, once=True)
+
+    def count():
+        return sum(1 for obj in gc.get_objects() if isinstance(obj, ui.timer))
+
+    await user.open('/')
+    assert count() > 0, 'there are timer objects in memory'
+    await asyncio.sleep(0.1)
+    gc.collect()
+    assert count() == 1, 'only current timer object is in memory'