Skip to content

Commit

Permalink
Added automatic unregistering of BindableProperty objects to avoid st…
Browse files Browse the repository at this point in the history
…oring references in binding.bindable_properties until explicitly removed
  • Loading branch information
Andreas Bayer committed Dec 18, 2024
1 parent 561c02b commit 19ffaf0
Showing 1 changed file with 16 additions and 5 deletions.
21 changes: 16 additions & 5 deletions nicegui/binding.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import time
import weakref
from collections import defaultdict
from collections.abc import Mapping
from typing import Any, Callable, DefaultDict, Dict, Iterable, List, Optional, Set, Tuple, Union
Expand All @@ -10,7 +11,7 @@
MAX_PROPAGATION_TIME = 0.01

bindings: DefaultDict[Tuple[int, str], List] = defaultdict(list)
bindable_properties: Dict[Tuple[int, str], Any] = {}
bindable_properties: Dict[Tuple[int, str], weakref.finalize] = {}
active_links: List[Tuple[Any, str, Any, str, Callable[[Any], Any]]] = []


Expand Down Expand Up @@ -149,11 +150,19 @@ def __set__(self, owner: Any, value: Any) -> None:
if has_attr and not value_changed:
return
setattr(owner, '___' + self.name, value)
bindable_properties[(id(owner), self.name)] = owner
self._register(owner)
_propagate(owner, self.name)
if value_changed and self._change_handler is not None:
self._change_handler(owner, value)

def _register(self, owner: Any) -> None:
registry_key = (id(owner), str(self.name))

def try_unregister() -> None:
bindable_properties.pop(registry_key, None)

bindable_properties.setdefault(registry_key, weakref.finalize(owner, try_unregister))


def remove(objects: Iterable[Any]) -> None:
"""Remove all bindings that involve the given objects.
Expand All @@ -174,9 +183,11 @@ def remove(objects: Iterable[Any]) -> None:
]
if not binding_list:
del bindings[key]
for (obj_id, name), obj in list(bindable_properties.items()):
if id(obj) in object_ids:
del bindable_properties[(obj_id, name)]
for registry_key, finalizer in list(bindable_properties.items()):
obj_id, _ = registry_key
if obj_id in object_ids:
del bindable_properties[registry_key]
finalizer.detach()


def reset() -> None:
Expand Down

0 comments on commit 19ffaf0

Please sign in to comment.