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.
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tenko-plugin-example
3
- Version: 0.1.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.3,>=0.2
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.2,<0.3`)和插件自己的依赖,
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. 打开 WebUI 的插件页,启用该插件(带“第三方”标记)。第三方插件默认关闭,启用后
72
- 写入 `.tenko/plugins/state.json`。
73
- 3. 如有配置,在 `config/tenko.toml` 里添加 `[plugin_config.<插件 ID>]`,见仓库中
74
- `config/tenko.toml.example` 末尾的说明。
75
- 4. 重启 Tenko(聊天里的 `/重启` 或重新运行进程),插件才会被加载。
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.2,<0.3`)和插件自己的依赖,
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. 打开 WebUI 的插件页,启用该插件(带“第三方”标记)。第三方插件默认关闭,启用后
60
- 写入 `.tenko/plugins/state.json`。
61
- 3. 如有配置,在 `config/tenko.toml` 里添加 `[plugin_config.<插件 ID>]`,见仓库中
62
- `config/tenko.toml.example` 末尾的说明。
63
- 4. 重启 Tenko(聊天里的 `/重启` 或重新运行进程),插件才会被加载。
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.1.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.2,<0.3",
10
+ "tenko-api>=0.3,<0.4",
11
11
  # 插件自己的依赖写在这里:只写下限,不要用 == 锁死,以免与宿主冲突。
12
12
  # Model 基于宿主已有的 SQLAlchemy,声明下限即可。
13
13
  "sqlalchemy>=2.0",
@@ -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
- ctx = context_from_session(session)
77
+ user_id = session.user.id
79
78
  # Store 是同步读写:读改写之间没有 await,协程不会交错,所以不需要加锁。
80
79
  records = visits.load(default={})
81
- record = records.setdefault(ctx.user_id, {"count": 0})
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 == ctx.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=ctx.user_id, text=note.result))
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 Channel, ChannelType, EventType, Guild, Login, MessageObject, User
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, text: str = ""):
69
- """构造 context_from_session 能解析的最小群聊 Session。"""
66
+ def make_session(user_id: str):
67
+ """构造只带发送者的最小 Session,足够直接调用命令处理函数。"""
70
68
 
71
- event = Event(
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))