Skip to content

Commit c2d74d4

Browse files
committed
refactor: 改进类型注解并修复代码风格
1 parent 0d6bfbf commit c2d74d4

12 files changed

Lines changed: 125 additions & 121 deletions

File tree

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ zmq>=0.0.0
66
pywin32>=311
77
loguru>=0.7.3
88
debugpy>=1.8.20
9+
PyQt5-stubs>=5.15.6.0

src/lib_zmq_plugins/client/zmq_client.py

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -104,31 +104,6 @@ def connect(self) -> None:
104104
# 启动后立即发一次心跳作为探测
105105
self._probe_connection()
106106

107-
@property
108-
def is_connected(self) -> bool:
109-
"""当前连接状态"""
110-
return self._is_connected
111-
112-
@property
113-
def reconnect_count(self) -> int:
114-
"""重连次数"""
115-
return self._reconnect_count
116-
117-
@property
118-
def endpoint(self) -> str:
119-
"""当前端点地址"""
120-
return self._endpoint
121-
122-
@property
123-
def pub_endpoint(self) -> str:
124-
"""PUB 端点地址"""
125-
return self._pub_endpoint
126-
127-
@property
128-
def ctrl_endpoint(self) -> str:
129-
"""CTRL 端点地址"""
130-
return self._ctrl_endpoint
131-
132107
def disconnect(self) -> None:
133108
self._stopped.set()
134109
if self._thread and self._thread.is_alive():
@@ -145,6 +120,8 @@ def _create_sockets(self) -> None:
145120
return
146121
self._sub_socket = self._ctx.socket(zmq.SUB)
147122
self._dealer_socket = self._ctx.socket(zmq.DEALER)
123+
if self._dealer_socket is None:
124+
return
148125
self._dealer_socket.setsockopt_string(zmq.IDENTITY, uuid.uuid4().hex)
149126

150127
# 启用 ZMQ 原生心跳,自动检测服务端断开
@@ -154,7 +131,8 @@ def _create_sockets(self) -> None:
154131
self._dealer_socket.setsockopt(zmq.HEARTBEAT_IVL, 5000)
155132
self._dealer_socket.setsockopt(zmq.HEARTBEAT_TIMEOUT, 5000)
156133
self._dealer_socket.setsockopt(zmq.HEARTBEAT_TTL, 10000)
157-
134+
if self._sub_socket is None:
135+
return
158136
self._sub_socket.connect(self._pub_endpoint)
159137
self._dealer_socket.connect(self._ctrl_endpoint)
160138

@@ -202,7 +180,8 @@ def _request_snapshot(self, topic: str) -> None:
202180
try:
203181
self._dealer_socket.send(payload)
204182
except zmq.ZMQError:
205-
self._log.warning("Failed to send sync request for topic: %s", topic)
183+
self._log.warning(
184+
"Failed to send sync request for topic: %s", topic)
206185
self._sync_topics.pop(rid, None)
207186

208187
# ── 指令发送(可在任意线程调用) ──
@@ -231,7 +210,7 @@ def request(
231210
def _poll_loop(self) -> None:
232211
while not self._stopped.is_set():
233212
try:
234-
events = self._poller.poll(timeout=200)
213+
events = self._poller.poll(timeout=200) # type: ignore
235214
except zmq.ZMQError:
236215
self._handle_reconnect(0.1)
237216
continue
@@ -275,7 +254,7 @@ def _probe_connection(self) -> bool:
275254

276255
def _handle_sub_message(self) -> None:
277256
try:
278-
msg = self._sub_socket.recv_multipart(zmq.NOBLOCK)
257+
msg = self._sub_socket.recv_multipart(zmq.NOBLOCK) # type: ignore
279258
except zmq.Again:
280259
return
281260
if len(msg) < 2:
@@ -293,7 +272,8 @@ def _handle_sub_message(self) -> None:
293272

294273
def _handle_dealer_message(self) -> None:
295274
try:
296-
msg = self._dealer_socket.recv_multipart(zmq.NOBLOCK)
275+
msg = self._dealer_socket.recv_multipart( # type: ignore
276+
zmq.NOBLOCK)
297277
except zmq.Again:
298278
return
299279
if len(msg) < 2:
@@ -312,7 +292,8 @@ def _handle_dealer_message(self) -> None:
312292
snapshot = self._serializer.decode_event(resp.data)
313293
self._notify_subscribers(topic, snapshot)
314294
except Exception:
315-
self._log.warning("Failed to decode snapshot", exc_info=True)
295+
self._log.warning(
296+
"Failed to decode snapshot", exc_info=True)
316297
else:
317298
self._sync_topics.pop(resp.request_id, None)
318299

src/lib_zmq_plugins/serializer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def _make_union(types: list[type]) -> type:
2929
"""将类型列表转为 Union 类型,供 msgspec 多态反序列化使用"""
3030
if len(types) == 1:
3131
return types[0]
32-
return Union[tuple(types)]
32+
return Union[tuple(types)] # type: ignore
3333

3434

3535
class Serializer:

src/lib_zmq_plugins/server/zmq_server.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ def __init__(self, endpoint: str, log_handler: LogHandler | None = None) -> None
4646
self._pub_endpoint, self._ctrl_endpoint = _derive_endpoints(endpoint)
4747
self._serializer = Serializer()
4848
self._serializer.register_command_types(SyncCommand)
49-
self._handlers: dict[str, Callable[[BaseCommand], CommandResponse | None]] = {}
49+
self._handlers: dict[str, Callable[[
50+
BaseCommand], CommandResponse | None]] = {}
5051
self._snapshot_providers: dict[str, Callable[[], BaseEvent]] = {}
5152
self._log: LogHandler = log_handler or NullHandler()
5253

@@ -89,7 +90,8 @@ def start(self) -> None:
8990
self._ctx = zmq.Context()
9091
self._pub_socket = self._ctx.socket(zmq.PUB)
9192
self._router_socket = self._ctx.socket(zmq.ROUTER)
92-
93+
if self._pub_socket is None or self._router_socket is None:
94+
raise RuntimeError("Failed to create socket")
9395
# 启用 ZMQ 原生心跳,与客户端匹配
9496
# HEARTBEAT_IVL: 每 5 秒发送心跳
9597
# HEARTBEAT_TIMEOUT: 5 秒内没收到回复视为断连
@@ -108,7 +110,8 @@ def start(self) -> None:
108110
self._thread = threading.Thread(target=self._poll_loop, daemon=True)
109111
self._thread.start()
110112

111-
self._log.info("Server started: pub=%s, ctrl=%s", self._pub_endpoint, self._ctrl_endpoint)
113+
self._log.info("Server started: pub=%s, ctrl=%s",
114+
self._pub_endpoint, self._ctrl_endpoint)
112115

113116
def stop(self) -> None:
114117
self._stopped.set()
@@ -141,14 +144,15 @@ def publish(self, topic: type[BaseEvent], event: BaseEvent) -> None:
141144
def _poll_loop(self) -> None:
142145
while not self._stopped.is_set():
143146
try:
144-
events = self._poller.poll(timeout=100)
147+
events = self._poller.poll(timeout=100) # type: ignore
145148
except zmq.ZMQError:
146149
break
147150

148151
for socket, _ in events:
149152
if socket is self._router_socket:
150153
try:
151-
msg = self._router_socket.recv_multipart(zmq.NOBLOCK)
154+
msg = self._router_socket.recv_multipart( # type: ignore
155+
zmq.NOBLOCK)
152156
except zmq.Again:
153157
continue
154158
if len(msg) < 2:
@@ -158,7 +162,8 @@ def _poll_loop(self) -> None:
158162
try:
159163
cmd = self._serializer.decode_command(payload)
160164
except Exception:
161-
self._log.warning("Failed to decode command", exc_info=True)
165+
self._log.warning(
166+
"Failed to decode command", exc_info=True)
162167
continue
163168
self._dispatch(client_id, cmd)
164169

@@ -167,11 +172,12 @@ def _dispatch(self, client_id: bytes, cmd: BaseCommand) -> None:
167172
if isinstance(tag, type):
168173
tag = tag.__name__
169174
tag = str(tag)
170-
171-
self._log.info("[Server] 收到命令: tag=%s, request_id=%s", tag, cmd.request_id)
175+
176+
self._log.info("[Server] 收到命令: tag=%s, request_id=%s",
177+
tag, cmd.request_id)
172178

173179
if tag == "__sync__":
174-
self._handle_sync(client_id, cmd)
180+
self._handle_sync(client_id, cmd) # type: ignore
175181
return
176182

177183
handler = self._handlers.get(tag)
@@ -181,7 +187,8 @@ def _dispatch(self, client_id: bytes, cmd: BaseCommand) -> None:
181187

182188
try:
183189
result = handler(cmd)
184-
self._log.info("[Server] handler 执行完成: tag=%s, result=%s", tag, result)
190+
self._log.info(
191+
"[Server] handler 执行完成: tag=%s, result=%s", tag, result)
185192
except Exception as e:
186193
self._log.error("Handler error for %s: %s", tag, e, exc_info=True)
187194
if cmd.request_id:
@@ -211,7 +218,8 @@ def _handle_sync(self, client_id: bytes, cmd: SyncCommand) -> None:
211218
request_id=cmd.request_id, success=True, data=payload
212219
)
213220
except Exception as e:
214-
self._log.error("Snapshot provider error for %s: %s", topic, e, exc_info=True)
221+
self._log.error(
222+
"Snapshot provider error for %s: %s", topic, e, exc_info=True)
215223
resp = CommandResponse(
216224
request_id=cmd.request_id, success=False, error=str(e)
217225
)
@@ -225,4 +233,5 @@ def _send_to_client(self, client_id: bytes, resp: CommandResponse) -> None:
225233
[client_id, b"", self._serializer.encode_response(resp)]
226234
)
227235
except zmq.ZMQError:
228-
self._log.warning("Failed to send response to client", exc_info=True)
236+
self._log.warning(
237+
"Failed to send response to client", exc_info=True)

src/plugin_manager/plugin_loader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class PluginLoader:
2828
- 实例化插件类
2929
"""
3030

31-
def __init__(self, plugin_dirs: list[str | Path] | None = None):
31+
def __init__(self, plugin_dirs: list[Path] | None = None):
3232
self._plugin_dirs: list[Path] = []
3333
self._added_paths: set[Path] = set() # 已添加到 sys.path 的目录
3434
if plugin_dirs:

src/plugin_manager/plugin_manager.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class PluginManager:
6464
def __init__(
6565
self,
6666
endpoint: str,
67-
plugin_dirs: list[str | Path] | None = None,
67+
plugin_dirs: list[Path] | None = None,
6868
log_handler: LogHandler | None = None,
6969
):
7070
self._endpoint = endpoint
@@ -223,7 +223,7 @@ def stop(self) -> None:
223223
"""停止插件管理器(调用优雅关闭)"""
224224
self._graceful_shutdown()
225225

226-
def start_with_gui(self, app: QApplication = None, *, show_main_window: bool = True) -> None:
226+
def start_with_gui(self, app: QApplication = None, *, show_main_window: bool = True) -> None: # type: ignore
227227
"""
228228
启动插件管理器并显示主界面
229229
@@ -267,7 +267,7 @@ def exec_gui(self, *, show_main_window: bool = True) -> int:
267267
if self._app is None:
268268
self.start_with_gui(show_main_window=show_main_window)
269269

270-
result = self._app.exec_()
270+
result = self._app.exec_() # type: ignore
271271
self.stop()
272272
return result
273273

@@ -390,7 +390,7 @@ def run_plugin_manager_process(
390390
退出代码
391391
"""
392392
manager = PluginManager(
393-
endpoint=endpoint, plugin_dirs=plugin_dirs, log_handler=_LogHandler()
393+
endpoint=endpoint, plugin_dirs=plugin_dirs, log_handler=_LogHandler() # type: ignore
394394
)
395395

396396
try:

src/plugin_sdk/config_types/base_config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from typing import Any, Callable, ClassVar, Generic, TypeVar
1212

1313
from PyQt5.QtWidgets import QWidget
14-
from PyQt5.QtCore import pyqtSignal, QObject
14+
from PyQt5.QtCore import pyqtBoundSignal, pyqtSignal, QObject
1515

1616
T = TypeVar("T")
1717

@@ -49,7 +49,7 @@ def __init__(
4949
widget: QWidget,
5050
getter: Callable[[], Any],
5151
setter: Callable[[Any], None],
52-
signal: QObject,
52+
signal: pyqtBoundSignal,
5353
parent: QWidget | None = None,
5454
):
5555
super().__init__(parent)

src/plugin_sdk/plugin_base.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
"""
1111

1212
from __future__ import annotations
13+
from pathlib import Path
14+
15+
1316
from .service_registry import ServiceNotFoundError
14-
from lib_zmq_plugins.shared.base import BaseEvent, get_event_tag
17+
from lib_zmq_plugins.shared.base import BaseEvent, CommandResponse, get_event_tag
1518
from PyQt5.QtGui import QIcon, QPixmap, QPainter, QPen, QColor, QBrush, QFont
1619
from PyQt5.QtCore import Qt, QThread, QObject, pyqtSignal, pyqtSlot
1720

@@ -29,7 +32,7 @@
2932

3033
if TYPE_CHECKING:
3134
from .config_types import OtherInfoBase
32-
35+
from plugin_manager.logging_setup import LogConfig
3336
if TYPE_CHECKING:
3437
from PyQt5.QtGui import QIcon
3538

@@ -77,8 +80,8 @@ def make_plugin_icon(
7780
p.setBrush(Qt.NoBrush) # type: ignore[attr-defined]
7881
font = QFont("Segoe UI Emoji", int(size * 0.44), QFont.Bold)
7982
p.setFont(font)
80-
p.drawText(pix.rect(), Qt.AlignCenter | Qt.AlignVCenter,
81-
symbol) # type: ignore[attr-defined]
83+
p.drawText(pix.rect(), Qt.AlignCenter | Qt.AlignVCenter, # type: ignore[attr-defined]
84+
symbol)
8285
p.end()
8386

8487
return QIcon(pix)
@@ -249,7 +252,7 @@ def __init__(self, info: PluginInfo):
249252

250253
# 连接 gui_call 信号到槽(QueuedConnection 跨线程安全)
251254
self.gui_call.connect(
252-
self._on_gui_call, Qt.ConnectionType.QueuedConnection)
255+
self._on_gui_call, Qt.ConnectionType.QueuedConnection) # type: ignore
253256

254257
# 每个插件拥有独立的 loguru logger(日志写入 plugins/<name>.log)
255258
from plugin_manager.logging_setup import get_plugin_logger

0 commit comments

Comments
 (0)