⬆️ auto update by pre-commit hooks (#4181)
Release Drafter / release (push) Skipped
Release Drafter / update-release-draft (push) Failing after 38s
Code Coverage / Test Coverage (pydantic-v1, ubuntu-latest, 3.10) (push) Failing after 43s
Ruff Lint / Ruff Lint (push) Successful in 57s
Pyright Lint / Pyright Lint (pydantic-v1) (push) Failing after 1m1s
Pyright Lint / Pyright Lint (pydantic-v2) (push) Failing after 1m4s
Code Coverage / Test Coverage (pydantic-v1, ubuntu-latest, 3.13) (push) Failing after 1m4s
Code Coverage / Test Coverage (pydantic-v2, ubuntu-latest, 3.11) (push) Failing after 1m5s
Site Deploy / publish (push) Failing after 1m8s
Code Coverage / Test Coverage (pydantic-v2, ubuntu-latest, 3.13) (push) Failing after 1m19s
Code Coverage / Test Coverage (pydantic-v1, ubuntu-latest, 3.11) (push) Failing after 1m26s
Code Coverage / Test Coverage (pydantic-v2, ubuntu-latest, 3.10) (push) Failing after 1m29s
Code Coverage / Test Coverage (pydantic-v2, ubuntu-latest, 3.12) (push) Failing after 1m31s
Code Coverage / Test Coverage (pydantic-v1, ubuntu-latest, 3.12) (push) Failing after 1m33s
Code Coverage / Test Coverage (pydantic-v1, macos-latest, 3.10) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v1, macos-latest, 3.11) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v1, macos-latest, 3.12) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v1, macos-latest, 3.13) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v1, windows-latest, 3.10) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v1, windows-latest, 3.11) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v1, windows-latest, 3.12) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v1, windows-latest, 3.13) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v2, macos-latest, 3.10) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v2, macos-latest, 3.11) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v2, macos-latest, 3.12) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v2, macos-latest, 3.13) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v2, windows-latest, 3.10) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v2, windows-latest, 3.11) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v2, windows-latest, 3.12) (push) Canceled after 0s
Code Coverage / Test Coverage (pydantic-v2, windows-latest, 3.13) (push) Canceled after 0s

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
pre-commit-ci[bot]
2026-09-11 22:03:57 +08:00
committed by GitHub
co-authored by pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
parent 9b4772ff8f
commit 206d31a61d
86 changed files with 819 additions and 271 deletions
@@ -45,14 +45,11 @@ message = UniMessage(
```python
from nonebot_plugin_alconna import Button, UniMessage
message = (
UniMessage.text("hello world")
.keyboard(
Button("link1", url="https://example.com/1"),
Button("link2", url="https://example.com/2"),
Button("link3", url="https://example.com/3"),
row=3,
)
message = UniMessage.text("hello world").keyboard(
Button("link1", url="https://example.com/1"),
Button("link2", url="https://example.com/2"),
Button("link3", url="https://example.com/3"),
row=3,
)
```
@@ -94,6 +91,7 @@ async def _():
```python
from nonebot_plugin_alconna import message_recall, message_edit, message_reaction
@matcher.handle()
async def _():
await message_edit(UniMessage.text("hello world"))
@@ -120,9 +118,9 @@ async def _():
```python
from nonebot_plugin_alconna import UniMsg
@matcher.handle()
async def _(msg: UniMsg):
...
async def _(msg: UniMsg): ...
```
然后你可以通过 `UniMessage` 的方法来处理消息.
@@ -182,6 +180,7 @@ async def _(msg: UniMsg):
```python
from nonebot_plugin_alconna import UniMsg
@matcher.handle()
async def _(msg: UniMsg):
data: list[dict] = msg.dump()
@@ -193,6 +192,7 @@ async def _(msg: UniMsg):
```python
from nonebot_plugin_alconna import UniMessage
@matcher.handle()
async def _():
data = [
@@ -12,9 +12,9 @@ from nonebot_plugin_alconna import Alconna, Args, Image, on_alconna
meme = on_alconna(Alconna("make_meme", Args["name", str]["img", Image]))
@meme.handle()
async def _(img: Image):
...
async def _(img: Image): ...
```
## 模型定义
@@ -24,6 +24,7 @@ async def _(img: Image):
```python
class Segment:
"""基类标注"""
@property
def type(self) -> str: ...
@property
@@ -31,29 +32,40 @@ class Segment:
@property
def children(self) -> list["Segment"]: ...
class Text(Segment):
"""Text对象, 表示一类文本元素"""
text: str
styles: dict[tuple[int, int], list[str]]
def cover(self, text: str): ...
def mark(self, start: Optional[int] = None, end: Optional[int] = None, *styles: str): ...
def mark(
self, start: Optional[int] = None, end: Optional[int] = None, *styles: str
): ...
class At(Segment):
"""At对象, 表示一类提醒某用户的元素"""
flag: Literal["user", "role", "channel"]
target: str
display: Optional[str]
class AtAll(Segment):
"""AtAll对象, 表示一类提醒所有人的元素"""
here: bool
class Emoji(Segment):
"""Emoji对象, 表示一类表情元素"""
id: str
name: Optional[str]
class Media(Segment):
id: Optional[str]
url: Optional[str]
@@ -64,53 +76,72 @@ class Media(Segment):
to_url: ClassVar[Optional[MediaToUrl]]
class Image(Media):
"""Image对象, 表示一类图片元素"""
width: Optional[int]
height: Optional[int]
class Audio(Media):
"""Audio对象, 表示一类音频元素"""
duration: Optional[float]
class Voice(Media):
"""Voice对象, 表示一类语音元素"""
duration: Optional[float]
class Video(Media):
"""Video对象, 表示一类视频元素"""
thumbnail: Optional[Image]
duration: Optional[float]
class File(Media):
"""File对象, 表示一类文件元素"""
class Reply(Segment):
"""Reply对象,表示一类回复消息"""
id: str
"""此处不一定是消息ID,可能是其他ID,如消息序号等"""
msg: Optional[Union[Message, str]]
origin: Optional[Any]
class Reference(Segment):
"""Reference对象,表示一类引用消息。转发消息 (Forward) 也属于此类"""
id: Optional[str]
"""此处不一定是消息ID,可能是其他ID,如消息序号等"""
children: List[Union[RefNode, CustomNode]]
class Hyper(Segment):
"""Hyper对象,表示一类超级消息。如卡片消息、ark消息、小程序等"""
format: Literal["xml", "json"]
raw: Optional[str]
content: Optional[Union[dict, list]]
class Reference(Segment):
"""Reference对象,表示一类引用消息。转发消息 (Forward) 也属于此类"""
id: Optional[str]
nodes: Sequence[Union[RefNode, CustomNode]]
class Button(Segment):
"""Button对象,表示一类按钮消息"""
flag: Literal["action", "link", "input", "enter"]
"""
- 点击 action 类型的按钮时会触发一个关于 按钮回调 事件,该事件的 button 资源会包含上述 id
@@ -138,20 +169,26 @@ class Button(Segment):
- list[At]: 指定用户/身份组可操作
"""
class Keyboard(Segment):
"""Keyboard对象,表示一行按钮元素"""
id: Optional[str]
"""此处一般用来表示模板id,特殊情况下可能表示例如 bot_appid 等"""
buttons: Optional[list[Button]]
row: Optional[int]
"""当消息中只写有一个 Keyboard 时可根据此参数约定按钮组的列数"""
class Other(Segment):
"""其他 Segment"""
origin: MessageSegment
class I18n(Segment):
"""特殊的 Segment,用于 i18n 消息"""
item_or_scope: Union[LangItem, str]
type_: Optional[str] = None
@@ -172,10 +209,14 @@ from nonebot_plugin_alconna import Args, Image, Alconna, select
from nonebot_plugin_alconna.builtins.uniseg.market_face import MarketFace
# 表示这个指令需要的图片会在目标元素下进行搜索,将所有符合 Image 的元素选出来并将第一个作为结果
alc1 = Alconna("make_meme", Args["name", str]["img", select(Image).first]) # 也可以使用 select(Image).nth(0)
alc1 = Alconna(
"make_meme", Args["name", str]["img", select(Image).first]
) # 也可以使用 select(Image).nth(0)
# 表示这个指令需要的图片要么直接是 Image 要么是在 MarketFace 元素内的 Image
alc2 = Alconna("make_meme", Args["name", str]["img", [Image, select(Image).from_(MarketFace)]])
alc2 = Alconna(
"make_meme", Args["name", str]["img", [Image, select(Image).from_(MarketFace)]]
)
```
也可以参考通用消息的 [`嵌套提取`](./message.mdx#嵌套提取)
@@ -213,10 +254,13 @@ def mfbuild(builder: MessageBuilder, seg: BaseMessageSegment):
@custom_handler(MarketFace)
async def mfexport(exporter: MessageExporter, seg: MarketFace, bot: Bot, fallback: bool):
async def mfexport(
exporter: MessageExporter, seg: MarketFace, bot: Bot, fallback: bool
):
if exporter.get_message_type() is Message:
return MessageSegment("chronocat:marketface", seg.data)(await exporter.export(seg.children, bot, fallback))
return MessageSegment("chronocat:marketface", seg.data)(
await exporter.export(seg.children, bot, fallback)
)
```
具体而言,你可以使用 `custom_register` 来增加一个从 MessageSegment 到 Segment 的处理方法;使用 `custom_handler` 来增加一个从 Segment 到 MessageSegment 的处理方法。