Skip to content

Commit afeeae8

Browse files
committed
🐛 fix version 0.59.2
change aliases
1 parent 310c0e8 commit afeeae8

File tree

5 files changed

+75
-9
lines changed

5 files changed

+75
-9
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ reportShadowedImports = false
231231
disableBytesTypePromotions = true
232232

233233
[tool.pdm.scripts]
234-
test = "pytest -v -n 2 -W ignore ./tests/"
234+
test = "pytest -v -W ignore ./tests/"
235235
format = { composite = ["isort ./src/ ./example/ ./tests/","black ./src/ ./example/ ./tests/","ruff check ./src/ ./example/ ./tests/"] }
236236

237237
[tool.pytest.ini_options]

src/nonebot_plugin_alconna/extension.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,14 @@ def __init__(
261261

262262
_callbacks.add(self._callback)
263263

264-
finalize(self, _callbacks.remove, self._callback)
264+
finalize(self, _callbacks.discard, self._callback)
265+
266+
def destroy(self) -> None:
267+
"""销毁当前的扩展执行器,清理相关资源。"""
268+
_callbacks.discard(self._callback)
269+
self.extensions.clear()
270+
self.context.clear()
271+
del self._rule
265272

266273
def _callback(self, *append_global_ext: type[Extension] | Extension):
267274
for _ext in append_global_ext:

src/nonebot_plugin_alconna/matcher.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from nonebot.consts import ARG_KEY, RECEIVE_KEY
2222
from nonebot.internal.params import DefaultParam
2323
from nepattern import ANY, STRING, TPattern, AnyString
24+
from nonebot.internal.matcher.matcher import MatcherMeta
2425
from _weakref import _remove_dead_weakref # type: ignore
2526
from nonebot import require, get_driver, get_plugin_config
2627
from nonebot.plugin.on import store_matcher, get_matcher_source
@@ -106,18 +107,47 @@ def __get__(self, instance, owner):
106107
T1 = TypeVar("T1")
107108

108109

109-
class AlconnaMatcher(Matcher):
110+
class AlconnaMatcherMeta(MatcherMeta):
111+
if TYPE_CHECKING:
112+
_command_path: str
113+
114+
def __repr__(self) -> str:
115+
return (
116+
f"{self.__class__.__name__}(type={self.type!r}"
117+
+ (f", module={self.module_name}" if self.module_name else "")
118+
+ (f", lineno={self._source.lineno}" if self._source and self._source.lineno is not None else "")
119+
+ f", command={self._command_path}"
120+
+ ")"
121+
)
122+
123+
124+
class AlconnaMatcher(Matcher, metaclass=AlconnaMatcherMeta):
110125
# command: ClassVar[weakref.ReferenceType[Alconna]]
111126
basepath: ClassVar[str]
112127
executor: ClassVar[ExtensionExecutor]
113-
_command_path: ClassVar[str]
128+
_command_path: ClassVar[str] = ""
114129
_tests: ClassVar[list[tuple[UniMessage, dict[str, Any] | None, bool]]]
115130
_rule: ClassVar[AlconnaRule]
116131

117132
@classmethod
118133
def command(cls) -> Alconna:
119134
return cls._rule.command() # type: ignore
120135

136+
@classmethod
137+
def clean(cls) -> None:
138+
matchers[cls.priority].remove(cls)
139+
cls._rule.destroy()
140+
cls.executor.destroy()
141+
142+
def __repr__(self) -> str:
143+
return (
144+
f"{self.__class__.__name__}(type={self.type!r}"
145+
+ (f", module={self.module_name}" if self.module_name else "")
146+
+ (f", lineno={self._source.lineno}" if self._source and self._source.lineno is not None else "")
147+
+ f", command={self._command_path}"
148+
+ ")"
149+
)
150+
121151
@classmethod
122152
@overload
123153
def shortcut(cls, key: str | TPattern, args: ShortcutArgs | None = None) -> type[Self]:
@@ -969,8 +999,7 @@ def on_alconna(
969999
command_manager.delete(command)
9701000
return _matcher
9711001
if conflict_resolver == "replace":
972-
_matcher.destroy()
973-
command_manager.delete(exist)
1002+
_matcher.clean()
9741003
command_manager.register(command)
9751004
else:
9761005
exist.formatter.remove(command)
@@ -1033,7 +1062,6 @@ def on_alconna(
10331062
)
10341063
matcher: type[AlconnaMatcher] = cast("type[AlconnaMatcher]", NewMatcher)
10351064
matcher.HANDLER_PARAM_TYPES = params
1036-
log("TRACE", f"Define new matcher {NewMatcher}")
10371065

10381066
matchers[priority].append(NewMatcher)
10391067
store_matcher(matcher)
@@ -1044,6 +1072,8 @@ def on_alconna(
10441072
command.meta.extra["matcher.source"] = matcher._source
10451073
command.meta.extra["matcher.position"] = (priority, len(matchers[priority]) - 1)
10461074

1075+
log("TRACE", f"Define new matcher {NewMatcher}")
1076+
10471077
def remove(wr, selfref=weakref.ref(command.meta), _atomic_removal=_remove_dead_weakref):
10481078
self = selfref()
10491079
if self is not None:

src/nonebot_plugin_alconna/rule.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def _update(cmd_id: int):
144144
self.command = weakref.ref(command, lambda _: _update(_.__hash__()))
145145
if _aliases:
146146
for alias in _aliases:
147-
command.shortcut(alias, prefix=True, compact=False)
147+
command.shortcut(alias, prefix=True, compact=None)
148148
self.skip = skip_for_unmatch
149149
self.executor = ExtensionExecutor(self, extensions, exclude_ext)
150150
self.executor.post_init(command)
@@ -198,6 +198,13 @@ async def _waiter_handle(_event: Event, _matcher: Matcher, content: UniMsg):
198198

199199
self._waiter = _waiter_handle
200200

201+
def destroy(self) -> None:
202+
"""销毁 Alconna 规则,释放资源。"""
203+
self._tasks.clear()
204+
if cmd := self.command():
205+
command_manager.delete(cmd)
206+
self._waiter = None
207+
201208
@property
202209
def rule(self) -> Rule:
203210
return Rule(self)

tests/test_aliases.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
@pytest.mark.asyncio()
1010
async def test_command(app: App):
11-
from nonebot_plugin_alconna import Args, Alconna, on_alconna
11+
from nonebot_plugin_alconna import Args, Alconna, CommandMeta, on_alconna
1212

1313
alc = Alconna("weather", Args["city#城市名称", str])
1414
matcher = on_alconna(alc, aliases={"天气"})
@@ -29,3 +29,25 @@ async def _(city: str):
2929
event2 = fake_group_message_event_v11(message=Message("天气abcd"), user_id=123)
3030
ctx.receive_event(bot, event2)
3131
ctx.should_not_pass_rule()
32+
33+
matcher.clean()
34+
35+
alc = Alconna(
36+
"weather",
37+
Args["city#城市名称", str],
38+
meta=CommandMeta(compact=True),
39+
)
40+
matcher = on_alconna(alc, aliases={"天气"})
41+
42+
@matcher.handle()
43+
async def _(city: str):
44+
await matcher.send(city)
45+
46+
async with app.test_matcher(matcher) as ctx:
47+
adapter = get_adapter(Adapter)
48+
bot = ctx.create_bot(base=Bot, adapter=adapter)
49+
event2 = fake_group_message_event_v11(message=Message("天气abcd"), user_id=123)
50+
ctx.receive_event(bot, event2)
51+
ctx.should_call_send(event2, "abcd")
52+
53+
matcher.clean()

0 commit comments

Comments
 (0)