mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-02-17 16:20:05 +08:00
add permission and command
This commit is contained in:
parent
865fd6af4c
commit
6435e29e8b
@ -4,10 +4,6 @@
|
|||||||
import logging
|
import logging
|
||||||
import importlib
|
import importlib
|
||||||
from ipaddress import IPv4Address
|
from ipaddress import IPv4Address
|
||||||
|
|
||||||
from nonebot.log import logger
|
|
||||||
from nonebot.config import Env, Config
|
|
||||||
from nonebot.adapters.cqhttp import Bot as CQBot
|
|
||||||
from nonebot.typing import Type, Union, Driver, Optional, NoReturn
|
from nonebot.typing import Type, Union, Driver, Optional, NoReturn
|
||||||
|
|
||||||
_driver: Optional[Driver] = None
|
_driver: Optional[Driver] = None
|
||||||
@ -34,6 +30,10 @@ def get_bots():
|
|||||||
return driver.bots
|
return driver.bots
|
||||||
|
|
||||||
|
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.config import Env, Config
|
||||||
|
from nonebot.adapters.cqhttp import Bot as CQBot
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import nonebot_test
|
import nonebot_test
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -83,6 +83,16 @@ class BaseEvent(abc.ABC):
|
|||||||
def sub_type(self, value) -> None:
|
def sub_type(self, value) -> None:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def user_id(self) -> Optional[int]:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@user_id.setter
|
||||||
|
@abc.abstractmethod
|
||||||
|
def user_id(self, value) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def message(self) -> Optional[Message]:
|
def message(self) -> Optional[Message]:
|
||||||
@ -103,6 +113,21 @@ class BaseEvent(abc.ABC):
|
|||||||
def raw_message(self, value) -> None:
|
def raw_message(self, value) -> None:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def plain_text(self) -> Optional[str]:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def sender(self) -> Optional[dict]:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@sender.setter
|
||||||
|
@abc.abstractmethod
|
||||||
|
def sender(self, value) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class BaseMessageSegment(abc.ABC):
|
class BaseMessageSegment(abc.ABC):
|
||||||
|
@ -142,7 +142,10 @@ class Bot(BaseBot):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(headers=headers) as client:
|
async with httpx.AsyncClient(headers=headers) as client:
|
||||||
response = await client.post(api_root + api, json=data)
|
response = await client.post(
|
||||||
|
api_root + api,
|
||||||
|
json=data,
|
||||||
|
timeout=self.config.api_timeout)
|
||||||
|
|
||||||
if 200 <= response.status_code < 300:
|
if 200 <= response.status_code < 300:
|
||||||
result = response.json()
|
result = response.json()
|
||||||
@ -193,6 +196,16 @@ class Event(BaseEvent):
|
|||||||
def sub_type(self, value) -> None:
|
def sub_type(self, value) -> None:
|
||||||
self._raw_event["sub_type"] = value
|
self._raw_event["sub_type"] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
@overrides(BaseEvent)
|
||||||
|
def user_id(self) -> Optional[int]:
|
||||||
|
return self._raw_event.get("user_id")
|
||||||
|
|
||||||
|
@user_id.setter
|
||||||
|
@overrides(BaseEvent)
|
||||||
|
def user_id(self, value) -> None:
|
||||||
|
self._raw_event["user_id"] = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@overrides(BaseEvent)
|
@overrides(BaseEvent)
|
||||||
def message(self) -> Optional["Message"]:
|
def message(self) -> Optional["Message"]:
|
||||||
@ -213,6 +226,21 @@ class Event(BaseEvent):
|
|||||||
def raw_message(self, value) -> None:
|
def raw_message(self, value) -> None:
|
||||||
self._raw_event["raw_message"] = value
|
self._raw_event["raw_message"] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
@overrides(BaseEvent)
|
||||||
|
def plain_text(self) -> Optional[str]:
|
||||||
|
return self.message and self.message.extract_plain_text()
|
||||||
|
|
||||||
|
@property
|
||||||
|
@overrides(BaseEvent)
|
||||||
|
def sender(self) -> Optional[dict]:
|
||||||
|
return self._raw_event.get("sender")
|
||||||
|
|
||||||
|
@sender.setter
|
||||||
|
@overrides(BaseEvent)
|
||||||
|
def sender(self, value) -> None:
|
||||||
|
self._raw_event["sender"] = value
|
||||||
|
|
||||||
|
|
||||||
class MessageSegment(BaseMessageSegment):
|
class MessageSegment(BaseMessageSegment):
|
||||||
|
|
||||||
|
@ -103,12 +103,14 @@ class Config(BaseConfig):
|
|||||||
|
|
||||||
# bot connection configs
|
# bot connection configs
|
||||||
api_root: Dict[str, str] = {}
|
api_root: Dict[str, str] = {}
|
||||||
api_timeout: float = 60.
|
api_timeout: Optional[float] = 60.
|
||||||
access_token: Optional[str] = None
|
access_token: Optional[str] = None
|
||||||
|
|
||||||
# bot runtime configs
|
# bot runtime configs
|
||||||
superusers: Set[int] = set()
|
superusers: Set[int] = set()
|
||||||
nickname: Union[str, Set[str]] = ""
|
nickname: Union[str, Set[str]] = ""
|
||||||
|
command_start: Set[str] = {"/"}
|
||||||
|
command_sep: Set[str] = {"."}
|
||||||
session_expire_timeout: timedelta = timedelta(minutes=2)
|
session_expire_timeout: timedelta = timedelta(minutes=2)
|
||||||
|
|
||||||
# custom configs
|
# custom configs
|
||||||
|
@ -6,8 +6,9 @@ from functools import wraps
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from nonebot.rule import SyncRule, user
|
from nonebot.rule import Rule
|
||||||
from nonebot.typing import Bot, Rule, Event, Handler
|
from nonebot.permission import Permission, EVERYBODY, USER
|
||||||
|
from nonebot.typing import Bot, Event, Handler
|
||||||
from nonebot.typing import Type, List, Dict, Optional, NoReturn
|
from nonebot.typing import Type, List, Dict, Optional, NoReturn
|
||||||
from nonebot.exception import PausedException, RejectedException, FinishedException
|
from nonebot.exception import PausedException, RejectedException, FinishedException
|
||||||
|
|
||||||
@ -18,7 +19,8 @@ class Matcher:
|
|||||||
"""`Matcher`类
|
"""`Matcher`类
|
||||||
"""
|
"""
|
||||||
|
|
||||||
rule: Rule = SyncRule()
|
rule: Rule = Rule()
|
||||||
|
permission: Permission = Permission()
|
||||||
handlers: List[Handler] = []
|
handlers: List[Handler] = []
|
||||||
temp: bool = False
|
temp: bool = False
|
||||||
expire_time: Optional[datetime] = None
|
expire_time: Optional[datetime] = None
|
||||||
@ -38,7 +40,8 @@ class Matcher:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new(cls,
|
def new(cls,
|
||||||
rule: Rule = SyncRule(),
|
rule: Rule = Rule(),
|
||||||
|
permission: Permission = Permission(),
|
||||||
handlers: list = [],
|
handlers: list = [],
|
||||||
temp: bool = False,
|
temp: bool = False,
|
||||||
priority: int = 1,
|
priority: int = 1,
|
||||||
@ -54,6 +57,7 @@ class Matcher:
|
|||||||
NewMatcher = type(
|
NewMatcher = type(
|
||||||
"Matcher", (Matcher,), {
|
"Matcher", (Matcher,), {
|
||||||
"rule": rule,
|
"rule": rule,
|
||||||
|
"permission": permission,
|
||||||
"handlers": handlers,
|
"handlers": handlers,
|
||||||
"temp": temp,
|
"temp": temp,
|
||||||
"expire_time": expire_time,
|
"expire_time": expire_time,
|
||||||
@ -66,7 +70,11 @@ class Matcher:
|
|||||||
return NewMatcher
|
return NewMatcher
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def check_rule(cls, bot: Bot, event: Event) -> bool:
|
async def check_perm(cls, bot: Bot, event: Event) -> bool:
|
||||||
|
return await cls.permission(bot, event)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def check_rule(cls, bot: Bot, event: Event, state: dict) -> bool:
|
||||||
"""检查 Matcher 的 Rule 是否成立
|
"""检查 Matcher 的 Rule 是否成立
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -75,7 +83,7 @@ class Matcher:
|
|||||||
Returns:
|
Returns:
|
||||||
bool: 条件成立与否
|
bool: 条件成立与否
|
||||||
"""
|
"""
|
||||||
return await cls.rule(bot, event)
|
return await cls.rule(bot, event, state)
|
||||||
|
|
||||||
# @classmethod
|
# @classmethod
|
||||||
# def args_parser(cls, func: Callable[[Event, dict], None]):
|
# def args_parser(cls, func: Callable[[Event, dict], None]):
|
||||||
@ -144,11 +152,14 @@ class Matcher:
|
|||||||
# raise RejectedException
|
# raise RejectedException
|
||||||
|
|
||||||
# 运行handlers
|
# 运行handlers
|
||||||
async def run(self, bot: Bot, event: Event):
|
async def run(self, bot: Bot, event: Event, state):
|
||||||
try:
|
try:
|
||||||
# if self.parser:
|
# if self.parser:
|
||||||
# await self.parser(event, state) # type: ignore
|
# await self.parser(event, state) # type: ignore
|
||||||
|
|
||||||
|
# Refresh preprocess state
|
||||||
|
self.state.update(state)
|
||||||
|
|
||||||
for _ in range(len(self.handlers)):
|
for _ in range(len(self.handlers)):
|
||||||
handler = self.handlers.pop(0)
|
handler = self.handlers.pop(0)
|
||||||
annotation = typing.get_type_hints(handler)
|
annotation = typing.get_type_hints(handler)
|
||||||
@ -158,23 +169,25 @@ class Matcher:
|
|||||||
await handler(bot, event, self.state)
|
await handler(bot, event, self.state)
|
||||||
except RejectedException:
|
except RejectedException:
|
||||||
self.handlers.insert(0, handler) # type: ignore
|
self.handlers.insert(0, handler) # type: ignore
|
||||||
matcher = Matcher.new(user(event.user_id) & self.rule,
|
matcher = Matcher.new(
|
||||||
self.handlers,
|
self.rule,
|
||||||
temp=True,
|
USER(event.user_id, perm=self.permission), # type:ignore
|
||||||
priority=0,
|
self.handlers,
|
||||||
default_state=self.state,
|
temp=True,
|
||||||
expire_time=datetime.now() +
|
priority=0,
|
||||||
bot.config.session_expire_timeout)
|
default_state=self.state,
|
||||||
|
expire_time=datetime.now() + bot.config.session_expire_timeout)
|
||||||
matchers[0].append(matcher)
|
matchers[0].append(matcher)
|
||||||
return
|
return
|
||||||
except PausedException:
|
except PausedException:
|
||||||
matcher = Matcher.new(user(event.user_id) & self.rule,
|
matcher = Matcher.new(
|
||||||
self.handlers,
|
self.rule,
|
||||||
temp=True,
|
USER(event.user_id, perm=self.permission), # type:ignore
|
||||||
priority=0,
|
self.handlers,
|
||||||
default_state=self.state,
|
temp=True,
|
||||||
expire_time=datetime.now() +
|
priority=0,
|
||||||
bot.config.session_expire_timeout)
|
default_state=self.state,
|
||||||
|
expire_time=datetime.now() + bot.config.session_expire_timeout)
|
||||||
matchers[0].append(matcher)
|
matchers[0].append(matcher)
|
||||||
return
|
return
|
||||||
except FinishedException:
|
except FinishedException:
|
||||||
|
@ -5,6 +5,7 @@ import asyncio
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
|
from nonebot.rule import TrieRule
|
||||||
from nonebot.matcher import matchers
|
from nonebot.matcher import matchers
|
||||||
from nonebot.exception import IgnoredException
|
from nonebot.exception import IgnoredException
|
||||||
from nonebot.typing import Bot, Set, Event, PreProcessor
|
from nonebot.typing import Bot, Set, Event, PreProcessor
|
||||||
@ -19,8 +20,9 @@ def event_preprocessor(func: PreProcessor) -> PreProcessor:
|
|||||||
|
|
||||||
async def handle_event(bot: Bot, event: Event):
|
async def handle_event(bot: Bot, event: Event):
|
||||||
coros = []
|
coros = []
|
||||||
|
state = {}
|
||||||
for preprocessor in _event_preprocessors:
|
for preprocessor in _event_preprocessors:
|
||||||
coros.append(preprocessor(bot, event))
|
coros.append(preprocessor(bot, event, state))
|
||||||
if coros:
|
if coros:
|
||||||
try:
|
try:
|
||||||
await asyncio.gather(*coros)
|
await asyncio.gather(*coros)
|
||||||
@ -28,6 +30,9 @@ async def handle_event(bot: Bot, event: Event):
|
|||||||
logger.info(f"Event {event} is ignored")
|
logger.info(f"Event {event} is ignored")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Trie Match
|
||||||
|
_, _ = TrieRule.get_value(bot, event, state)
|
||||||
|
|
||||||
for priority in sorted(matchers.keys()):
|
for priority in sorted(matchers.keys()):
|
||||||
index = 0
|
index = 0
|
||||||
while index <= len(matchers[priority]):
|
while index <= len(matchers[priority]):
|
||||||
@ -40,7 +45,9 @@ async def handle_event(bot: Bot, event: Event):
|
|||||||
|
|
||||||
# Check rule
|
# Check rule
|
||||||
try:
|
try:
|
||||||
if not await Matcher.check_rule(bot, event):
|
if not await Matcher.check_perm(
|
||||||
|
bot, event) or not await Matcher.check_rule(
|
||||||
|
bot, event, state):
|
||||||
index += 1
|
index += 1
|
||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -55,7 +62,7 @@ async def handle_event(bot: Bot, event: Event):
|
|||||||
del matchers[priority][index]
|
del matchers[priority][index]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await matcher.run(bot, event)
|
await matcher.run(bot, event, state)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Running matcher {matcher} failed.")
|
logger.error(f"Running matcher {matcher} failed.")
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
124
nonebot/permission.py
Normal file
124
nonebot/permission.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from nonebot.utils import run_sync
|
||||||
|
from nonebot.typing import Bot, Event, Union, NoReturn, PermissionChecker
|
||||||
|
|
||||||
|
|
||||||
|
class Permission:
|
||||||
|
__slots__ = ("checkers",)
|
||||||
|
|
||||||
|
def __init__(self, *checkers: PermissionChecker) -> None:
|
||||||
|
self.checkers = list(checkers)
|
||||||
|
|
||||||
|
async def __call__(self, bot: Bot, event: Event) -> bool:
|
||||||
|
if not self.checkers:
|
||||||
|
return True
|
||||||
|
results = await asyncio.gather(
|
||||||
|
*map(lambda c: c(bot, event), self.checkers))
|
||||||
|
return any(results)
|
||||||
|
|
||||||
|
def __and__(self, other) -> NoReturn:
|
||||||
|
raise RuntimeError("And operation between Permissions is not allowed.")
|
||||||
|
|
||||||
|
def __or__(self, other: Union["Permission",
|
||||||
|
PermissionChecker]) -> "Permission":
|
||||||
|
checkers = [*self.checkers]
|
||||||
|
if isinstance(other, Permission):
|
||||||
|
checkers.extend(other.checkers)
|
||||||
|
elif asyncio.iscoroutinefunction(other):
|
||||||
|
checkers.append(other)
|
||||||
|
else:
|
||||||
|
checkers.append(run_sync(other))
|
||||||
|
return Permission(*checkers)
|
||||||
|
|
||||||
|
|
||||||
|
async def _message(bot: Bot, event: Event) -> bool:
|
||||||
|
return event.type == "message"
|
||||||
|
|
||||||
|
|
||||||
|
async def _notice(bot: Bot, event: Event) -> bool:
|
||||||
|
return event.type == "notice"
|
||||||
|
|
||||||
|
|
||||||
|
async def _request(bot: Bot, event: Event) -> bool:
|
||||||
|
return event.type == "request"
|
||||||
|
|
||||||
|
|
||||||
|
async def _metaevent(bot: Bot, event: Event) -> bool:
|
||||||
|
return event.type == "meta_event"
|
||||||
|
|
||||||
|
|
||||||
|
MESSAGE = Permission(_message)
|
||||||
|
NOTICE = Permission(_notice)
|
||||||
|
REQUEST = Permission(_request)
|
||||||
|
METAEVENT = Permission(_metaevent)
|
||||||
|
|
||||||
|
|
||||||
|
def USER(*user: int, perm: Permission = Permission()):
|
||||||
|
|
||||||
|
async def _user(bot: Bot, event: Event) -> bool:
|
||||||
|
return event.type == "message" and event.user_id in user and await perm(
|
||||||
|
bot, event)
|
||||||
|
|
||||||
|
return Permission(_user)
|
||||||
|
|
||||||
|
|
||||||
|
async def _private(bot: Bot, event: Event) -> bool:
|
||||||
|
return event.type == "message" and event.detail_type == "private"
|
||||||
|
|
||||||
|
|
||||||
|
async def _private_friend(bot: Bot, event: Event) -> bool:
|
||||||
|
return (event.type == "message" and event.detail_type == "private" and
|
||||||
|
event.sub_type == "friend")
|
||||||
|
|
||||||
|
|
||||||
|
async def _private_group(bot: Bot, event: Event) -> bool:
|
||||||
|
return (event.type == "message" and event.detail_type == "private" and
|
||||||
|
event.sub_type == "group")
|
||||||
|
|
||||||
|
|
||||||
|
async def _private_other(bot: Bot, event: Event) -> bool:
|
||||||
|
return (event.type == "message" and event.detail_type == "private" and
|
||||||
|
event.sub_type == "other")
|
||||||
|
|
||||||
|
|
||||||
|
PRIVATE = Permission(_private)
|
||||||
|
PRIVATE_FRIEND = Permission(_private_friend)
|
||||||
|
PRIVATE_GROUP = Permission(_private_group)
|
||||||
|
PRIVATE_OTHER = Permission(_private_other)
|
||||||
|
|
||||||
|
|
||||||
|
async def _group(bot: Bot, event: Event) -> bool:
|
||||||
|
return event.type == "message" and event.detail_type == "group"
|
||||||
|
|
||||||
|
|
||||||
|
async def _group_member(bot: Bot, event: Event) -> bool:
|
||||||
|
return (event.type == "message" and event.detail_type == "group" and
|
||||||
|
event.sender.get("role") == "member")
|
||||||
|
|
||||||
|
|
||||||
|
async def _group_admin(bot: Bot, event: Event) -> bool:
|
||||||
|
return (event.type == "message" and event.detail_type == "group" and
|
||||||
|
event.sender.get("role") == "admin")
|
||||||
|
|
||||||
|
|
||||||
|
async def _group_owner(bot: Bot, event: Event) -> bool:
|
||||||
|
return (event.type == "message" and event.detail_type == "group" and
|
||||||
|
event.sender.get("role") == "owner")
|
||||||
|
|
||||||
|
|
||||||
|
GROUP = Permission(_group)
|
||||||
|
GROUP_MEMBER = Permission(_group_member)
|
||||||
|
GROUP_ADMIN = Permission(_group_admin)
|
||||||
|
GROUP_OWNER = Permission(_group_owner)
|
||||||
|
|
||||||
|
|
||||||
|
async def _superuser(bot: Bot, event: Event) -> bool:
|
||||||
|
return event.type == "message" and event.user_id in bot.config.superusers
|
||||||
|
|
||||||
|
|
||||||
|
SUPERUSER = Permission(_superuser)
|
||||||
|
EVERYBODY = MESSAGE
|
@ -1,14 +1,16 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import re
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import importlib
|
import importlib
|
||||||
from importlib.util import module_from_spec
|
from importlib.util import module_from_spec
|
||||||
|
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
from nonebot.matcher import Matcher
|
from nonebot.matcher import Matcher
|
||||||
from nonebot.rule import SyncRule, metaevent, message, notice, request
|
from nonebot.rule import Rule, startswith, endswith, command, regex
|
||||||
from nonebot.typing import Set, Dict, Type, Rule, Union, Optional, ModuleType, RuleChecker
|
from nonebot.permission import Permission, METAEVENT, MESSAGE, NOTICE, REQUEST
|
||||||
|
from nonebot.typing import Set, Dict, Type, Tuple, Union, Optional, ModuleType, RuleChecker
|
||||||
|
|
||||||
plugins: Dict[str, "Plugin"] = {}
|
plugins: Dict[str, "Plugin"] = {}
|
||||||
|
|
||||||
@ -25,13 +27,14 @@ class Plugin(object):
|
|||||||
self.matchers = matchers
|
self.matchers = matchers
|
||||||
|
|
||||||
|
|
||||||
def on_metaevent(rule: Union[Rule, RuleChecker] = SyncRule(),
|
def on_metaevent(rule: Union[Rule, RuleChecker] = Rule(),
|
||||||
*,
|
*,
|
||||||
handlers=[],
|
handlers=[],
|
||||||
temp=False,
|
temp=False,
|
||||||
priority: int = 1,
|
priority: int = 1,
|
||||||
state={}) -> Type[Matcher]:
|
state={}) -> Type[Matcher]:
|
||||||
matcher = Matcher.new(metaevent() & rule,
|
matcher = Matcher.new(Rule() & rule,
|
||||||
|
METAEVENT,
|
||||||
temp=temp,
|
temp=temp,
|
||||||
priority=priority,
|
priority=priority,
|
||||||
handlers=handlers,
|
handlers=handlers,
|
||||||
@ -40,13 +43,15 @@ def on_metaevent(rule: Union[Rule, RuleChecker] = SyncRule(),
|
|||||||
return matcher
|
return matcher
|
||||||
|
|
||||||
|
|
||||||
def on_message(rule: Union[Rule, RuleChecker] = SyncRule(),
|
def on_message(rule: Union[Rule, RuleChecker] = Rule(),
|
||||||
|
permission: Permission = MESSAGE,
|
||||||
*,
|
*,
|
||||||
handlers=[],
|
handlers=[],
|
||||||
temp=False,
|
temp=False,
|
||||||
priority: int = 1,
|
priority: int = 1,
|
||||||
state={}) -> Type[Matcher]:
|
state={}) -> Type[Matcher]:
|
||||||
matcher = Matcher.new(message() & rule,
|
matcher = Matcher.new(Rule() & rule,
|
||||||
|
permission,
|
||||||
temp=temp,
|
temp=temp,
|
||||||
priority=priority,
|
priority=priority,
|
||||||
handlers=handlers,
|
handlers=handlers,
|
||||||
@ -55,13 +60,14 @@ def on_message(rule: Union[Rule, RuleChecker] = SyncRule(),
|
|||||||
return matcher
|
return matcher
|
||||||
|
|
||||||
|
|
||||||
def on_notice(rule: Union[Rule, RuleChecker] = SyncRule(),
|
def on_notice(rule: Union[Rule, RuleChecker] = Rule(),
|
||||||
*,
|
*,
|
||||||
handlers=[],
|
handlers=[],
|
||||||
temp=False,
|
temp=False,
|
||||||
priority: int = 1,
|
priority: int = 1,
|
||||||
state={}) -> Type[Matcher]:
|
state={}) -> Type[Matcher]:
|
||||||
matcher = Matcher.new(notice() & rule,
|
matcher = Matcher.new(Rule() & rule,
|
||||||
|
NOTICE,
|
||||||
temp=temp,
|
temp=temp,
|
||||||
priority=priority,
|
priority=priority,
|
||||||
handlers=handlers,
|
handlers=handlers,
|
||||||
@ -70,13 +76,14 @@ def on_notice(rule: Union[Rule, RuleChecker] = SyncRule(),
|
|||||||
return matcher
|
return matcher
|
||||||
|
|
||||||
|
|
||||||
def on_request(rule: Union[Rule, RuleChecker] = SyncRule(),
|
def on_request(rule: Union[Rule, RuleChecker] = Rule(),
|
||||||
*,
|
*,
|
||||||
handlers=[],
|
handlers=[],
|
||||||
temp=False,
|
temp=False,
|
||||||
priority: int = 1,
|
priority: int = 1,
|
||||||
state={}) -> Type[Matcher]:
|
state={}) -> Type[Matcher]:
|
||||||
matcher = Matcher.new(request() & rule,
|
matcher = Matcher.new(Rule() & rule,
|
||||||
|
REQUEST,
|
||||||
temp=temp,
|
temp=temp,
|
||||||
priority=priority,
|
priority=priority,
|
||||||
handlers=handlers,
|
handlers=handlers,
|
||||||
@ -85,22 +92,40 @@ def on_request(rule: Union[Rule, RuleChecker] = SyncRule(),
|
|||||||
return matcher
|
return matcher
|
||||||
|
|
||||||
|
|
||||||
# def on_startswith(msg,
|
def on_startswith(msg: str,
|
||||||
# start: int = None,
|
rule: Optional[Union[Rule, RuleChecker]] = None,
|
||||||
# end: int = None,
|
permission: Permission = MESSAGE,
|
||||||
# rule: Optional[Rule] = None,
|
**kwargs) -> Type[Matcher]:
|
||||||
# **kwargs) -> Type[Matcher]:
|
return on_message(startswith(msg) &
|
||||||
# return on_message(startswith(msg, start, end) &
|
rule, permission, **kwargs) if rule else on_message(
|
||||||
# rule, **kwargs) if rule else on_message(
|
startswith(msg), permission, **kwargs)
|
||||||
# startswith(msg, start, end), **kwargs)
|
|
||||||
|
|
||||||
# def on_regex(pattern,
|
|
||||||
# flags: Union[int, re.RegexFlag] = 0,
|
def on_endswith(msg: str,
|
||||||
# rule: Optional[Rule] = None,
|
rule: Optional[Union[Rule, RuleChecker]] = None,
|
||||||
# **kwargs) -> Type[Matcher]:
|
permission: Permission = MESSAGE,
|
||||||
# return on_message(regex(pattern, flags) &
|
**kwargs) -> Type[Matcher]:
|
||||||
# rule, **kwargs) if rule else on_message(
|
return on_message(endswith(msg) &
|
||||||
# regex(pattern, flags), **kwargs)
|
rule, permission, **kwargs) if rule else on_message(
|
||||||
|
startswith(msg), permission, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def on_command(cmd: Tuple[str],
|
||||||
|
rule: Optional[Union[Rule, RuleChecker]] = None,
|
||||||
|
permission: Permission = MESSAGE,
|
||||||
|
**kwargs) -> Type[Matcher]:
|
||||||
|
return on_message(command(cmd) &
|
||||||
|
rule, permission, **kwargs) if rule else on_message(
|
||||||
|
command(cmd), permission, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def on_regex(pattern: str,
|
||||||
|
flags: Union[int, re.RegexFlag] = 0,
|
||||||
|
rule: Optional[Rule] = None,
|
||||||
|
**kwargs) -> Type[Matcher]:
|
||||||
|
return on_message(regex(pattern, flags) &
|
||||||
|
rule, **kwargs) if rule else on_message(
|
||||||
|
regex(pattern, flags), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def load_plugin(module_path: str) -> Optional[Plugin]:
|
def load_plugin(module_path: str) -> Optional[Plugin]:
|
||||||
|
281
nonebot/rule.py
281
nonebot/rule.py
@ -2,207 +2,126 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import abc
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import cast
|
from itertools import product
|
||||||
|
|
||||||
|
from pygtrie import CharTrie
|
||||||
|
|
||||||
|
from nonebot import get_driver
|
||||||
|
from nonebot.log import logger
|
||||||
from nonebot.utils import run_sync
|
from nonebot.utils import run_sync
|
||||||
from nonebot.typing import Bot, Event, Union, Optional, Awaitable
|
from nonebot.typing import Bot, Any, Dict, Event, Union, Tuple, NoReturn, RuleChecker
|
||||||
from nonebot.typing import RuleChecker, SyncRuleChecker, AsyncRuleChecker
|
|
||||||
|
|
||||||
|
|
||||||
class BaseRule(abc.ABC):
|
class Rule:
|
||||||
|
__slots__ = ("checkers",)
|
||||||
|
|
||||||
def __init__(self, checker: RuleChecker):
|
def __init__(self, *checkers: RuleChecker) -> None:
|
||||||
self.checker: RuleChecker = checker
|
self.checkers = list(checkers)
|
||||||
|
|
||||||
@abc.abstractmethod
|
async def __call__(self, bot: Bot, event: Event, state: dict) -> bool:
|
||||||
def __call__(self, bot: Bot, event: Event) -> Awaitable[bool]:
|
results = await asyncio.gather(
|
||||||
raise NotImplementedError
|
*map(lambda c: c(bot, event, state), self.checkers))
|
||||||
|
return all(results)
|
||||||
|
|
||||||
@abc.abstractmethod
|
def __and__(self, other: Union["Rule", RuleChecker]) -> "Rule":
|
||||||
def __and__(self, other: Union["BaseRule", RuleChecker]) -> "BaseRule":
|
checkers = [*self.checkers]
|
||||||
raise NotImplementedError
|
if isinstance(other, Rule):
|
||||||
|
checkers.extend(other.checkers)
|
||||||
@abc.abstractmethod
|
elif asyncio.iscoroutinefunction(other):
|
||||||
def __or__(self, other: Union["BaseRule", RuleChecker]) -> "BaseRule":
|
checkers.append(other)
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def __neg__(self) -> "BaseRule":
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
class AsyncRule(BaseRule):
|
|
||||||
|
|
||||||
def __init__(self, checker: Optional[AsyncRuleChecker] = None):
|
|
||||||
|
|
||||||
async def always_true(bot: Bot, event: Event) -> bool:
|
|
||||||
return True
|
|
||||||
|
|
||||||
self.checker: AsyncRuleChecker = checker or always_true
|
|
||||||
|
|
||||||
def __call__(self, bot: Bot, event: Event) -> Awaitable[bool]:
|
|
||||||
return self.checker(bot, event)
|
|
||||||
|
|
||||||
def __and__(self, other: Union[BaseRule, RuleChecker]) -> "AsyncRule":
|
|
||||||
func = other
|
|
||||||
if isinstance(other, BaseRule):
|
|
||||||
func = other.checker
|
|
||||||
|
|
||||||
if not asyncio.iscoroutinefunction(func):
|
|
||||||
func = run_sync(func)
|
|
||||||
|
|
||||||
async def tmp(bot: Bot, event: Event) -> bool:
|
|
||||||
a, b = await asyncio.gather(self.checker(bot, event),
|
|
||||||
func(bot, event))
|
|
||||||
return a and b
|
|
||||||
|
|
||||||
return AsyncRule(tmp)
|
|
||||||
|
|
||||||
def __or__(self, other: Union[BaseRule, RuleChecker]) -> "AsyncRule":
|
|
||||||
func = other
|
|
||||||
if isinstance(other, BaseRule):
|
|
||||||
func = other.checker
|
|
||||||
|
|
||||||
if not asyncio.iscoroutinefunction(func):
|
|
||||||
func = run_sync(func)
|
|
||||||
|
|
||||||
async def tmp(bot: Bot, event: Event) -> bool:
|
|
||||||
a, b = await asyncio.gather(self.checker(bot, event),
|
|
||||||
func(bot, event))
|
|
||||||
return a or b
|
|
||||||
|
|
||||||
return AsyncRule(tmp)
|
|
||||||
|
|
||||||
def __neg__(self) -> "AsyncRule":
|
|
||||||
|
|
||||||
async def neg(bot: Bot, event: Event) -> bool:
|
|
||||||
result = await self.checker(bot, event)
|
|
||||||
return not result
|
|
||||||
|
|
||||||
return AsyncRule(neg)
|
|
||||||
|
|
||||||
|
|
||||||
class SyncRule(BaseRule):
|
|
||||||
|
|
||||||
def __init__(self, checker: Optional[SyncRuleChecker] = None):
|
|
||||||
|
|
||||||
def always_true(bot: Bot, event: Event) -> bool:
|
|
||||||
return True
|
|
||||||
|
|
||||||
self.checker: SyncRuleChecker = checker or always_true
|
|
||||||
|
|
||||||
def __call__(self, bot: Bot, event: Event) -> Awaitable[bool]:
|
|
||||||
return run_sync(self.checker)(bot, event)
|
|
||||||
|
|
||||||
def __and__(self, other: Union[BaseRule, RuleChecker]) -> BaseRule:
|
|
||||||
func = other
|
|
||||||
if isinstance(other, BaseRule):
|
|
||||||
func = other.checker
|
|
||||||
|
|
||||||
if not asyncio.iscoroutinefunction(func):
|
|
||||||
# func: SyncRuleChecker
|
|
||||||
syncfunc = cast(SyncRuleChecker, func)
|
|
||||||
|
|
||||||
def tmp(bot: Bot, event: Event) -> bool:
|
|
||||||
return self.checker(bot, event) and syncfunc(bot, event)
|
|
||||||
|
|
||||||
return SyncRule(tmp)
|
|
||||||
else:
|
else:
|
||||||
# func: AsyncRuleChecker
|
checkers.append(run_sync(other))
|
||||||
asyncfunc = cast(AsyncRuleChecker, func)
|
return Rule(*checkers)
|
||||||
|
|
||||||
async def tmp(bot: Bot, event: Event) -> bool:
|
def __or__(self, other) -> NoReturn:
|
||||||
a, b = await asyncio.gather(
|
raise RuntimeError("Or operation between rules is not allowed.")
|
||||||
run_sync(self.checker)(bot, event), asyncfunc(bot, event))
|
|
||||||
return a and b
|
|
||||||
|
|
||||||
return AsyncRule(tmp)
|
|
||||||
|
|
||||||
def __or__(self, other: Union[BaseRule, RuleChecker]) -> BaseRule:
|
|
||||||
func = other
|
|
||||||
if isinstance(other, BaseRule):
|
|
||||||
func = other.checker
|
|
||||||
|
|
||||||
if not asyncio.iscoroutinefunction(func):
|
|
||||||
# func: SyncRuleChecker
|
|
||||||
syncfunc = cast(SyncRuleChecker, func)
|
|
||||||
|
|
||||||
def tmp(bot: Bot, event: Event) -> bool:
|
|
||||||
return self.checker(bot, event) or syncfunc(bot, event)
|
|
||||||
|
|
||||||
return SyncRule(tmp)
|
|
||||||
else:
|
|
||||||
# func: AsyncRuleChecker
|
|
||||||
asyncfunc = cast(AsyncRuleChecker, func)
|
|
||||||
|
|
||||||
async def tmp(bot: Bot, event: Event) -> bool:
|
|
||||||
a, b = await asyncio.gather(
|
|
||||||
run_sync(self.checker)(bot, event), asyncfunc(bot, event))
|
|
||||||
return a or b
|
|
||||||
|
|
||||||
return AsyncRule(tmp)
|
|
||||||
|
|
||||||
def __neg__(self) -> "SyncRule":
|
|
||||||
|
|
||||||
def neg(bot: Bot, event: Event) -> bool:
|
|
||||||
return not self.checker(bot, event)
|
|
||||||
|
|
||||||
return SyncRule(neg)
|
|
||||||
|
|
||||||
|
|
||||||
def Rule(func: Optional[RuleChecker] = None) -> BaseRule:
|
class TrieRule:
|
||||||
if func and asyncio.iscoroutinefunction(func):
|
prefix: CharTrie = CharTrie()
|
||||||
asyncfunc = cast(AsyncRuleChecker, func)
|
suffix: CharTrie = CharTrie()
|
||||||
return AsyncRule(asyncfunc)
|
|
||||||
else:
|
@classmethod
|
||||||
syncfunc = cast(Optional[SyncRuleChecker], func)
|
def add_prefix(cls, prefix: str, value: Any):
|
||||||
return SyncRule(syncfunc)
|
if prefix in cls.prefix:
|
||||||
|
logger.warning(f'Duplicated prefix rule "{prefix}"')
|
||||||
|
return
|
||||||
|
cls.prefix[prefix] = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_suffix(cls, suffix: str, value: Any):
|
||||||
|
if suffix[::-1] in cls.suffix:
|
||||||
|
logger.warning(f'Duplicated suffix rule "{suffix}"')
|
||||||
|
return
|
||||||
|
cls.suffix[suffix[::-1]] = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_value(cls, bot: Bot, event: Event,
|
||||||
|
state: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
||||||
|
prefix = None
|
||||||
|
suffix = None
|
||||||
|
message = event.message[0]
|
||||||
|
if message.type == "text":
|
||||||
|
prefix = cls.prefix.longest_prefix(message.data["text"].lstrip())
|
||||||
|
message_r = event.message[-1]
|
||||||
|
if message_r.type == "text":
|
||||||
|
suffix = cls.suffix.longest_prefix(
|
||||||
|
message_r.data["text"].rstrip()[::-1])
|
||||||
|
|
||||||
|
state["_prefix"] = {prefix.key: prefix.value} if prefix else {}
|
||||||
|
state["_suffix"] = {suffix.key: suffix.value} if suffix else {}
|
||||||
|
|
||||||
|
return ({
|
||||||
|
prefix.key: prefix.value
|
||||||
|
} if prefix else {}, {
|
||||||
|
suffix.key: suffix.value
|
||||||
|
} if suffix else {})
|
||||||
|
|
||||||
|
|
||||||
def message() -> BaseRule:
|
def startswith(msg: str) -> Rule:
|
||||||
return Rule(lambda bot, event: event.type == "message")
|
TrieRule.add_prefix(msg, (msg,))
|
||||||
|
|
||||||
|
async def _startswith(bot: Bot, event: Event, state: dict) -> bool:
|
||||||
|
return msg in state["_prefix"]
|
||||||
|
|
||||||
|
return Rule(_startswith)
|
||||||
|
|
||||||
|
|
||||||
def notice() -> BaseRule:
|
def endswith(msg: str) -> Rule:
|
||||||
return Rule(lambda bot, event: event.type == "notice")
|
TrieRule.add_suffix(msg, (msg,))
|
||||||
|
|
||||||
|
async def _endswith(bot: Bot, event: Event, state: dict) -> bool:
|
||||||
|
return msg in state["_suffix"]
|
||||||
|
|
||||||
|
return Rule(_endswith)
|
||||||
|
|
||||||
|
|
||||||
def request() -> BaseRule:
|
def keyword(msg: str) -> Rule:
|
||||||
return Rule(lambda bot, event: event.type == "request")
|
|
||||||
|
async def _keyword(bot: Bot, event: Event, state: dict) -> bool:
|
||||||
|
return bool(event.plain_text and msg in event.plain_text)
|
||||||
|
|
||||||
|
return Rule(_keyword)
|
||||||
|
|
||||||
|
|
||||||
def metaevent() -> BaseRule:
|
def command(command: Tuple[str]) -> Rule:
|
||||||
return Rule(lambda bot, event: event.type == "meta_event")
|
config = get_driver().config
|
||||||
|
command_start = config.command_start
|
||||||
|
command_sep = config.command_sep
|
||||||
|
for start, sep in product(command_start, command_sep):
|
||||||
|
TrieRule.add_prefix(f"{start}{sep.join(command)}", command)
|
||||||
|
|
||||||
|
async def _command(bot: Bot, event: Event, state: dict) -> bool:
|
||||||
|
return command in state["_prefix"].values()
|
||||||
|
|
||||||
|
return Rule(_command)
|
||||||
|
|
||||||
|
|
||||||
def user(*qq: int) -> BaseRule:
|
def regex(regex: str, flags: Union[int, re.RegexFlag] = 0) -> Rule:
|
||||||
return Rule(lambda bot, event: event.user_id in qq)
|
|
||||||
|
|
||||||
|
|
||||||
def private() -> BaseRule:
|
|
||||||
return Rule(lambda bot, event: event.detail_type == "private")
|
|
||||||
|
|
||||||
|
|
||||||
def group(*group: int) -> BaseRule:
|
|
||||||
return Rule(lambda bot, event: event.detail_type == "group" and event.
|
|
||||||
group_id in group)
|
|
||||||
|
|
||||||
|
|
||||||
def startswith(msg, start: int = None, end: int = None) -> BaseRule:
|
|
||||||
return Rule(lambda bot, event: event.message.startswith(msg, start, end))
|
|
||||||
|
|
||||||
|
|
||||||
def endswith(msg, start: int = None, end: int = None) -> BaseRule:
|
|
||||||
return Rule(
|
|
||||||
lambda bot, event: event.message.endswith(msg, start=None, end=None))
|
|
||||||
|
|
||||||
|
|
||||||
def has(msg: str) -> BaseRule:
|
|
||||||
return Rule(lambda bot, event: msg in event.message)
|
|
||||||
|
|
||||||
|
|
||||||
def regex(regex, flags: Union[int, re.RegexFlag] = 0) -> BaseRule:
|
|
||||||
pattern = re.compile(regex, flags)
|
pattern = re.compile(regex, flags)
|
||||||
return Rule(lambda bot, event: bool(pattern.search(str(event.message))))
|
|
||||||
|
async def _regex(bot: Bot, event: Event, state: dict) -> bool:
|
||||||
|
return bool(pattern.search(str(event.message)))
|
||||||
|
|
||||||
|
return Rule(_regex)
|
||||||
|
@ -8,9 +8,10 @@ from typing import Union, TypeVar, Optional, Iterable, Callable, Awaitable
|
|||||||
|
|
||||||
# import some modules needed when checking types
|
# import some modules needed when checking types
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from nonebot.rule import BaseRule
|
from nonebot.rule import Rule as RuleClass
|
||||||
from nonebot.matcher import Matcher as MatcherClass
|
from nonebot.matcher import Matcher as MatcherClass
|
||||||
from nonebot.drivers import BaseDriver, BaseWebSocket
|
from nonebot.drivers import BaseDriver, BaseWebSocket
|
||||||
|
from nonebot.permission import Permission as PermissionClass
|
||||||
from nonebot.adapters import BaseBot, BaseEvent, BaseMessage, BaseMessageSegment
|
from nonebot.adapters import BaseBot, BaseEvent, BaseMessage, BaseMessageSegment
|
||||||
|
|
||||||
|
|
||||||
@ -32,14 +33,13 @@ Event = TypeVar("Event", bound="BaseEvent")
|
|||||||
Message = TypeVar("Message", bound="BaseMessage")
|
Message = TypeVar("Message", bound="BaseMessage")
|
||||||
MessageSegment = TypeVar("MessageSegment", bound="BaseMessageSegment")
|
MessageSegment = TypeVar("MessageSegment", bound="BaseMessageSegment")
|
||||||
|
|
||||||
PreProcessor = Callable[[Bot, Event], Union[Awaitable[None],
|
PreProcessor = Callable[[Bot, Event, dict], Union[Awaitable[None],
|
||||||
Awaitable[NoReturn]]]
|
Awaitable[NoReturn]]]
|
||||||
|
|
||||||
Matcher = TypeVar("Matcher", bound="MatcherClass")
|
Matcher = TypeVar("Matcher", bound="MatcherClass")
|
||||||
Handler = Callable[[Bot, Event, Dict[Any, Any]], Union[Awaitable[None],
|
Handler = Callable[[Bot, Event, Dict[Any, Any]], Union[Awaitable[None],
|
||||||
Awaitable[NoReturn]]]
|
Awaitable[NoReturn]]]
|
||||||
Rule = TypeVar("Rule", bound="BaseRule")
|
Rule = TypeVar("Rule", bound="RuleClass")
|
||||||
_RuleChecker_Return = TypeVar("_RuleChecker_Return", bool, Awaitable[bool])
|
RuleChecker = Callable[[Bot, Event, dict], Awaitable[bool]]
|
||||||
RuleChecker = Callable[[Bot, Event], _RuleChecker_Return]
|
Permission = TypeVar("Permission", bound="PermissionClass")
|
||||||
SyncRuleChecker = RuleChecker[Bot, Event, bool]
|
PermissionChecker = Callable[[Bot, Event], Awaitable[bool]]
|
||||||
AsyncRuleChecker = RuleChecker[Bot, Event, Awaitable[bool]]
|
|
||||||
|
27
poetry.lock
generated
27
poetry.lock
generated
@ -414,6 +414,19 @@ reference = "aliyun"
|
|||||||
type = "legacy"
|
type = "legacy"
|
||||||
url = "https://mirrors.aliyun.com/pypi/simple"
|
url = "https://mirrors.aliyun.com/pypi/simple"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Trie data structure implementation."
|
||||||
|
name = "pygtrie"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2.3.3"
|
||||||
|
|
||||||
|
[package.source]
|
||||||
|
reference = "aliyun"
|
||||||
|
type = "legacy"
|
||||||
|
url = "https://mirrors.aliyun.com/pypi/simple"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Python parsing module"
|
description = "Python parsing module"
|
||||||
@ -540,7 +553,7 @@ description = "Python documentation generator"
|
|||||||
name = "sphinx"
|
name = "sphinx"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.5"
|
||||||
version = "3.2.0"
|
version = "3.2.1"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
Jinja2 = ">=2.3"
|
Jinja2 = ">=2.3"
|
||||||
@ -587,9 +600,10 @@ unify = "*"
|
|||||||
yapf = "*"
|
yapf = "*"
|
||||||
|
|
||||||
[package.source]
|
[package.source]
|
||||||
reference = "5254c22fad13be69d8301e184818c4578d0e4115"
|
reference = "88a68ed340013067a1c673bdf7541680c581fa60"
|
||||||
type = "git"
|
type = "git"
|
||||||
url = "https://github.com/nonebot/sphinx-markdown-builder.git"
|
url = "https://github.com/nonebot/sphinx-markdown-builder.git"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books"
|
description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books"
|
||||||
@ -838,7 +852,7 @@ scheduler = ["apscheduler"]
|
|||||||
test = []
|
test = []
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
content-hash = "b89641a9b24184b999991e1534842905ece528b73824eb79d6d378d686526da2"
|
content-hash = "4d16d7ad0930bc9851802bc149f843c4e990a987e89414d765579ea8dccc8d6e"
|
||||||
python-versions = "^3.7"
|
python-versions = "^3.7"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
@ -1002,6 +1016,9 @@ pygments = [
|
|||||||
{file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"},
|
{file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"},
|
||||||
{file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"},
|
{file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"},
|
||||||
]
|
]
|
||||||
|
pygtrie = [
|
||||||
|
{file = "pygtrie-2.3.3.tar.gz", hash = "sha256:2204dbd95584f67821da5b3771c4305ac5585552b3230b210f1f05322608db2c"},
|
||||||
|
]
|
||||||
pyparsing = [
|
pyparsing = [
|
||||||
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
|
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
|
||||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
||||||
@ -1035,8 +1052,8 @@ snowballstemmer = [
|
|||||||
{file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"},
|
{file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"},
|
||||||
]
|
]
|
||||||
sphinx = [
|
sphinx = [
|
||||||
{file = "Sphinx-3.2.0-py3-none-any.whl", hash = "sha256:f7db5b76c42c8b5ef31853c2de7178ef378b985d7793829ec071e120dac1d0ca"},
|
{file = "Sphinx-3.2.1-py3-none-any.whl", hash = "sha256:ce6fd7ff5b215af39e2fcd44d4a321f6694b4530b6f2b2109b64d120773faea0"},
|
||||||
{file = "Sphinx-3.2.0.tar.gz", hash = "sha256:cf2d5bc3c6c930ab0a1fbef3ad8a82994b1bf4ae923f8098a05c7e5516f07177"},
|
{file = "Sphinx-3.2.1.tar.gz", hash = "sha256:321d6d9b16fa381a5306e5a0b76cd48ffbc588e6340059a729c6fdd66087e0e8"},
|
||||||
]
|
]
|
||||||
sphinx-markdown-builder = []
|
sphinx-markdown-builder = []
|
||||||
sphinxcontrib-applehelp = [
|
sphinxcontrib-applehelp = [
|
||||||
|
@ -21,6 +21,7 @@ classifiers = [
|
|||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.7"
|
python = "^3.7"
|
||||||
httpx = "^0.13.3"
|
httpx = "^0.13.3"
|
||||||
|
pygtrie = "^2.3.3"
|
||||||
fastapi = "^0.58.1"
|
fastapi = "^0.58.1"
|
||||||
uvicorn = "^0.11.5"
|
uvicorn = "^0.11.5"
|
||||||
pydantic = { extras = ["dotenv"], version = "^1.6.1" }
|
pydantic = { extras = ["dotenv"], version = "^1.6.1" }
|
||||||
|
@ -4,19 +4,19 @@
|
|||||||
from nonebot.rule import Rule
|
from nonebot.rule import Rule
|
||||||
from nonebot.typing import Event
|
from nonebot.typing import Event
|
||||||
from nonebot.plugin import on_message
|
from nonebot.plugin import on_message
|
||||||
from nonebot.adapters.cqhttp import Bot, Message
|
from nonebot.adapters.cqhttp import Bot
|
||||||
|
|
||||||
test_matcher = on_message(state={"default": 1})
|
test_message = on_message(state={"default": 1})
|
||||||
|
|
||||||
|
|
||||||
@test_matcher.handle()
|
@test_message.handle()
|
||||||
async def test_handler(bot: Bot, event: Event, state: dict):
|
async def test_handler(bot: Bot, event: Event, state: dict):
|
||||||
print("Test Matcher Received:", event)
|
print("Test Matcher Received:", event)
|
||||||
print("Current State:", state)
|
print("Current State:", state)
|
||||||
state["event"] = event
|
state["event"] = event
|
||||||
|
|
||||||
|
|
||||||
@test_matcher.receive()
|
@test_message.receive()
|
||||||
async def test_receive(bot: Bot, event: Event, state: dict):
|
async def test_receive(bot: Bot, event: Event, state: dict):
|
||||||
print("Test Matcher Received next time:", event)
|
print("Test Matcher Received next time:", event)
|
||||||
print("Current State:", state)
|
print("Current State:", state)
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from . import matchers
|
from . import test_command
|
||||||
|
14
tests/test_plugins/test_package/test_command.py
Normal file
14
tests/test_plugins/test_package/test_command.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from nonebot.rule import Rule
|
||||||
|
from nonebot.typing import Event
|
||||||
|
from nonebot.plugin import on_command
|
||||||
|
from nonebot.adapters.cqhttp import Bot
|
||||||
|
|
||||||
|
test_command = on_command(("帮助",))
|
||||||
|
|
||||||
|
|
||||||
|
@test_command.handle()
|
||||||
|
async def test_handler(bot: Bot, event: Event, state: dict):
|
||||||
|
print(state["_prefix"])
|
Loading…
x
Reference in New Issue
Block a user