From c0b0994feddc8a51d49fef66f601a183d16b7f4d Mon Sep 17 00:00:00 2001 From: Dawn Date: Tue, 8 Sep 2026 14:16:16 +0200 Subject: [PATCH] fix: satisfy basedpyright on the Optional subscriber and socket CI lint failed on reportOptionalMemberAccess: prediction_thread is None when the GUI runs without a sample feed, and _sock is nulled by run()'s cleanup, so both attributes are Optional to the checker even though the flagged call sites cannot see None at runtime. Guard the slot and bind the socket to a local asserted non-None in _recv_latest. Co-Authored-By: Claude Fable 5.1 --- src/aare/gui/main_window.py | 5 ++++- src/aare/gui/threads/prediction_subscriber.py | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/aare/gui/main_window.py b/src/aare/gui/main_window.py index 471b342a..40b98ec4 100644 --- a/src/aare/gui/main_window.py +++ b/src/aare/gui/main_window.py @@ -1631,7 +1631,10 @@ class MainWindow(QMainWindow): if view.isVisible(): view.update_pixmap(pixmap) finally: - self.prediction_thread.notify_frame_displayed() + # The slot is only connected once the subscriber exists, but the + # attribute is Optional so the guard is what the type checker needs. + if self.prediction_thread is not None: + self.prediction_thread.notify_frame_displayed() @Slot(bool) def _on_sample_camera_availability_changed(self, available: bool) -> None: diff --git a/src/aare/gui/threads/prediction_subscriber.py b/src/aare/gui/threads/prediction_subscriber.py index 1def221c..e5c40980 100644 --- a/src/aare/gui/threads/prediction_subscriber.py +++ b/src/aare/gui/threads/prediction_subscriber.py @@ -201,10 +201,14 @@ class PredictionSubscriber(QThread): backlog that piled up while we were busy, and the stream is always consumed at line rate no matter how long a frame takes to decode. """ - parts = self._sock.recv_multipart() # honours RCVTIMEO, may raise zmq.Again + # Bind locally: run() nulls the attribute on cleanup, so it is Optional + # to the type checker even though it cannot be None while run() loops. + sock = self._sock + assert sock is not None, "_recv_latest called after the socket was closed" + parts = sock.recv_multipart() # honours RCVTIMEO, may raise zmq.Again while True: try: - parts = self._sock.recv_multipart(zmq.NOBLOCK) + parts = sock.recv_multipart(zmq.NOBLOCK) except zmq.Again: return parts self._dropped += 1