Skip to content
This repository has been archived by the owner on Jul 21, 2023. It is now read-only.

Commit

Permalink
✨ version 0.9.0
Browse files Browse the repository at this point in the history
add `funcommand`
  • Loading branch information
RF-Tar-Railt committed Jul 3, 2023
1 parent f640006 commit 8aee048
Show file tree
Hide file tree
Showing 14 changed files with 135 additions and 41 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,17 @@ def on_alconna(
| [BiliBili Live](https://github.com/wwweww/adapter-bilibili) | adapters.bilibili |


### 便捷装饰器

`funcommand` 装饰器用于将一个接受任意参数,返回 `str``Message``MessageSegment` 的函数转换为命令响应器。

```python
from nonebot_plugin_alconna import funcommand

@funcommand()
async def echo(msg: str):
return msg
```

## 体验

Expand Down
13 changes: 13 additions & 0 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,19 @@ async def install(arp: CommandResult = AlconnaResult()):
...
```

### 便捷装饰器

本插件提供了一个 `funcommand` 装饰器, 其用于将一个接受任意参数,
返回 `str``Message``MessageSegment` 的函数转换为命令响应器。

```python
from nonebot_plugin_alconna import funcommand

@funcommand()
async def echo(msg: str):
return msg
```

## MessageSegment 标注

本插件提供了一系列便捷的 `MessageSegment` 标注,可用于匹配消息中除 text 外的其他 `MessageSegment`,也可用于快速创建 `MessageSegment`
Expand Down
42 changes: 28 additions & 14 deletions pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[project]
name = "nonebot-plugin-alconna"
version = "0.8.4"
version = "0.9.0"
description = "Alconna Adapter for Nonebot"
authors = [
{name = "RF-Tar-Railt", email = "rf_tar_railt@qq.com"},
]
dependencies = [
"nonebot2>=2.0.0rc4",
"arclet-alconna<2.0.0, >=1.7.7",
"arclet-alconna-tools<0.7.0, >=0.6.1",
"arclet-alconna<2.0.0, >=1.7.10",
"arclet-alconna-tools<0.7.0, >=0.6.3",
]
requires-python = ">=3.8"
readme = "README.md"
Expand All @@ -30,7 +30,7 @@ build-backend = "pdm.pep517.api"
[tool.pdm]
[tool.pdm.dev-dependencies]
dev = [
"nonebot2>=2.0.0",
"nonebot2[fastapi,httpx,websockets]>=2.0.0",
"fix-future-annotations>=0.5.0",
"nonebot-adapter-onebot>=2.2.3",
"nonebot-adapter-feishu>=2.0.0b8",
Expand Down
3 changes: 2 additions & 1 deletion src/nonebot_plugin_alconna/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .argv import MessageArgv as MessageArgv
from .consts import ALCONNA_RESULT as ALCONNA_RESULT
from .matcher import on_alconna as on_alconna
from .matcher import funcommand as funcommand
from .model import CommandResult as CommandResult
from .model import Match as Match
from .model import Query as Query
Expand All @@ -22,7 +23,7 @@
from .rule import set_output_converter as set_output_converter
from .config import Config

__version__ = "0.8.4"
__version__ = "0.9.0"

_meta_source = {
"name": "Alconna 插件",
Expand Down
43 changes: 43 additions & 0 deletions src/nonebot_plugin_alconna/matcher.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from __future__ import annotations

from typing import Callable

from arclet.alconna import Alconna, command_manager
from arclet.alconna.tools import AlconnaFormat
from arclet.alconna.tools.construct import FuncMounter
from tarina import is_awaitable
from nonebot.matcher import Matcher
from nonebot.plugin.on import on_message
from nonebot.rule import Rule
from nonebot.typing import T_RuleChecker
from nonebot.internal.adapter import Bot, Event, Message, MessageSegment

from .model import CompConfig
from .rule import alconna
Expand Down Expand Up @@ -62,3 +67,41 @@ def on_alconna(
**kwargs,
_depth=_depth + 1 # type: ignore
)


def funcommand(
name: str | None = None,
prefixes: list[str] | None = None,
description: str | None = None,
):
_config = {"raise_exception": False}
if name:
_config["name"] = name
if prefixes:
_config["prefixes"] = prefixes
if description:
_config["description"] = description
def wrapper(func: Callable) -> type[Matcher]:
alc = FuncMounter(func, _config) # type: ignore

async def handle(bot: Bot, event: Event):
msg = getattr(event, "original_message", event.get_message())
try:
arp, res = alc.exec(msg)
except Exception as e:
if _config["raise_exception"]:
raise e
await bot.send(event, str(e))
return
if arp.matched:
if is_awaitable(res):
res = await res
if isinstance(res, (str, Message, MessageSegment)):
await bot.send(event, res)

matcher = on_alconna(alc)
matcher.handle()(handle)

return matcher

return wrapper
11 changes: 10 additions & 1 deletion src/nonebot_plugin_alconna/matcher.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from datetime import datetime, timedelta
from typing import Callable

from arclet.alconna import Alconna
from nonebot.dependencies import Dependent
Expand All @@ -9,7 +10,7 @@ from nonebot.permission import Permission
from nonebot.rule import Rule
from nonebot.typing import T_Handler, T_PermissionChecker, T_RuleChecker, T_State
from nonebot_plugin_alconna.model import CompConfig
from nonebot_plugin_alconna.typings import TConvert
from nonebot_plugin_alconna.typings import TConvert, MReturn

def on_alconna(
command: Alconna | str,
Expand All @@ -28,3 +29,11 @@ def on_alconna(
block: bool = ...,
state: T_State | None = ...,
) -> type[Matcher]: ...


def funcommand(
name: str | None = None,
prefixes: list[str] | None = None,
description: str | None = None,
) -> Callable[[Callable[..., MReturn]], type[Matcher]]:
...
3 changes: 2 additions & 1 deletion src/nonebot_plugin_alconna/typings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

T = TypeVar("T")
TMS = TypeVar("TMS", bound=MessageSegment)
TCallable = TypeVar("TCallable", bound=Callable[..., Any])
P = ParamSpec("P")


Expand Down Expand Up @@ -47,7 +48,7 @@ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> TMS:

OutputType = Literal["help", "shortcut", "completion"]
TConvert: TypeAlias = Callable[[OutputType, str], Union[Message, Awaitable[Message]]]

MReturn: TypeAlias = Union[Union[str, Message, MessageSegment], Awaitable[Union[str, Message, MessageSegment]]]

def _isinstance(seg: MessageSegment, mapping: dict[str, Callable[[MessageSegment], Any]]):
if (key := seg.type) in mapping and (res := mapping[key](seg)):
Expand Down
4 changes: 0 additions & 4 deletions src/test/.env

This file was deleted.

1 change: 0 additions & 1 deletion src/test/.env.dev

This file was deleted.

5 changes: 5 additions & 0 deletions src/test/.env.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DRIVER=~fastapi+~httpx+~websockets
HOST=127.0.0.1
PORT=9555
ALCONNA_AUTO_SEND_OUTPUT=true
ALCONNA_USE_COMMAND_START=false
4 changes: 2 additions & 2 deletions src/test/bot.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import nonebot
from nonebot.adapters.console import Adapter as ConsoleAdapter
from nonebot.adapters.onebot.v12 import Adapter as ONEBOT_V12Adapter
nonebot.init()

driver = nonebot.get_driver()
driver.register_adapter(ConsoleAdapter)
driver.register_adapter(ONEBOT_V12Adapter)

# nonebot.require("nonebot_plugin_alconna")
nonebot.load_plugin("plugins.demo")
Expand Down
23 changes: 13 additions & 10 deletions src/test/plugins/demo.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
# 应与使用的 adapter 对应
# 不加也可以,做了兼容
import nonebot_plugin_alconna.adapters.console # noqa
from arclet.alconna import Alconna, Args, Arparma, Option, Subcommand, command_manager, namespace, Duplication, SubcommandStub, Empty
from arclet.alconna.tools import MarkdownTextFormatter
import nonebot_plugin_alconna.adapters.onebot12 # noqa: F401
from arclet.alconna import Alconna, Args, Arparma, Option, Subcommand, command_manager, namespace, Duplication, SubcommandStub
from importlib_metadata import distributions
from nonebot.adapters.console.message import Message, MessageSegment
from nonebot.adapters.onebot.v12.message import Message, MessageSegment
from nonebot_plugin_alconna import (
AlconnaMatches, on_alconna, set_output_converter, AlconnaDuplication,
Check, assign
Check, assign, funcommand
)
from tarina import lang

set_output_converter(lambda t, x: Message([MessageSegment.markdown(x)]))
set_output_converter(lambda t, x: Message([MessageSegment.text(x)]))

with namespace("nbtest") as ns:
ns.headers = ["/"]
ns.formatter_type = MarkdownTextFormatter
ns.builtin_option_name["help"] = {"-h", "帮助", "--help"}

help_cmd = on_alconna(Alconna("help"))
Expand All @@ -33,7 +31,7 @@

# auto_send already set in .env
pipcmd = on_alconna(pip, comp_config={'timeout': 10}, block=True) # , auto_send_output=True)
ali = on_alconna(Alconna(["/"], "一言"), aliases={"hitokoto"}, skip_for_unmatch=False)
ali = on_alconna(Alconna(["/"], "一言"), aliases={"hitokoto"}, skip_for_unmatch=True)
i18n = on_alconna(Alconna("lang", Args["lang", ["zh_CN", "en_US"]]))

class PipResult(Duplication):
Expand All @@ -55,7 +53,7 @@ def get_dist_map() -> dict:

@help_cmd.handle()
async def _help(arp: Arparma = AlconnaMatches()):
await help_cmd.send(MessageSegment.markdown(command_manager.all_command_help()))
await help_cmd.send(MessageSegment.text(command_manager.all_command_help()))


@i18n.handle()
Expand All @@ -70,7 +68,7 @@ async def _i18n(arp: Arparma = AlconnaMatches()):
@pipcmd.handle([Check(assign("list"))])
async def ll():
md = "\n".join([f"- {k} {v}" for k, v in get_dist_map().items()])
await pipcmd.send(MessageSegment.markdown(md))
await pipcmd.send(MessageSegment.text(md))


@pipcmd.handle([Check(assign("install.pak"))])
Expand All @@ -89,3 +87,8 @@ async def yiyan(res: Arparma = AlconnaMatches()):
await ali.send("WIP...")
# else:
# await ali.send(f"[hitokoto] Unmatched: {res}")

@funcommand()
def add(a: float, b: float):
"""加法测试"""
return f"{a} + {b} = {a + b}"
6 changes: 3 additions & 3 deletions src/test/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ requires-python = ">=3.8, <4.0"

[tool.nonebot]
adapters = [
{ name = "Console", module_name = "nonebot.adapters.console" },
{ name = "OneBot V12", module_name = "nonebot.adapters.onebot.v12" }
]
plugins = []
plugin_dirs = ["src/plugins"]
plugins = ["nonebot_plugin_alconna"]
plugin_dirs = []
builtin_plugins = []

0 comments on commit 8aee048

Please sign in to comment.