clovers 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
clovers-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 KarisAya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
clovers-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,382 @@
1
+ Metadata-Version: 2.1
2
+ Name: clovers
3
+ Version: 0.1.0
4
+ Summary:
5
+ Author: KarisAya
6
+ Author-email: 1048827424@qq.com
7
+ Requires-Python: >=3.12,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Dist: toml (>=0.10.2,<0.11.0)
10
+ Description-Content-Type: text/markdown
11
+
12
+ # CLOVERS
13
+
14
+ _✨ 自定义的聊天平台异步机器人指令-响应插件框架 ✨_
15
+
16
+ <div align="center">
17
+ <img src="https://img.shields.io/badge/python-3.12+-blue.svg" alt="python">
18
+ <a href="./LICENSE">
19
+ <img src="https://img.shields.io/github/license/KarisAya/clovers.svg" alt="license">
20
+ </a>
21
+ <a href="https://pypi.python.org/pypi/clovers">
22
+ <img src="https://img.shields.io/pypi/v/clovers.svg" alt="pypi">
23
+ </a>
24
+ <a href="https://pypi.python.org/pypi/clovers">
25
+ <img src="https://img.shields.io/pypi/dm/clovers" alt="pypi download">
26
+ </a>
27
+ </div>
28
+
29
+ ## 💿 安装
30
+
31
+ <details open>
32
+ <summary>pip</summary>
33
+
34
+ ```bash
35
+ pip install clovers
36
+ ```
37
+
38
+ </details>
39
+
40
+ <details>
41
+ <summary>poetry</summary>
42
+
43
+ ```bash
44
+ poetry add clovers
45
+ ```
46
+
47
+ </details>
48
+
49
+ ## 插件获取配置
50
+
51
+ 配置文件存放在一个 toml 文件里,文件由你指定
52
+
53
+ 下面是配置一个例子
54
+
55
+ clovers.toml
56
+
57
+ ```toml
58
+ [nonebot_plugin_clovers]
59
+ plugins_path = "./clovers/plugins"
60
+ plugins_list = ["clovers_apscheduler"]
61
+ ```
62
+
63
+ 意味着 clovers 会加载`./clovers/plugins`文件夹下的文件或文件夹作为插件(排除`_`开头的文件)
64
+
65
+ 插件获取的配置会是一个字典。
66
+
67
+ 为便于插件间的配置互相获取,建议在插件中使用类似下面的代码加载配置
68
+
69
+ ```python
70
+ from clovers.core.config import config as clovers_config
71
+ config_key = __package__ # 或者你自定义的任何key
72
+ default_config = {"some_config_name":"some_config_value"}
73
+ # 各种方法获取配置
74
+ config_data = clovers_config.get(config_key, {})
75
+ default_config.update(config_data)
76
+ # 把配置存回总配置
77
+ clovers_config[config_key] = config_data
78
+ ```
79
+
80
+ 当然你也可以不这么做
81
+
82
+ ## 关于插件
83
+
84
+ 下面是一个模板
85
+
86
+ ```python
87
+ from clovers.core.config import config as clovers_config
88
+ from clovers.core.plugin import Plugin
89
+ from .config import Config
90
+
91
+ # 获取你的配置
92
+ config_key = __package__
93
+ config_data = Config.parse_obj(clovers_config.get(config_key, {}))
94
+ clovers_config[config_key] = config_data.dict()
95
+
96
+ plugin = Plugin()
97
+
98
+ # 启动时的任务
99
+ @plugin.startup
100
+ async def _():
101
+ pass
102
+
103
+ # 关闭时的任务
104
+ @plugin.shutdown
105
+ async def _():
106
+ pass
107
+
108
+
109
+ # 指令-响应任务
110
+ @plugin.handle({"测试"})
111
+ async def _(event: Event):
112
+ pass
113
+
114
+ __plugin__ = plugin
115
+ ```
116
+
117
+ 插件加载器会尝试获取你的模块的`__plugin__`属性,并作为插件放进适配器的插件列表里
118
+
119
+ 如果你想编写插件的插件,也可以不定义`__plugin__`属性,但是一般你需要使用其他插件的`__plugin__`属性
120
+
121
+ ```python
122
+ from some_plugin import __plugin__ as plugin
123
+
124
+ # do something
125
+ @plugin.handle({"其他测试"})
126
+ async def _(event: Event):
127
+ pass
128
+ ```
129
+
130
+ ### 指令-响应任务获取平台参数
131
+
132
+ 如果你在插件中需要获取一些平台参数,那么需要在注册 plugin.handle 时事先声明需要的参数
133
+
134
+ ```python
135
+ @plugin.handle({"测试"},{"user_id","others"})
136
+ async def _(event: Event):
137
+ print(event.kwargs["user_id"])
138
+ print(event.kwargs["others"])
139
+ print(event.kwargs["extra"]) # KeyError
140
+ ```
141
+
142
+ 适配器方法会根据你需要的参数构建 event.kwargs
143
+
144
+ ### 指令-响应任务中的 event
145
+
146
+ event 是你在指令-响应任务的函数中唯一获得的参数,你需要的所有东西都在 event 里
147
+
148
+ `raw_command` 触发本次响应的原始字符串
149
+ `args` 解析的参数列表
150
+
151
+ ```python
152
+ #使用 "你好世界" 触发响应
153
+ @plugin.handle({"你好"})
154
+ async def _(event: Event):
155
+ print(event.raw_command) # "你好世界"
156
+ print(event.args) # ["世界"]
157
+ ```
158
+
159
+ 如果你不想使用原始的 event,你也可以自建 event 类,然后在创建 plugin 实例时注入 build_event 方法。
160
+
161
+ ```python
162
+ from clovers.core.plugin import Plugin
163
+ class Event:
164
+ def __init__(self, event: CloversEvent):
165
+ self.event: CloversEvent = event
166
+
167
+ @property
168
+ def raw_command(self):
169
+ return self.event.raw_command
170
+
171
+ @property
172
+ def args(self):
173
+ return self.event.args
174
+
175
+ @property
176
+ def user_id(self) -> str:
177
+ return self.event.kwargs["user_id"]
178
+
179
+ plugin = Plugin(build_event=lambda event: Event(event))
180
+
181
+ @plugin.handle({"测试"},{"user_id"})
182
+ async def _(event: Event):
183
+ print(event.user_id) # "123456"
184
+ ```
185
+
186
+ ### 插件的响应
187
+
188
+ 响应的格式应该是 clovers.core.plugin.Result 类
189
+
190
+ `send_method` 控制适配器方法用什么方式发送你的数据
191
+
192
+ `data` 是要发送的原始数据
193
+
194
+ 接下来的示例是指令为 "测试" 回应 "你好" 的 插件指令-响应任务
195
+
196
+ ```python
197
+ @plugin.handle({"测试"})
198
+ async def _(event: Event):
199
+ return Result("text", "你好")
200
+ ```
201
+
202
+ 当然如果你认为这样太过繁琐,你也可以使用 build_result 方法
203
+
204
+ ```python
205
+ from clovers.core.plugin import Plugin
206
+ def build_result(result):
207
+ if isinstance(result, str):
208
+ return Result("text", result)
209
+ if isinstance(result, BytesIO):
210
+ return Result("image", result)
211
+ if isinstance(result, AnyTypeYouNeed):
212
+ return Result("any_method_you_want", result)
213
+ return result
214
+
215
+ plugin = Plugin(build_result=build_result)
216
+
217
+ @plugin.handle({"测试"},{"user_id"})
218
+ async def _(event: Event):
219
+ return "你好"
220
+ ```
221
+
222
+ ### 关于插件的其他功能
223
+
224
+ **临时任意触发任务**
225
+
226
+ ```python
227
+ @plugin.temp_handle("temp_handle1", {"user_id", "group_id"}, 30)
228
+ async def _(event: Event, finish):
229
+ if i_should_finish:
230
+ finish()
231
+ ```
232
+
233
+ 需要的三个参数
234
+
235
+ `key` 临时任务 key 如果这个 key 被注册过,并且没有超时也没有结束,那么之前的任务会被下面的任务覆盖
236
+
237
+ `extra_args` 需要的平台参数
238
+
239
+ `timeout` 任务超时时间(秒)
240
+
241
+ temp_handle 会被任意消息触发,请在任务内自定义检查规则。
242
+
243
+ temp_handle 任务除了 event,你还会获得一个 Callable 参数 finish,它的功能是结束本任务。如果你不结束,在临时任务超时前每次消息都会触发。
244
+
245
+ **关于 handle 任务的指令格式和参数列表**
246
+
247
+ set 格式:合集内的指令都会触发插件
248
+
249
+ ```python
250
+ #触发指令为"你好 世界"时,输出 ["世界"]
251
+ #触发指令为"hello1 world with extra args"时,输出 ["1","world","with","extra","args"]
252
+ @plugin.handle({"你好","hello"})
253
+ async def _(event: Event):
254
+ print(event.args)
255
+ ```
256
+
257
+ 字符串格式:正则匹配
258
+
259
+ 如果 handle 的指令参数是字符串那么它会进行正则匹配,args 会是正则字符串中的 group 列表
260
+
261
+ ```python
262
+ #触发指令为"i love you"时,输出 ["i "," you"] 使用时注意去掉参数里的空格
263
+ #触发指令为"you love me"时,输出 ["you "," me"]
264
+ #触发指令为"make love"时,输出 ["make ", None]
265
+ @plugin.handle(r"^(.+)love(.*)")
266
+ async def _(event: Event):
267
+ print(event.args)
268
+ ```
269
+
270
+ ## 关于适配器
271
+
272
+ 创建一个适配器
273
+
274
+ ```python
275
+ adapter = Adapter()
276
+ ```
277
+
278
+ ~~创建好了~~
279
+
280
+ 一个适配器可以有多个适配器方法
281
+
282
+ 适配器的所有方法都需要自己写
283
+
284
+ 如果你想使用 clovers 框架,需要使用你接收到的纯文本消息触发适配器响应
285
+
286
+ 像这样
287
+
288
+ ```python
289
+ #假设你在一个循环里不断轮询收发消息端是否有新消息
290
+ while True:
291
+ command = received_plain_text()
292
+ if command:
293
+ await adapter.response(adapter_key, command, **kwargs)
294
+ ```
295
+
296
+ `adapter_key` 适配器方法指定的 key
297
+ `kwargs` 适配器方法需要的所有参数
298
+
299
+ ### 适配器方法
300
+
301
+ 获取参数,发送信息的方法。里面所有的方法都需要自己写
302
+
303
+ 发送信息,获取参数
304
+
305
+ ```python
306
+ # 假如收发信息框架提供了如下方法
307
+
308
+ # send_plain_text(text:str)发送纯文本
309
+
310
+ method = AdapterMethod()
311
+ @method.send("text")
312
+ async def _(message: str):
313
+ send_plain_text(message)
314
+
315
+ # send_image(image:bytes) 发送图片,但是需要response的参数
316
+
317
+ @method.send("image")
318
+ async def _(message: bytes,send_image):
319
+ send_image(message)
320
+
321
+ # sender发送消息的用户信息,通过response的参数传入
322
+ # 假设有 sender.user_id 属性为该用户uid
323
+ @method.kwarg("user_id")
324
+ async def _(sender):
325
+ return sender.user_id
326
+
327
+ # 注入适配器方法
328
+ adapter.methods["my_adapter_method"] = method
329
+ ```
330
+
331
+ 使用上述适配器
332
+
333
+ 你的 `Result("text", "你好")` 会使用 send_plain_text 发送
334
+
335
+ 你的指令响应任务获取平台参数的 `"user_id"` 就是 sender.user_id
336
+
337
+ ### 使用插件加载器 PluginLoader 向适配器注入插件
338
+
339
+ ```python
340
+ loader = PluginLoader(plugins_path, plugins_list)
341
+ adapter.plugins = loader.plugins
342
+ ```
343
+
344
+ `plugins_list` 插件名列表,例如["plugin1","plugin2"]。从 python lib 路径下的包名加载插件
345
+
346
+ `plugins_path` 插件文件夹,加载改路径下的文件或文件夹作为插件(排除`_`开头的文件)
347
+
348
+ 或者
349
+
350
+ ```python
351
+ plugin = PluginLoader.load("plugin1")
352
+ if not plugin is None:
353
+ adapter.plugins.append(plugin)
354
+ ```
355
+
356
+ ### 开始,结束任务
357
+
358
+ 一些插件会注册一些开始时,结束时运行的任务
359
+
360
+ 所以你需要在开始时,或结束时执行
361
+
362
+ ```python
363
+ asyncio.create_task(adapter.startup)
364
+ asyncio.create_task(adapter.shutdown)
365
+ ```
366
+
367
+ 或类似作用的代码
368
+
369
+ ## 📞 联系
370
+
371
+ 如有建议,bug 反馈等可以加群
372
+
373
+ 机器人 bug 研究中心(闲聊群) 744751179
374
+
375
+ 永恒之城(测试群) 724024810
376
+
377
+ ![群号](https://github.com/KarisAya/clovers/blob/master/%E9%99%84%E4%BB%B6/qrcode_1676538742221.jpg)
378
+
379
+ ## 💡 鸣谢
380
+
381
+ - [nonebot2](https://github.com/nonebot/nonebot2) 跨平台 Python 异步聊天机器人框架 ~~需求都是基于这个写的~~
382
+