diff --git a/skillbridge/client/channel.py b/skillbridge/client/channel.py index c211e82..c67c610 100644 --- a/skillbridge/client/channel.py +++ b/skillbridge/client/channel.py @@ -31,7 +31,7 @@ def max_transmission_length(self, value: int) -> None: def __del__(self) -> None: try: self.close() - except BrokenPipeError: + except: # noqa pass @staticmethod diff --git a/skillbridge/client/workspace.py b/skillbridge/client/workspace.py index 01de15c..b97bf4a 100644 --- a/skillbridge/client/workspace.py +++ b/skillbridge/client/workspace.py @@ -1,6 +1,7 @@ import sys from functools import partial from inspect import signature +from logging import getLogger from textwrap import dedent from typing import Any, Callable, Dict, Iterable, NoReturn, Optional, Union, cast @@ -17,6 +18,9 @@ _open_workspaces: Dict[WorkspaceId, 'Workspace'] = {} +logger = getLogger(__file__) + + class _NoWorkspace: id = object() is_current = False @@ -253,8 +257,13 @@ def open(cls, workspace_id: WorkspaceId = None, direct: bool = False) -> 'Worksp _open_workspaces[workspace_id] = Workspace(channel, workspace_id) return _open_workspaces[workspace_id] - def close(self) -> None: - self._channel.close() + def close(self, log_exception: bool = True) -> None: + try: + self._channel.close() + except: # noqa + if log_exception: + logger.exception("Failed to close workspace") + _open_workspaces.pop(self.id, None) if current_workspace.id == self.id: diff --git a/tests/test_workspace.py b/tests/test_workspace.py new file mode 100644 index 0000000..2fac7b7 --- /dev/null +++ b/tests/test_workspace.py @@ -0,0 +1,29 @@ +from typing import Any + +from skillbridge import Workspace +from skillbridge.client.channel import Channel +from skillbridge.client.translator import DefaultTranslator +from skillbridge.client.workspace import _open_workspaces + + +class DummyChannel(Channel): + def send(self, data: str) -> str: + pass + + def flush(self) -> None: + pass + + def try_repair(self) -> Any: + pass + + def close(self): + raise RuntimeError("no, i won't close") + + +def test_a_crash_while_closing_still_clears_the_cache(): + dummy_channel = DummyChannel(1) + ws = Workspace(channel=dummy_channel, id_=123, translator=DefaultTranslator()) + _open_workspaces[123] = ws + + ws.close() + assert 123 not in _open_workspaces