From 139b8a60b9ba7cba65f3ddb5879a8deffe9680bb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 29 Jan 2022 13:35:31 -0600 Subject: [PATCH 1/4] Fix unsafe __del__ in TPLinkSmartHomeProtocol Fixes ``` Exception ignored in: Traceback (most recent call last): File "/Users/bdraco/home-assistant/venv/lib/python3.9/site-packages/kasa/protocol.py", line 159, in __del__ self.writer.close() File "/opt/homebrew/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/streams.py", line 353, in close return self._transport.close() File "/opt/homebrew/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/selector_events.py", line 700, in close self._loop.call_soon(self._call_connection_lost, None) File "/opt/homebrew/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 748, in call_soon self._check_thread() File "/opt/homebrew/Cellar/python@3.9/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 785, in _check_thread raise RuntimeError( RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one ``` --- kasa/protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kasa/protocol.py b/kasa/protocol.py index 14de9c6c6..802760268 100755 --- a/kasa/protocol.py +++ b/kasa/protocol.py @@ -156,7 +156,7 @@ async def _query(self, request: str, retry_count: int, timeout: int) -> Dict: def __del__(self) -> None: if self.writer and self.loop and self.loop.is_running(): - self.writer.close() + self.loop.call_soon_threadsafe(self.writer.close) self._reset() @staticmethod From 845aa2358a2d142a9e033eb9f7a8cb479f0507d3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 30 Jan 2022 14:48:57 -0600 Subject: [PATCH 2/4] comment --- kasa/protocol.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kasa/protocol.py b/kasa/protocol.py index 802760268..24d1422bd 100755 --- a/kasa/protocol.py +++ b/kasa/protocol.py @@ -156,6 +156,10 @@ async def _query(self, request: str, retry_count: int, timeout: int) -> Dict: def __del__(self) -> None: if self.writer and self.loop and self.loop.is_running(): + # Since __del__ will be called when python does + # garbage collection is can happen in the event loop + # or in a thread so we need to make sure the call to + # close is called safely with call_soon_threadsafe self.loop.call_soon_threadsafe(self.writer.close) self._reset() From a126f2a724cb94d0ea5d00292d89cec192000d90 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 30 Jan 2022 14:49:26 -0600 Subject: [PATCH 3/4] comment --- kasa/protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kasa/protocol.py b/kasa/protocol.py index 24d1422bd..5ea51e477 100755 --- a/kasa/protocol.py +++ b/kasa/protocol.py @@ -158,7 +158,7 @@ def __del__(self) -> None: if self.writer and self.loop and self.loop.is_running(): # Since __del__ will be called when python does # garbage collection is can happen in the event loop - # or in a thread so we need to make sure the call to + # or in another thread so we need to make sure the call to # close is called safely with call_soon_threadsafe self.loop.call_soon_threadsafe(self.writer.close) self._reset() From d804a190a05354a7d53a8fcf4779d5326a8138dd Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 30 Jan 2022 14:49:40 -0600 Subject: [PATCH 4/4] comment --- kasa/protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kasa/protocol.py b/kasa/protocol.py index 5ea51e477..e2f946269 100755 --- a/kasa/protocol.py +++ b/kasa/protocol.py @@ -157,7 +157,7 @@ async def _query(self, request: str, retry_count: int, timeout: int) -> Dict: def __del__(self) -> None: if self.writer and self.loop and self.loop.is_running(): # Since __del__ will be called when python does - # garbage collection is can happen in the event loop + # garbage collection is can happen in the event loop thread # or in another thread so we need to make sure the call to # close is called safely with call_soon_threadsafe self.loop.call_soon_threadsafe(self.writer.close)