tenko-plugin-example 0.1.0__tar.gz → 0.2.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.
- {tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/PKG-INFO +13 -8
- {tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/README.md +11 -6
- {tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/pyproject.toml +2 -2
- {tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/src/tenko_plugin_example/__init__.py +4 -5
- {tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/tests/conftest.py +4 -16
- {tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/.github/workflows/publish.yml +0 -0
- {tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/.github/workflows/test.yml +0 -0
- {tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/.gitignore +0 -0
- {tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/tests/test_plugin.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tenko-plugin-example
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Tenko 第三方插件示例与模板
|
|
5
5
|
Project-URL: Homepage, https://github.com/g1331/tenko/tree/main/examples/tenko-plugin-example
|
|
6
6
|
Project-URL: Repository, https://github.com/g1331/tenko
|
|
7
7
|
License-Expression: GPL-3.0-only
|
|
8
8
|
Requires-Python: <3.14,>=3.11
|
|
9
9
|
Requires-Dist: sqlalchemy>=2.0
|
|
10
|
-
Requires-Dist: tenko-api<0.
|
|
10
|
+
Requires-Dist: tenko-api<0.4,>=0.3
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
|
|
13
13
|
# tenko-plugin-example
|
|
@@ -33,7 +33,7 @@ Description-Content-Type: text/markdown
|
|
|
33
33
|
的 `[project.urls]`(插件目录靠这里的 GitHub 地址确认仓库归你所有)。示例本身作为真实
|
|
34
34
|
插件发布在 PyPI 上,这些地方写的是 Tenko 维护者的信息。
|
|
35
35
|
4. **不要声明 `entari.plugin` 入口**:Entari 会无视 Tenko 的启用状态自动加载它。
|
|
36
|
-
5. 依赖只写 `tenko-api` 的兼容范围(预览期为 `>=0.
|
|
36
|
+
5. 依赖只写 `tenko-api` 的兼容范围(预览期为 `>=0.3,<0.4`)和插件自己的依赖,
|
|
37
37
|
不要依赖 `tenko` 本体,也不要用 `==` 锁死依赖版本。
|
|
38
38
|
|
|
39
39
|
## 开发与测试
|
|
@@ -68,11 +68,16 @@ uv run ruff check .
|
|
|
68
68
|
|
|
69
69
|
1. 在运行 Tenko 的环境里安装插件:`uv pip install tenko-plugin-xxx`(本地调试用
|
|
70
70
|
`uv pip install -e /path/to/plugin`)。
|
|
71
|
-
2.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
2. 如有配置,在 `config/tenko.toml` 里添加 `[plugin_config.<插件 ID>]`,见仓库中
|
|
72
|
+
`config/tenko.toml.example` 末尾的说明。运行中的 Tenko 只认启动时读到的配置,改了配置
|
|
73
|
+
要重启。
|
|
74
|
+
3. 打开 WebUI 的插件页,启用该插件(带“第三方”标记)。第三方插件默认关闭,启用后写入
|
|
75
|
+
`.tenko/plugins/state.json` 并直接加载。
|
|
76
|
+
4. 本示例定义了数据库模型,运行中加载会被拒绝,面板会提示重启(聊天里的 `/重启` 或重新
|
|
77
|
+
运行进程)。没有数据库模型的插件不需要这一步。
|
|
78
|
+
|
|
79
|
+
插件可能在 Tenko 运行中被加载,这时启动、就绪等生命周期事件已经过去,初始化不要只放在
|
|
80
|
+
这些事件里。
|
|
76
81
|
|
|
77
82
|
之后可以在 WebUI 开关页或用 `/开启`、`/关闭` 按群控制,插件命令与内置命令走同一套
|
|
78
83
|
维护模式、功能开关和限流。
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
的 `[project.urls]`(插件目录靠这里的 GitHub 地址确认仓库归你所有)。示例本身作为真实
|
|
22
22
|
插件发布在 PyPI 上,这些地方写的是 Tenko 维护者的信息。
|
|
23
23
|
4. **不要声明 `entari.plugin` 入口**:Entari 会无视 Tenko 的启用状态自动加载它。
|
|
24
|
-
5. 依赖只写 `tenko-api` 的兼容范围(预览期为 `>=0.
|
|
24
|
+
5. 依赖只写 `tenko-api` 的兼容范围(预览期为 `>=0.3,<0.4`)和插件自己的依赖,
|
|
25
25
|
不要依赖 `tenko` 本体,也不要用 `==` 锁死依赖版本。
|
|
26
26
|
|
|
27
27
|
## 开发与测试
|
|
@@ -56,11 +56,16 @@ uv run ruff check .
|
|
|
56
56
|
|
|
57
57
|
1. 在运行 Tenko 的环境里安装插件:`uv pip install tenko-plugin-xxx`(本地调试用
|
|
58
58
|
`uv pip install -e /path/to/plugin`)。
|
|
59
|
-
2.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
2. 如有配置,在 `config/tenko.toml` 里添加 `[plugin_config.<插件 ID>]`,见仓库中
|
|
60
|
+
`config/tenko.toml.example` 末尾的说明。运行中的 Tenko 只认启动时读到的配置,改了配置
|
|
61
|
+
要重启。
|
|
62
|
+
3. 打开 WebUI 的插件页,启用该插件(带“第三方”标记)。第三方插件默认关闭,启用后写入
|
|
63
|
+
`.tenko/plugins/state.json` 并直接加载。
|
|
64
|
+
4. 本示例定义了数据库模型,运行中加载会被拒绝,面板会提示重启(聊天里的 `/重启` 或重新
|
|
65
|
+
运行进程)。没有数据库模型的插件不需要这一步。
|
|
66
|
+
|
|
67
|
+
插件可能在 Tenko 运行中被加载,这时启动、就绪等生命周期事件已经过去,初始化不要只放在
|
|
68
|
+
这些事件里。
|
|
64
69
|
|
|
65
70
|
之后可以在 WebUI 开关页或用 `/开启`、`/关闭` 按群控制,插件命令与内置命令走同一套
|
|
66
71
|
维护模式、功能开关和限流。
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tenko-plugin-example"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "Tenko 第三方插件示例与模板"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "GPL-3.0-only"
|
|
7
7
|
requires-python = ">=3.11,<3.14"
|
|
8
8
|
dependencies = [
|
|
9
9
|
# 兼容声明:解析器据此拒绝不兼容的宿主。上限写到下一个次版本(1.0 之后写到主版本)。
|
|
10
|
-
"tenko-api>=0.
|
|
10
|
+
"tenko-api>=0.3,<0.4",
|
|
11
11
|
# 插件自己的依赖写在这里:只写下限,不要用 == 锁死,以免与宿主冲突。
|
|
12
12
|
# Model 基于宿主已有的 SQLAlchemy,声明下限即可。
|
|
13
13
|
"sqlalchemy>=2.0",
|
{tenko_plugin_example-0.1.0 → tenko_plugin_example-0.2.0}/src/tenko_plugin_example/__init__.py
RENAMED
|
@@ -12,7 +12,6 @@ from arclet.alconna import Alconna, Args, CommandMeta
|
|
|
12
12
|
from arclet.entari import BasicConfModel, Session, command, plugin
|
|
13
13
|
from arclet.entari.command import Query
|
|
14
14
|
|
|
15
|
-
from tenko_api.context import context_from_session
|
|
16
15
|
from tenko_api.features import declare
|
|
17
16
|
from tenko_api.perm import Permission, require
|
|
18
17
|
from tenko_api.storage import Model, Store, get_session
|
|
@@ -75,10 +74,10 @@ example_command = Alconna(
|
|
|
75
74
|
@command.on(example_command)
|
|
76
75
|
@require(Permission.User)
|
|
77
76
|
async def example(session: Session, note: Query[str] = Query("note", "")):
|
|
78
|
-
|
|
77
|
+
user_id = session.user.id
|
|
79
78
|
# Store 是同步读写:读改写之间没有 await,协程不会交错,所以不需要加锁。
|
|
80
79
|
records = visits.load(default={})
|
|
81
|
-
record = records.setdefault(
|
|
80
|
+
record = records.setdefault(user_id, {"count": 0})
|
|
82
81
|
record["count"] += 1
|
|
83
82
|
visits.save(records)
|
|
84
83
|
|
|
@@ -86,12 +85,12 @@ async def example(session: Session, note: Query[str] = Query("note", "")):
|
|
|
86
85
|
async with get_session() as db:
|
|
87
86
|
previous = await db.scalar(
|
|
88
87
|
select(Note.text)
|
|
89
|
-
.where(Note.user_id ==
|
|
88
|
+
.where(Note.user_id == user_id)
|
|
90
89
|
.order_by(Note.id.desc())
|
|
91
90
|
.limit(1)
|
|
92
91
|
)
|
|
93
92
|
if note.result:
|
|
94
|
-
db.add(Note(user_id=
|
|
93
|
+
db.add(Note(user_id=user_id, text=note.result))
|
|
95
94
|
await db.commit()
|
|
96
95
|
|
|
97
96
|
reply = f"{config.greeting},这是你第 {record['count']} 次使用示例命令"
|
|
@@ -6,15 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
|
-
from datetime import datetime
|
|
10
9
|
from types import SimpleNamespace
|
|
11
10
|
|
|
12
11
|
import pytest
|
|
13
12
|
import pytest_asyncio
|
|
14
13
|
from arclet.entari import Entari
|
|
15
14
|
from arclet.entari.config import EntariConfig
|
|
16
|
-
from satori import
|
|
17
|
-
from satori.model import Event, Member
|
|
15
|
+
from satori import User
|
|
18
16
|
|
|
19
17
|
from tenko.config import DatabaseConfig
|
|
20
18
|
from tenko.db.bootstrap import load_database_plugin
|
|
@@ -65,17 +63,7 @@ def module(runtime):
|
|
|
65
63
|
return runtime.loaded_plugins["example"].module
|
|
66
64
|
|
|
67
65
|
|
|
68
|
-
def make_session(user_id: str
|
|
69
|
-
"""
|
|
66
|
+
def make_session(user_id: str):
|
|
67
|
+
"""构造只带发送者的最小 Session,足够直接调用命令处理函数。"""
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
type=EventType.MESSAGE_CREATED,
|
|
73
|
-
timestamp=datetime.now(),
|
|
74
|
-
login=Login(platform="onebot", user=User("10001")),
|
|
75
|
-
channel=Channel("40001", ChannelType.TEXT),
|
|
76
|
-
guild=Guild("40001", "Tenko"),
|
|
77
|
-
member=Member(user=User(user_id)),
|
|
78
|
-
user=User(user_id),
|
|
79
|
-
message=MessageObject.from_elements("50001", []),
|
|
80
|
-
)
|
|
81
|
-
return SimpleNamespace(event=SimpleNamespace(_origin=event))
|
|
69
|
+
return SimpleNamespace(user=User(user_id))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|