Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve memory management: more aggressive message culling + tests #353

Merged
merged 7 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/viser/_gui_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ def __init__(
self._container_handle_from_uuid: dict[str, GuiContainerProtocol] = {
"root": _RootGuiContainer({})
}
self._modal_handle_from_uuid: dict[str, GuiModalHandle] = {}
self._current_file_upload_states: dict[str, _FileUploadState] = {}

# Set to True when plotly.min.js has been sent to client.
Expand Down Expand Up @@ -372,13 +373,17 @@ def _get_container_uuid(self) -> str:
"""Get container ID associated with the current thread."""
return self._target_container_from_thread_id.get(threading.get_ident(), "root")

def _set_container_uid(self, container_uuid: str) -> None:
def _set_container_uuid(self, container_uuid: str) -> None:
"""Set container ID associated with the current thread."""
self._target_container_from_thread_id[threading.get_ident()] = container_uuid

def reset(self) -> None:
"""Reset the GUI."""
self._websock_interface.queue_message(_messages.ResetGuiMessage())
root_container = self._container_handle_from_uuid["root"]
while len(root_container._children) > 0:
next(iter(root_container._children.values())).remove()
while len(self._modal_handle_from_uuid) > 0:
next(iter(self._modal_handle_from_uuid.values())).close()

def set_panel_label(self, label: str | None) -> None:
"""Set the main label that appears in the GUI panel.
Expand Down Expand Up @@ -533,7 +538,7 @@ def add_modal(
)
return GuiModalHandle(
_gui_api=self,
_uid=modal_container_id,
_uuid=modal_container_id,
)

def add_tab_group(
Expand Down
30 changes: 16 additions & 14 deletions src/viser/_gui_handles.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,13 +598,13 @@ class GuiTabHandle:

def __enter__(self) -> GuiTabHandle:
self._container_id_restore = self._parent._impl.gui_api._get_container_uuid()
self._parent._impl.gui_api._set_container_uid(self._id)
self._parent._impl.gui_api._set_container_uuid(self._id)
return self

def __exit__(self, *args) -> None:
del args
assert self._container_id_restore is not None
self._parent._impl.gui_api._set_container_uid(self._container_id_restore)
self._parent._impl.gui_api._set_container_uuid(self._container_id_restore)
self._container_id_restore = None

def __post_init__(self) -> None:
Expand Down Expand Up @@ -662,13 +662,13 @@ def __init__(self, _impl: _GuiHandleState[None]) -> None:

def __enter__(self) -> GuiFolderHandle:
self._container_id_restore = self._impl.gui_api._get_container_uuid()
self._impl.gui_api._set_container_uid(self._impl.uuid)
self._impl.gui_api._set_container_uuid(self._impl.uuid)
return self

def __exit__(self, *args) -> None:
del args
assert self._container_id_restore is not None
self._impl.gui_api._set_container_uid(self._container_id_restore)
self._impl.gui_api._set_container_uuid(self._container_id_restore)
self._container_id_restore = None

def remove(self) -> None:
Expand Down Expand Up @@ -703,34 +703,36 @@ class GuiModalHandle:
"""Use as a context to place GUI elements into a modal."""

_gui_api: GuiApi
_uid: str # Used as container ID of children.
_container_uid_restore: str | None = None
_uuid: str # Used as container ID of children.
_container_uuid_restore: str | None = None
_children: dict[str, SupportsRemoveProtocol] = dataclasses.field(
default_factory=dict
)

def __enter__(self) -> GuiModalHandle:
self._container_uid_restore = self._gui_api._get_container_uuid()
self._gui_api._set_container_uid(self._uid)
self._container_uuid_restore = self._gui_api._get_container_uuid()
self._gui_api._set_container_uuid(self._uuid)
return self

def __exit__(self, *args) -> None:
del args
assert self._container_uid_restore is not None
self._gui_api._set_container_uid(self._container_uid_restore)
self._container_uid_restore = None
assert self._container_uuid_restore is not None
self._gui_api._set_container_uuid(self._container_uuid_restore)
self._container_uuid_restore = None

def __post_init__(self) -> None:
self._gui_api._container_handle_from_uuid[self._uid] = self
self._gui_api._container_handle_from_uuid[self._uuid] = self
self._gui_api._modal_handle_from_uuid[self._uuid] = self

def close(self) -> None:
"""Close this modal and permananently remove all contained GUI elements."""
self._gui_api._websock_interface.queue_message(
GuiCloseModalMessage(self._uid),
GuiCloseModalMessage(self._uuid),
)
for child in tuple(self._children.values()):
child.remove()
self._gui_api._container_handle_from_uuid.pop(self._uid)
self._gui_api._container_handle_from_uuid.pop(self._uuid)
self._gui_api._modal_handle_from_uuid.pop(self._uuid)


def _get_data_url(url: str, image_root: Path | None) -> str:
Expand Down
Loading
Loading