Refactor protocol and transport modules to use type hints for improved clarity and consistency

- Updated Codec class to use abstract methods for encoding and decoding envelopes.
- Changed Envelope class to use Dict and Optional for payload and error fields.
- Refined error handling in RPCError class with Optional type hints for details.
- Enhanced manifest validation logic with type hints for better type safety.
- Improved plugin loading mechanism with consistent type annotations.
- Updated RPCClient to utilize Optional for codec and connection attributes.
- Refactored transport classes to use Optional for server attributes and socket paths.
This commit is contained in:
DrSmoothl
2026-03-11 00:07:13 +08:00
parent 7f1e79ea28
commit 69219e36f7
19 changed files with 273 additions and 253 deletions

View File

@@ -7,7 +7,7 @@
"""
from collections import deque
from typing import Any
from typing import Any, Dict, List, Optional, Set, Tuple
import importlib
import importlib.util
@@ -29,7 +29,7 @@ class PluginMeta:
plugin_id: str,
plugin_dir: str,
plugin_instance: Any,
manifest: dict[str, Any],
manifest: Dict[str, Any],
):
self.plugin_id = plugin_id
self.plugin_dir = plugin_dir
@@ -37,12 +37,12 @@ class PluginMeta:
self.manifest = manifest
self.version = manifest.get("version", "1.0.0")
self.capabilities_required = manifest.get("capabilities", [])
self.dependencies: list[str] = self._extract_dependencies(manifest)
self.dependencies: List[str] = self._extract_dependencies(manifest)
@staticmethod
def _extract_dependencies(manifest: dict[str, Any]) -> list[str]:
def _extract_dependencies(manifest: Dict[str, Any]) -> List[str]:
raw = manifest.get("dependencies", [])
result: list[str] = []
result: List[str] = []
for dep in raw:
if isinstance(dep, str):
result.append(dep.strip())
@@ -62,12 +62,12 @@ class PluginLoader:
"""
def __init__(self, host_version: str = ""):
self._loaded_plugins: dict[str, PluginMeta] = {}
self._failed_plugins: dict[str, str] = {}
self._loaded_plugins: Dict[str, PluginMeta] = {}
self._failed_plugins: Dict[str, str] = {}
self._manifest_validator = ManifestValidator(host_version=host_version)
self._compat_hook_installed = False
def discover_and_load(self, plugin_dirs: list[str]) -> list[PluginMeta]:
def discover_and_load(self, plugin_dirs: List[str]) -> List[PluginMeta]:
"""扫描多个目录并加载所有插件(含依赖排序和 manifest 校验)
Args:
@@ -77,7 +77,7 @@ class PluginLoader:
成功加载的插件元数据列表(按依赖顺序)
"""
# 第一阶段:发现并校验 manifest
candidates: dict[str, tuple[str, dict[str, Any], str]] = {} # id -> (dir, manifest, plugin_path)
candidates: Dict[str, Tuple[str, Dict[str, Any], str]] = {} # id -> (dir, manifest, plugin_path)
for base_dir in plugin_dirs:
if not os.path.isdir(base_dir):
logger.warning(f"插件目录不存在: {base_dir}")
@@ -131,33 +131,33 @@ class PluginLoader:
return results
def get_plugin(self, plugin_id: str) -> PluginMeta | None:
def get_plugin(self, plugin_id: str) -> Optional[PluginMeta]:
"""获取已加载的插件"""
return self._loaded_plugins.get(plugin_id)
def list_plugins(self) -> list[str]:
def list_plugins(self) -> List[str]:
"""列出所有已加载的插件 ID"""
return list(self._loaded_plugins.keys())
@property
def failed_plugins(self) -> dict[str, str]:
def failed_plugins(self) -> Dict[str, str]:
return dict(self._failed_plugins)
# ──── 依赖解析 ────────────────────────────────────────────
def _resolve_dependencies(
self,
candidates: dict[str, tuple[str, dict[str, Any], str]],
) -> tuple[list[str], dict[str, str]]:
candidates: Dict[str, Tuple[str, Dict[str, Any], str]],
) -> Tuple[List[str], Dict[str, str]]:
"""拓扑排序解析加载顺序,返回 (有序列表, 失败项 {id: reason})。"""
available = set(candidates.keys())
dep_graph: dict[str, set[str]] = {}
failed: dict[str, str] = {}
dep_graph: Dict[str, Set[str]] = {}
failed: Dict[str, str] = {}
for pid, (_, manifest, _) in candidates.items():
raw_deps = manifest.get("dependencies", [])
resolved: set[str] = set()
missing: list[str] = []
resolved: Set[str] = set()
missing: List[str] = []
for dep in raw_deps:
dep_name = dep if isinstance(dep, str) else str(dep.get("name", ""))
dep_name = dep_name.strip()
@@ -177,14 +177,14 @@ class PluginLoader:
# Kahn 拓扑排序
indegree = {pid: len(deps) for pid, deps in dep_graph.items()}
reverse: dict[str, set[str]] = {pid: set() for pid in dep_graph}
reverse: Dict[str, Set[str]] = {pid: set() for pid in dep_graph}
for pid, deps in dep_graph.items():
for d in deps:
if d in reverse:
reverse[d].add(pid)
queue = deque(sorted(pid for pid, deg in indegree.items() if deg == 0))
sorted_order: list[str] = []
sorted_order: List[str] = []
while queue:
current = queue.popleft()
@@ -206,9 +206,9 @@ class PluginLoader:
self,
plugin_id: str,
plugin_dir: str,
manifest: dict[str, Any],
manifest: Dict[str, Any],
plugin_path: str,
) -> PluginMeta | None:
) -> Optional[PluginMeta]:
"""加载单个插件"""
# 确保兼容层导入钩子已安装(旧版插件可能 import src.plugin_system
self._ensure_compat_hook()
@@ -267,7 +267,7 @@ class PluginLoader:
logger.debug("maibot_sdk.compat 不可用,跳过导入钩子安装")
@staticmethod
def _try_load_legacy_plugin(module: Any, plugin_id: str) -> Any | None:
def _try_load_legacy_plugin(module: Any, plugin_id: str) -> Optional[Any]:
"""尝试从模块中发现旧版 BasePlugin 子类并包装为 LegacyPluginAdapter"""
# 方式 1: @register_plugin 装饰器设置的标记
legacy_cls = getattr(module, "_legacy_plugin_class", None)