Skip to content

Commit

Permalink
Remove ui.timer objects from hierarchy (#3647)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
rodja and falkoschindler committed Aug 31, 2024
1 parent 2cf863c commit d31c60d
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 2 deletions.
2 changes: 1 addition & 1 deletion nicegui/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ def remove_elements(self, elements: Iterable[Element]) -> None:
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."""
Expand Down
3 changes: 3 additions & 0 deletions nicegui/elements/timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,6 @@ def _should_stop(self) -> bool:

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)
18 changes: 17 additions & 1 deletion tests/test_timer.py
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -129,3 +130,18 @@ async def async_lambda(msg: str):
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'

0 comments on commit d31c60d

Please sign in to comment.