-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplugin_base.py
More file actions
226 lines (184 loc) · 6.66 KB
/
Copy pathplugin_base.py
File metadata and controls
226 lines (184 loc) · 6.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
"""
插件基类模块 — 为插件开发者提供标准化的类继承接口
使用方式一(类继承,推荐):
from plugin_base import PluginBase
class MyPlugin(PluginBase):
def on_initialize(self) -> bool:
self.api.register_hook('on_ui_ready', self._on_ui_ready)
return True
def _on_ui_ready(self, main_window):
pass
def on_shutdown(self):
pass
PLUGIN_CLASS = MyPlugin
使用方式二(函数导出,兼容旧方式):
def initialize(api):
...
def shutdown():
...
"""
from abc import ABC, abstractmethod
from typing import Any, Callable, Optional
class PluginBase(ABC):
"""
插件基类 — 封装生命周期管理与API访问
生命周期:
__init__(api) → initialize() → on_initialize()
启用: enable() → on_enable()
禁用: disable() → on_disable()
卸载: shutdown() → on_shutdown()
子类只需重写 on_* 方法即可。
"""
def __init__(self, api):
self._api = api
self._plugin_dir = api.plugin_dir # 在 PluginManager 设置 _current_plugin_dir 期间捕获
self._enabled = False
self._initialized = False
# ==================== 属性 ====================
@property
def api(self):
"""PluginAPI 实例,提供 data / config / logger / ui / hooks 等所有接口"""
return self._api
@property
def enabled(self) -> bool:
return self._enabled
@property
def plugin_dir(self) -> str:
"""当前插件目录路径,在插件整个生命周期内有效"""
return self._plugin_dir
# ==================== 框架调用(不要重写) ====================
def initialize(self, api=None) -> bool:
"""由 PluginManager 调用,触发 on_initialize。插件不要重写此方法。"""
if api is not None:
self._api = api
try:
result = self.on_initialize()
self._initialized = bool(result)
return self._initialized
except Exception:
import logger
_log = logger.setup_logger(log_dir_path='files/logs', log_filename='plugin_base.log')
_log.error(f"插件 {self.__class__.__name__} on_initialize 失败", exc_info=True)
return False
def shutdown(self):
"""由 PluginManager 调用,触发 on_shutdown。插件不要重写此方法。"""
try:
if self._enabled:
self.on_disable()
self._enabled = False
self.on_shutdown()
except Exception:
import logger
_log = logger.setup_logger(log_dir_path='files/logs', log_filename='plugin_base.log')
_log.error(f"插件 {self.__class__.__name__} shutdown 失败", exc_info=True)
finally:
self._initialized = False
def enable(self) -> bool:
"""启用插件"""
if not self._enabled:
try:
self.on_enable()
self._enabled = True
except Exception:
import logger
_log = logger.setup_logger(log_dir_path='files/logs', log_filename='plugin_base.log')
_log.error(f"插件 {self.__class__.__name__} on_enable 失败", exc_info=True)
return False
return True
def disable(self):
"""禁用插件"""
if self._enabled:
try:
self.on_disable()
except Exception:
import logger
_log = logger.setup_logger(log_dir_path='files/logs', log_filename='plugin_base.log')
_log.error(f"插件 {self.__class__.__name__} on_disable 失败", exc_info=True)
finally:
self._enabled = False
# ==================== 子类重写点 ====================
@abstractmethod
def on_initialize(self) -> bool:
"""
插件初始化时调用(子类必须实现)。
在此注册钩子、菜单、创建资源等。
:return: 是否初始化成功
"""
...
def on_enable(self):
"""插件被启用时调用"""
def on_disable(self):
"""插件被禁用时调用"""
def on_shutdown(self):
"""插件卸载/应用退出时调用。清理所有资源。"""
# ==================== 便捷方法 ====================
def register_hook(self, hook_name: str, callback: Callable):
"""注册生命周期钩子"""
self._api.register_hook(hook_name, callback)
def log(self, msg: str, level: str = 'info'):
"""使用主程序日志记录"""
import logger
_log = logger.setup_logger(log_dir_path='files/logs', log_filename='plugin_base.log')
getattr(_log, level, _log.info)(f"[{self.__class__.__name__}] {msg}")
class DataPluginBase(PluginBase):
"""
数据插件基类 — 专注于数据处理与验证
适用于需要导入/导出/清洗数据的插件
"""
@abstractmethod
def process_data(self, data: Any) -> Any:
"""
处理数据(子类必须实现)
:param data: 输入数据
:return: 处理后的数据
"""
...
@abstractmethod
def validate_data(self, data: Any) -> bool:
"""
验证数据格式(子类必须实现)
:param data: 待验证的数据
:return: 是否有效
"""
...
class UIPluginBase(PluginBase):
"""
UI插件基类 — 提供独立界面面板
适用于需要在主界面中嵌入自定义控件的插件
"""
@abstractmethod
def get_widget(self):
"""
获取UI组件(子类必须实现)
:return: QWidget 实例
"""
...
@abstractmethod
def on_show(self):
"""UI显示时调用"""
@abstractmethod
def on_hide(self):
"""UI隐藏时调用"""
class FileOperationPluginBase(PluginBase):
"""
文件操作插件基类 — 拦截文件操作
适用于需要在读写文件前后执行额外处理的插件
"""
@abstractmethod
def before_operation(self, file_path: str, operation: str) -> bool:
"""
文件操作前钩子(子类必须实现)
:param file_path: 文件路径
:param operation: 操作类型 (read/write/copy/move/delete)
:return: 是否允许继续操作
"""
...
@abstractmethod
def after_operation(self, file_path: str, operation: str, success: bool):
"""
文件操作后钩子(子类必须实现)
:param file_path: 文件路径
:param operation: 操作类型
:param success: 操作是否成功
"""
...