mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-01-19 09:38:21 +08:00
move decorators to plugin module
This commit is contained in:
parent
9fbd09331c
commit
4f9a9136f9
@ -15,12 +15,16 @@ else:
|
|||||||
|
|
||||||
|
|
||||||
class NoneBot(CQHttp):
|
class NoneBot(CQHttp):
|
||||||
|
|
||||||
def __init__(self, config_object: Optional[Any] = None):
|
def __init__(self, config_object: Optional[Any] = None):
|
||||||
if config_object is None:
|
if config_object is None:
|
||||||
from . import default_config as config_object
|
from . import default_config as config_object
|
||||||
|
|
||||||
config_dict = {k: v for k, v in config_object.__dict__.items()
|
config_dict = {
|
||||||
if k.isupper() and not k.startswith('_')}
|
k: v
|
||||||
|
for k, v in config_object.__dict__.items()
|
||||||
|
if k.isupper() and not k.startswith('_')
|
||||||
|
}
|
||||||
logger.debug(f'Loaded configurations: {config_dict}')
|
logger.debug(f'Loaded configurations: {config_dict}')
|
||||||
super().__init__(message_class=aiocqhttp.message.Message,
|
super().__init__(message_class=aiocqhttp.message.Message,
|
||||||
**{k.lower(): v for k, v in config_dict.items()})
|
**{k.lower(): v for k, v in config_dict.items()})
|
||||||
@ -43,8 +47,11 @@ class NoneBot(CQHttp):
|
|||||||
async def _(event: aiocqhttp.Event):
|
async def _(event: aiocqhttp.Event):
|
||||||
asyncio.create_task(handle_notice_or_request(self, event))
|
asyncio.create_task(handle_notice_or_request(self, event))
|
||||||
|
|
||||||
def run(self, host: Optional[str] = None, port: Optional[int] = None,
|
def run(self,
|
||||||
*args, **kwargs) -> None:
|
host: Optional[str] = None,
|
||||||
|
port: Optional[int] = None,
|
||||||
|
*args,
|
||||||
|
**kwargs) -> None:
|
||||||
host = host or self.config.HOST
|
host = host or self.config.HOST
|
||||||
port = port or self.config.PORT
|
port = port or self.config.PORT
|
||||||
if 'debug' not in kwargs:
|
if 'debug' not in kwargs:
|
||||||
@ -99,8 +106,8 @@ def get_bot() -> NoneBot:
|
|||||||
return _bot
|
return _bot
|
||||||
|
|
||||||
|
|
||||||
def run(host: Optional[str] = None, port: Optional[int] = None,
|
def run(host: Optional[str] = None, port: Optional[int] = None, *args,
|
||||||
*args, **kwargs) -> None:
|
**kwargs) -> None:
|
||||||
"""Run the NoneBot instance."""
|
"""Run the NoneBot instance."""
|
||||||
get_bot().run(host=host, port=port, *args, **kwargs)
|
get_bot().run(host=host, port=port, *args, **kwargs)
|
||||||
|
|
||||||
@ -125,31 +132,40 @@ def on_websocket_connect(func: Callable[[aiocqhttp.Event], Awaitable[None]]) \
|
|||||||
|
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .message import message_preprocessor, Message, MessageSegment
|
from .message import message_preprocessor, Message, MessageSegment
|
||||||
from .plugin import (load_plugin, load_plugins, load_builtin_plugins,
|
from .plugin import (on_command, on_natural_language, on_notice, on_request,
|
||||||
|
load_plugin, load_plugins, load_builtin_plugins,
|
||||||
get_loaded_plugins)
|
get_loaded_plugins)
|
||||||
from .command import on_command, CommandSession, CommandGroup
|
from .command import CommandSession, CommandGroup
|
||||||
from .natural_language import (on_natural_language, NLPSession, NLPResult,
|
from .natural_language import NLPSession, NLPResult, IntentCommand
|
||||||
IntentCommand)
|
from .notice_request import NoticeSession, RequestSession
|
||||||
from .notice_request import (on_notice, NoticeSession,
|
|
||||||
on_request, RequestSession)
|
|
||||||
from .helpers import context_id
|
from .helpers import context_id
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'NoneBot', 'scheduler', 'init', 'get_bot', 'run',
|
'NoneBot',
|
||||||
|
'scheduler',
|
||||||
'on_startup', 'on_websocket_connect',
|
'init',
|
||||||
|
'get_bot',
|
||||||
|
'run',
|
||||||
|
'on_startup',
|
||||||
|
'on_websocket_connect',
|
||||||
'CQHttpError',
|
'CQHttpError',
|
||||||
|
'load_plugin',
|
||||||
'load_plugin', 'load_plugins', 'load_builtin_plugins',
|
'load_plugins',
|
||||||
|
'load_builtin_plugins',
|
||||||
'get_loaded_plugins',
|
'get_loaded_plugins',
|
||||||
|
'message_preprocessor',
|
||||||
'message_preprocessor', 'Message', 'MessageSegment',
|
'Message',
|
||||||
|
'MessageSegment',
|
||||||
'on_command', 'CommandSession', 'CommandGroup',
|
'on_command',
|
||||||
|
'CommandSession',
|
||||||
'on_natural_language', 'NLPSession', 'NLPResult', 'IntentCommand',
|
'CommandGroup',
|
||||||
'on_notice', 'NoticeSession', 'on_request', 'RequestSession',
|
'on_natural_language',
|
||||||
|
'NLPSession',
|
||||||
|
'NLPResult',
|
||||||
|
'IntentCommand',
|
||||||
|
'on_notice',
|
||||||
|
'NoticeSession',
|
||||||
|
'on_request',
|
||||||
|
'RequestSession',
|
||||||
'context_id',
|
'context_id',
|
||||||
]
|
]
|
||||||
|
@ -4,6 +4,7 @@ from .command import CommandSession
|
|||||||
|
|
||||||
|
|
||||||
class ParserExit(RuntimeError):
|
class ParserExit(RuntimeError):
|
||||||
|
|
||||||
def __init__(self, status=0, message=None):
|
def __init__(self, status=0, message=None):
|
||||||
self.status = status
|
self.status = status
|
||||||
self.message = message
|
self.message = message
|
||||||
|
@ -15,20 +15,17 @@ from nonebot.helpers import context_id, send, render_expression
|
|||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
from nonebot.message import Message
|
from nonebot.message import Message
|
||||||
from nonebot.session import BaseSession
|
from nonebot.session import BaseSession
|
||||||
from nonebot.typing import (CommandName_T, CommandArgs_T, Message_T, State_T,
|
from nonebot.typing import (CommandName_T, CommandArgs_T, CommandHandler_T,
|
||||||
Filter_T)
|
Message_T, State_T, Filter_T)
|
||||||
|
|
||||||
# key: context id
|
# key: context id
|
||||||
# value: CommandSession object
|
# value: CommandSession object
|
||||||
_sessions = {} # type: Dict[str, "CommandSession"]
|
_sessions = {} # type: Dict[str, "CommandSession"]
|
||||||
|
|
||||||
CommandHandler_T = Callable[['CommandSession'], Any]
|
|
||||||
|
|
||||||
|
|
||||||
class Command:
|
class Command:
|
||||||
__slots__ = ('name', 'func', 'permission', 'only_to_me', 'privileged',
|
__slots__ = ('name', 'func', 'permission', 'only_to_me', 'privileged',
|
||||||
'args_parser_func', '__name__', '__qualname__', '__doc__',
|
'args_parser_func')
|
||||||
'__annotations__', '__dict__')
|
|
||||||
|
|
||||||
def __init__(self, *, name: CommandName_T, func: CommandHandler_T,
|
def __init__(self, *, name: CommandName_T, func: CommandHandler_T,
|
||||||
permission: int, only_to_me: bool, privileged: bool):
|
permission: int, only_to_me: bool, privileged: bool):
|
||||||
@ -361,55 +358,6 @@ class CommandManager:
|
|||||||
cmd_name] if state is None else bool(state)
|
cmd_name] if state is None else bool(state)
|
||||||
|
|
||||||
|
|
||||||
def on_command(name: Union[str, CommandName_T],
|
|
||||||
*,
|
|
||||||
aliases: Union[Iterable[str], str] = (),
|
|
||||||
permission: int = perm.EVERYBODY,
|
|
||||||
only_to_me: bool = True,
|
|
||||||
privileged: bool = False,
|
|
||||||
shell_like: bool = False) -> Callable:
|
|
||||||
"""
|
|
||||||
Decorator to register a function as a command.
|
|
||||||
|
|
||||||
:param name: command name (e.g. 'echo' or ('random', 'number'))
|
|
||||||
:param aliases: aliases of command name, for convenient access
|
|
||||||
:param permission: permission required by the command
|
|
||||||
:param only_to_me: only handle messages to me
|
|
||||||
:param privileged: can be run even when there is already a session
|
|
||||||
:param shell_like: use shell-like syntax to split arguments
|
|
||||||
"""
|
|
||||||
|
|
||||||
def deco(func: CommandHandler_T) -> Command:
|
|
||||||
if not isinstance(name, (str, tuple)):
|
|
||||||
raise TypeError('the name of a command must be a str or tuple')
|
|
||||||
if not name:
|
|
||||||
raise ValueError('the name of a command must not be empty')
|
|
||||||
|
|
||||||
cmd_name = (name,) if isinstance(name, str) else name
|
|
||||||
|
|
||||||
cmd = Command(name=cmd_name,
|
|
||||||
func=func,
|
|
||||||
permission=permission,
|
|
||||||
only_to_me=only_to_me,
|
|
||||||
privileged=privileged)
|
|
||||||
|
|
||||||
if shell_like:
|
|
||||||
|
|
||||||
async def shell_like_args_parser(session):
|
|
||||||
session.args['argv'] = shlex.split(session.current_arg)
|
|
||||||
|
|
||||||
cmd.args_parser_func = shell_like_args_parser
|
|
||||||
|
|
||||||
CommandManager.add_command(cmd_name, cmd)
|
|
||||||
CommandManager.add_aliases(aliases, cmd)
|
|
||||||
|
|
||||||
update_wrapper(wrapper=cmd, wrapped=func) # type: ignore
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
|
|
||||||
return deco
|
|
||||||
|
|
||||||
|
|
||||||
class _PauseException(Exception):
|
class _PauseException(Exception):
|
||||||
"""
|
"""
|
||||||
Raised by session.pause() indicating that the command session
|
Raised by session.pause() indicating that the command session
|
||||||
|
@ -4,5 +4,6 @@ from nonebot.typing import Message_T
|
|||||||
|
|
||||||
|
|
||||||
class ValidateError(ValueError):
|
class ValidateError(ValueError):
|
||||||
|
|
||||||
def __init__(self, message: Optional[Message_T] = None):
|
def __init__(self, message: Optional[Message_T] = None):
|
||||||
self.message = message
|
self.message = message
|
||||||
|
@ -11,8 +11,8 @@ def handle_cancellation(session: CommandSession):
|
|||||||
|
|
||||||
def control(value):
|
def control(value):
|
||||||
if _is_cancellation(value) is True:
|
if _is_cancellation(value) is True:
|
||||||
session.finish(render_expression(
|
session.finish(
|
||||||
session.bot.config.SESSION_CANCEL_EXPRESSION))
|
render_expression(session.bot.config.SESSION_CANCEL_EXPRESSION))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
return control
|
return control
|
||||||
|
@ -15,13 +15,15 @@ def _simple_chinese_to_bool(text: str) -> Optional[bool]:
|
|||||||
"""
|
"""
|
||||||
text = text.strip().lower().replace(' ', '') \
|
text = text.strip().lower().replace(' ', '') \
|
||||||
.rstrip(',.!?~,。!?~了的呢吧呀啊呗啦')
|
.rstrip(',.!?~,。!?~了的呢吧呀啊呗啦')
|
||||||
if text in {'要', '用', '是', '好', '对', '嗯', '行',
|
if text in {
|
||||||
'ok', 'okay', 'yeah', 'yep',
|
'要', '用', '是', '好', '对', '嗯', '行', 'ok', 'okay', 'yeah', 'yep',
|
||||||
'当真', '当然', '必须', '可以', '肯定', '没错', '确定', '确认'}:
|
'当真', '当然', '必须', '可以', '肯定', '没错', '确定', '确认'
|
||||||
|
}:
|
||||||
return True
|
return True
|
||||||
if text in {'不', '不要', '不用', '不是', '否', '不好', '不对', '不行', '别',
|
if text in {
|
||||||
'no', 'nono', 'nonono', 'nope', '不ok', '不可以', '不能',
|
'不', '不要', '不用', '不是', '否', '不好', '不对', '不行', '别', 'no', 'nono',
|
||||||
'不可以'}:
|
'nonono', 'nope', '不ok', '不可以', '不能', '不可以'
|
||||||
|
}:
|
||||||
return False
|
return False
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -31,8 +33,8 @@ def _split_nonempty_lines(text: str) -> List[str]:
|
|||||||
|
|
||||||
|
|
||||||
def _split_nonempty_stripped_lines(text: str) -> List[str]:
|
def _split_nonempty_stripped_lines(text: str) -> List[str]:
|
||||||
return list(filter(lambda x: x,
|
return list(filter(lambda x: x, map(lambda x: x.strip(),
|
||||||
map(lambda x: x.strip(), text.splitlines())))
|
text.splitlines())))
|
||||||
|
|
||||||
|
|
||||||
simple_chinese_to_bool = _simple_chinese_to_bool
|
simple_chinese_to_bool = _simple_chinese_to_bool
|
||||||
|
@ -14,8 +14,11 @@ def _extract_text(arg: Message_T) -> str:
|
|||||||
def _extract_image_urls(arg: Message_T) -> List[str]:
|
def _extract_image_urls(arg: Message_T) -> List[str]:
|
||||||
"""Extract all image urls from a message-like object."""
|
"""Extract all image urls from a message-like object."""
|
||||||
arg_as_msg = Message(arg)
|
arg_as_msg = Message(arg)
|
||||||
return [s.data['url'] for s in arg_as_msg
|
return [
|
||||||
if s.type == 'image' and 'url' in s.data]
|
s.data['url']
|
||||||
|
for s in arg_as_msg
|
||||||
|
if s.type == 'image' and 'url' in s.data
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def _extract_numbers(arg: Message_T) -> List[float]:
|
def _extract_numbers(arg: Message_T) -> List[float]:
|
||||||
|
@ -6,6 +6,7 @@ from nonebot.typing import Filter_T
|
|||||||
|
|
||||||
|
|
||||||
class BaseValidator:
|
class BaseValidator:
|
||||||
|
|
||||||
def __init__(self, message=None):
|
def __init__(self, message=None):
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
@ -69,8 +70,7 @@ def match_regex(pattern: str, message=None, *, flags=0,
|
|||||||
return validate
|
return validate
|
||||||
|
|
||||||
|
|
||||||
def ensure_true(bool_func: Callable[[Any], bool],
|
def ensure_true(bool_func: Callable[[Any], bool], message=None) -> Filter_T:
|
||||||
message=None) -> Filter_T:
|
|
||||||
"""
|
"""
|
||||||
Validate any object to ensure the result of applying
|
Validate any object to ensure the result of applying
|
||||||
a boolean function to it is True.
|
a boolean function to it is True.
|
||||||
|
@ -45,6 +45,4 @@ TOO_MANY_VALIDATION_FAILURES_EXPRESSION: Expression_T = \
|
|||||||
|
|
||||||
SESSION_CANCEL_EXPRESSION: Expression_T = '好的'
|
SESSION_CANCEL_EXPRESSION: Expression_T = '好的'
|
||||||
|
|
||||||
APSCHEDULER_CONFIG: Dict[str, Any] = {
|
APSCHEDULER_CONFIG: Dict[str, Any] = {'apscheduler.timezone': 'Asia/Shanghai'}
|
||||||
'apscheduler.timezone': 'Asia/Shanghai'
|
|
||||||
}
|
|
||||||
|
@ -10,8 +10,8 @@ from .message import escape
|
|||||||
from .typing import Message_T, Expression_T
|
from .typing import Message_T, Expression_T
|
||||||
|
|
||||||
|
|
||||||
def context_id(event: CQEvent, *,
|
def context_id(event: CQEvent, *, mode: str = 'default',
|
||||||
mode: str = 'default', use_hash: bool = False) -> str:
|
use_hash: bool = False) -> str:
|
||||||
"""
|
"""
|
||||||
Calculate a unique id representing the context of the given event.
|
Calculate a unique id representing the context of the given event.
|
||||||
|
|
||||||
@ -48,8 +48,10 @@ def context_id(event: CQEvent, *,
|
|||||||
return ctx_id
|
return ctx_id
|
||||||
|
|
||||||
|
|
||||||
async def send(bot: NoneBot, event: CQEvent,
|
async def send(bot: NoneBot,
|
||||||
message: Message_T, *,
|
event: CQEvent,
|
||||||
|
message: Message_T,
|
||||||
|
*,
|
||||||
ensure_private: bool = False,
|
ensure_private: bool = False,
|
||||||
ignore_failure: bool = True,
|
ignore_failure: bool = True,
|
||||||
**kwargs) -> Any:
|
**kwargs) -> Any:
|
||||||
@ -65,8 +67,10 @@ async def send(bot: NoneBot, event: CQEvent,
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def render_expression(expr: Expression_T, *args,
|
def render_expression(expr: Expression_T,
|
||||||
escape_args: bool = True, **kwargs) -> str:
|
*args,
|
||||||
|
escape_args: bool = True,
|
||||||
|
**kwargs) -> str:
|
||||||
"""
|
"""
|
||||||
Render an expression to message string.
|
Render an expression to message string.
|
||||||
|
|
||||||
@ -82,8 +86,8 @@ def render_expression(expr: Expression_T, *args,
|
|||||||
expr = random.choice(expr)
|
expr = random.choice(expr)
|
||||||
if escape_args:
|
if escape_args:
|
||||||
return expr.format(
|
return expr.format(
|
||||||
*[escape(s) if isinstance(s, str) else s for s in args],
|
*[escape(s) if isinstance(s, str) else s for s in args], **{
|
||||||
**{k: escape(v) if isinstance(v, str) else v
|
k: escape(v) if isinstance(v, str) else v
|
||||||
for k, v in kwargs.items()}
|
for k, v in kwargs.items()
|
||||||
)
|
})
|
||||||
return expr.format(*args, **kwargs)
|
return expr.format(*args, **kwargs)
|
||||||
|
@ -10,7 +10,6 @@ import sys
|
|||||||
|
|
||||||
logger = logging.getLogger('nonebot')
|
logger = logging.getLogger('nonebot')
|
||||||
default_handler = logging.StreamHandler(sys.stdout)
|
default_handler = logging.StreamHandler(sys.stdout)
|
||||||
default_handler.setFormatter(logging.Formatter(
|
default_handler.setFormatter(
|
||||||
'[%(asctime)s %(name)s] %(levelname)s: %(message)s'
|
logging.Formatter('[%(asctime)s %(name)s] %(levelname)s: %(message)s'))
|
||||||
))
|
|
||||||
logger.addHandler(default_handler)
|
logger.addHandler(default_handler)
|
||||||
|
@ -57,7 +57,8 @@ async def handle_message(bot: NoneBot, event: CQEvent) -> None:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
handled = await handle_command(bot, event, plugin_manager.cmd_manager)
|
handled = await handle_command(bot, event,
|
||||||
|
plugin_manager.cmd_manager)
|
||||||
break
|
break
|
||||||
except SwitchException as e:
|
except SwitchException as e:
|
||||||
# we are sure that there is no session existing now
|
# we are sure that there is no session existing now
|
||||||
@ -67,7 +68,8 @@ async def handle_message(bot: NoneBot, event: CQEvent) -> None:
|
|||||||
logger.info(f'Message {event.message_id} is handled as a command')
|
logger.info(f'Message {event.message_id} is handled as a command')
|
||||||
return
|
return
|
||||||
|
|
||||||
handled = await handle_natural_language(bot, event, plugin_manager.nlp_manager)
|
handled = await handle_natural_language(bot, event,
|
||||||
|
plugin_manager.nlp_manager)
|
||||||
if handled:
|
if handled:
|
||||||
logger.info(f'Message {event.message_id} is handled '
|
logger.info(f'Message {event.message_id} is handled '
|
||||||
f'as natural language')
|
f'as natural language')
|
||||||
@ -121,8 +123,8 @@ def _check_calling_me_nickname(bot: NoneBot, event: CQEvent) -> None:
|
|||||||
else:
|
else:
|
||||||
nicknames = filter(lambda n: n, bot.config.NICKNAME)
|
nicknames = filter(lambda n: n, bot.config.NICKNAME)
|
||||||
nickname_regex = '|'.join(nicknames)
|
nickname_regex = '|'.join(nicknames)
|
||||||
m = re.search(rf'^({nickname_regex})([\s,,]*|$)',
|
m = re.search(rf'^({nickname_regex})([\s,,]*|$)', first_text,
|
||||||
first_text, re.IGNORECASE)
|
re.IGNORECASE)
|
||||||
if m:
|
if m:
|
||||||
nickname = m.group(1)
|
nickname = m.group(1)
|
||||||
logger.debug(f'User is calling me {nickname}')
|
logger.debug(f'User is calling me {nickname}')
|
||||||
|
@ -15,8 +15,7 @@ from .typing import CommandName_T, CommandArgs_T
|
|||||||
|
|
||||||
class NLProcessor:
|
class NLProcessor:
|
||||||
__slots__ = ('func', 'keywords', 'permission', 'only_to_me',
|
__slots__ = ('func', 'keywords', 'permission', 'only_to_me',
|
||||||
'only_short_message', 'allow_empty_message', '__name__', '__qualname__', '__doc__',
|
'only_short_message', 'allow_empty_message')
|
||||||
'__annotations__', '__dict__')
|
|
||||||
|
|
||||||
def __init__(self, *, func: Callable, keywords: Optional[Iterable],
|
def __init__(self, *, func: Callable, keywords: Optional[Iterable],
|
||||||
permission: int, only_to_me: bool, only_short_message: bool,
|
permission: int, only_to_me: bool, only_short_message: bool,
|
||||||
@ -101,44 +100,6 @@ class NLPManager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def on_natural_language(
|
|
||||||
keywords: Union[Optional[Iterable], str, Callable] = None,
|
|
||||||
*,
|
|
||||||
permission: int = perm.EVERYBODY,
|
|
||||||
only_to_me: bool = True,
|
|
||||||
only_short_message: bool = True,
|
|
||||||
allow_empty_message: bool = False) -> Callable:
|
|
||||||
"""
|
|
||||||
Decorator to register a function as a natural language processor.
|
|
||||||
|
|
||||||
:param keywords: keywords to respond to, if None, respond to all messages
|
|
||||||
:param permission: permission required by the processor
|
|
||||||
:param only_to_me: only handle messages to me
|
|
||||||
:param only_short_message: only handle short messages
|
|
||||||
:param allow_empty_message: handle empty messages
|
|
||||||
"""
|
|
||||||
|
|
||||||
def deco(func: Callable) -> NLProcessor:
|
|
||||||
nl_processor = NLProcessor(
|
|
||||||
func=func,
|
|
||||||
keywords=keywords, # type: ignore
|
|
||||||
permission=permission,
|
|
||||||
only_to_me=only_to_me,
|
|
||||||
only_short_message=only_short_message,
|
|
||||||
allow_empty_message=allow_empty_message)
|
|
||||||
NLPManager.add_nl_processor(nl_processor)
|
|
||||||
update_wrapper(wrapper=nl_processor, wrapped=func) # type: ignore
|
|
||||||
return nl_processor
|
|
||||||
|
|
||||||
if isinstance(keywords, Callable):
|
|
||||||
# here "keywords" is the function to be decorated
|
|
||||||
return on_natural_language()(keywords)
|
|
||||||
else:
|
|
||||||
if isinstance(keywords, str):
|
|
||||||
keywords = (keywords,)
|
|
||||||
return deco
|
|
||||||
|
|
||||||
|
|
||||||
class NLPSession(BaseSession):
|
class NLPSession(BaseSession):
|
||||||
__slots__ = ('msg', 'msg_text', 'msg_images')
|
__slots__ = ('msg', 'msg_text', 'msg_images')
|
||||||
|
|
||||||
|
@ -11,41 +11,15 @@ from .session import BaseSession
|
|||||||
|
|
||||||
_bus = EventBus()
|
_bus = EventBus()
|
||||||
|
|
||||||
|
|
||||||
class EventHandler:
|
class EventHandler:
|
||||||
__slots__ = ('events', 'func', '__name__', '__qualname__', '__doc__',
|
__slots__ = ('events', 'func')
|
||||||
'__annotations__', '__dict__')
|
|
||||||
|
|
||||||
def __init__(self, events: List[str], func: Callable):
|
def __init__(self, events: List[str], func: Callable):
|
||||||
self.events = events
|
self.events = events
|
||||||
self.func = func
|
self.func = func
|
||||||
|
|
||||||
|
|
||||||
def _make_event_deco(post_type: str) -> Callable:
|
|
||||||
def deco_deco(arg: Optional[Union[str, Callable]] = None,
|
|
||||||
*events: str) -> Callable:
|
|
||||||
def deco(func: Callable) -> EventHandler:
|
|
||||||
if isinstance(arg, str):
|
|
||||||
events_tmp = list(map(lambda x: f"{post_type}.{x}", [arg] + list(events)))
|
|
||||||
for e in events_tmp:
|
|
||||||
_bus.subscribe(e, func)
|
|
||||||
handler = EventHandler(events_tmp, func)
|
|
||||||
return update_wrapper(handler, func) # type: ignore
|
|
||||||
else:
|
|
||||||
_bus.subscribe(post_type, func)
|
|
||||||
handler = EventHandler([post_type], func)
|
|
||||||
return update_wrapper(handler, func) # type: ignore
|
|
||||||
|
|
||||||
if isinstance(arg, Callable):
|
|
||||||
return deco(arg) # type: ignore
|
|
||||||
return deco
|
|
||||||
|
|
||||||
return deco_deco
|
|
||||||
|
|
||||||
|
|
||||||
on_notice = _make_event_deco('notice')
|
|
||||||
on_request = _make_event_deco('request')
|
|
||||||
|
|
||||||
|
|
||||||
class NoticeSession(BaseSession):
|
class NoticeSession(BaseSession):
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
@ -66,12 +40,13 @@ class RequestSession(BaseSession):
|
|||||||
:param remark: remark of friend (only works in friend request)
|
:param remark: remark of friend (only works in friend request)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await self.bot.call_action(
|
await self.bot.call_action(action='.handle_quick_operation_async',
|
||||||
action='.handle_quick_operation_async',
|
self_id=self.event.self_id,
|
||||||
self_id=self.event.self_id,
|
context=self.event,
|
||||||
context=self.event,
|
operation={
|
||||||
operation={'approve': True, 'remark': remark}
|
'approve': True,
|
||||||
)
|
'remark': remark
|
||||||
|
})
|
||||||
except CQHttpError:
|
except CQHttpError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -82,12 +57,13 @@ class RequestSession(BaseSession):
|
|||||||
:param reason: reason to reject (only works in group request)
|
:param reason: reason to reject (only works in group request)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await self.bot.call_action(
|
await self.bot.call_action(action='.handle_quick_operation_async',
|
||||||
action='.handle_quick_operation_async',
|
self_id=self.event.self_id,
|
||||||
self_id=self.event.self_id,
|
context=self.event,
|
||||||
context=self.event,
|
operation={
|
||||||
operation={'approve': False, 'reason': reason}
|
'approve': False,
|
||||||
)
|
'reason': reason
|
||||||
|
})
|
||||||
except CQHttpError:
|
except CQHttpError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -88,8 +88,7 @@ async def _check(bot: NoneBot, min_event: _MinEvent,
|
|||||||
self_id=min_event.self_id,
|
self_id=min_event.self_id,
|
||||||
group_id=min_event.group_id,
|
group_id=min_event.group_id,
|
||||||
user_id=min_event.user_id,
|
user_id=min_event.user_id,
|
||||||
no_cache=True
|
no_cache=True)
|
||||||
)
|
|
||||||
if member_info:
|
if member_info:
|
||||||
if member_info['role'] == 'owner':
|
if member_info['role'] == 'owner':
|
||||||
permission |= IS_GROUP_OWNER
|
permission |= IS_GROUP_OWNER
|
||||||
|
@ -1,20 +1,29 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shlex
|
||||||
import warnings
|
import warnings
|
||||||
import importlib
|
import importlib
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Any, Set, Dict, Optional
|
from typing import Any, Set, Dict, Union, Optional, Iterable, Callable
|
||||||
|
|
||||||
from .log import logger
|
from .log import logger
|
||||||
|
from nonebot import permission as perm
|
||||||
from .command import Command, CommandManager
|
from .command import Command, CommandManager
|
||||||
from .natural_language import NLProcessor, NLPManager
|
from .natural_language import NLProcessor, NLPManager
|
||||||
from .notice_request import _bus, EventHandler
|
from .notice_request import _bus, EventHandler
|
||||||
|
from .typing import CommandName_T, CommandHandler_T
|
||||||
|
|
||||||
|
_tmp_command: Set[Command] = set()
|
||||||
|
_tmp_nl_processor: Set[NLProcessor] = set()
|
||||||
|
_tmp_event_handler: Set[EventHandler] = set()
|
||||||
|
|
||||||
|
|
||||||
class Plugin:
|
class Plugin:
|
||||||
__slots__ = ('module', 'name', 'usage', 'commands', 'nl_processors', 'event_handlers')
|
__slots__ = ('module', 'name', 'usage', 'commands', 'nl_processors',
|
||||||
|
'event_handlers')
|
||||||
|
|
||||||
def __init__(self, module: ModuleType,
|
def __init__(self,
|
||||||
|
module: ModuleType,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
usage: Optional[Any] = None,
|
usage: Optional[Any] = None,
|
||||||
commands: Set[Command] = set(),
|
commands: Set[Command] = set(),
|
||||||
@ -27,40 +36,58 @@ class Plugin:
|
|||||||
self.nl_processors = nl_processors
|
self.nl_processors = nl_processors
|
||||||
self.event_handlers = event_handlers
|
self.event_handlers = event_handlers
|
||||||
|
|
||||||
|
|
||||||
class PluginManager:
|
class PluginManager:
|
||||||
_plugins: Dict[str, Plugin] = {}
|
_plugins: Dict[str, Plugin] = {}
|
||||||
_anonymous_plugins: Set[Plugin] = set()
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.cmd_manager = CommandManager()
|
self.cmd_manager = CommandManager()
|
||||||
self.nlp_manager = NLPManager()
|
self.nlp_manager = NLPManager()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_plugin(cls, plugin: Plugin) -> None:
|
def add_plugin(cls, module_path: str, plugin: Plugin) -> None:
|
||||||
"""Register a plugin
|
"""Register a plugin
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
name (str): module path
|
||||||
plugin (Plugin): Plugin object
|
plugin (Plugin): Plugin object
|
||||||
"""
|
"""
|
||||||
if plugin.name:
|
if module_path in cls._plugins:
|
||||||
if plugin.name in cls._plugins:
|
warnings.warn(f"Plugin {module_path} already exists")
|
||||||
warnings.warn(f"Plugin {plugin.name} already exists")
|
return
|
||||||
return
|
cls._plugins[module_path] = plugin
|
||||||
cls._plugins[plugin.name] = plugin
|
|
||||||
else:
|
|
||||||
cls._anonymous_plugins.add(plugin)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_plugin(cls, name: str) -> Optional[Plugin]:
|
|
||||||
return cls._plugins.get(name)
|
|
||||||
|
|
||||||
# TODO: plugin重加载
|
|
||||||
@classmethod
|
|
||||||
def reload_plugin(cls, plugin: Plugin) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def switch_plugin_global(cls, name: str, state: Optional[bool] = None) -> None:
|
def get_plugin(cls, module_path: str) -> Optional[Plugin]:
|
||||||
|
"""Get plugin object by plugin path
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): plugin path
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[Plugin]: Plugin object
|
||||||
|
"""
|
||||||
|
return cls._plugins.get(module_path, None)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def remove_plugin(cls, module_path: str) -> bool:
|
||||||
|
plugin = cls.get_plugin(module_path)
|
||||||
|
if not plugin:
|
||||||
|
warnings.warn(f"Plugin {module_path} not exists")
|
||||||
|
return False
|
||||||
|
for command in plugin.commands:
|
||||||
|
CommandManager.remove_command(command.name)
|
||||||
|
for nl_processor in plugin.nl_processors:
|
||||||
|
NLPManager.remove_nl_processor(nl_processor)
|
||||||
|
for event_handler in plugin.event_handlers:
|
||||||
|
for event in event_handler.events:
|
||||||
|
_bus.unsubscribe(event, event_handler.func)
|
||||||
|
del cls._plugins[module_path]
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def switch_plugin_global(cls, name: str,
|
||||||
|
state: Optional[bool] = None) -> None:
|
||||||
"""Change plugin state globally or simply switch it if `state` is None
|
"""Change plugin state globally or simply switch it if `state` is None
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -79,11 +106,13 @@ class PluginManager:
|
|||||||
for event in event_handler.events:
|
for event in event_handler.events:
|
||||||
if event_handler.func in _bus._subscribers[event] and not state:
|
if event_handler.func in _bus._subscribers[event] and not state:
|
||||||
_bus.unsubscribe(event, event_handler.func)
|
_bus.unsubscribe(event, event_handler.func)
|
||||||
elif event_handler.func not in _bus._subscribers[event] and state != False:
|
elif event_handler.func not in _bus._subscribers[
|
||||||
|
event] and state != False:
|
||||||
_bus.subscribe(event, event_handler.func)
|
_bus.subscribe(event, event_handler.func)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def switch_command_global(cls, name: str, state: Optional[bool] = None) -> None:
|
def switch_command_global(cls, name: str,
|
||||||
|
state: Optional[bool] = None) -> None:
|
||||||
"""Change plugin command state globally or simply switch it if `state` is None
|
"""Change plugin command state globally or simply switch it if `state` is None
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -96,9 +125,10 @@ class PluginManager:
|
|||||||
return
|
return
|
||||||
for command in plugin.commands:
|
for command in plugin.commands:
|
||||||
CommandManager.switch_command_global(command.name, state)
|
CommandManager.switch_command_global(command.name, state)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def switch_nlprocessor_global(cls, name: str, state: Optional[bool] = None) -> None:
|
def switch_nlprocessor_global(cls, name: str,
|
||||||
|
state: Optional[bool] = None) -> None:
|
||||||
"""Change plugin nlprocessor state globally or simply switch it if `state` is None
|
"""Change plugin nlprocessor state globally or simply switch it if `state` is None
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -113,7 +143,8 @@ class PluginManager:
|
|||||||
NLPManager.switch_nlprocessor_global(processor, state)
|
NLPManager.switch_nlprocessor_global(processor, state)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def switch_eventhandler_global(cls, name: str, state: Optional[bool] = None) -> None:
|
def switch_eventhandler_global(cls, name: str,
|
||||||
|
state: Optional[bool] = None) -> None:
|
||||||
"""Change plugin event handler state globally or simply switch it if `state` is None
|
"""Change plugin event handler state globally or simply switch it if `state` is None
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -128,7 +159,8 @@ class PluginManager:
|
|||||||
for event in event_handler.events:
|
for event in event_handler.events:
|
||||||
if event_handler.func in _bus._subscribers[event] and not state:
|
if event_handler.func in _bus._subscribers[event] and not state:
|
||||||
_bus.unsubscribe(event, event_handler.func)
|
_bus.unsubscribe(event, event_handler.func)
|
||||||
elif event_handler.func not in _bus._subscribers[event] and state != False:
|
elif event_handler.func not in _bus._subscribers[
|
||||||
|
event] and state != False:
|
||||||
_bus.subscribe(event, event_handler.func)
|
_bus.subscribe(event, event_handler.func)
|
||||||
|
|
||||||
def switch_plugin(self, name: str, state: Optional[bool] = None) -> None:
|
def switch_plugin(self, name: str, state: Optional[bool] = None) -> None:
|
||||||
@ -151,7 +183,7 @@ class PluginManager:
|
|||||||
self.cmd_manager.switch_command(command.name, state)
|
self.cmd_manager.switch_command(command.name, state)
|
||||||
for nl_processor in plugin.nl_processors:
|
for nl_processor in plugin.nl_processors:
|
||||||
self.nlp_manager.switch_nlprocessor(nl_processor, state)
|
self.nlp_manager.switch_nlprocessor(nl_processor, state)
|
||||||
|
|
||||||
def switch_command(self, name: str, state: Optional[bool] = None) -> None:
|
def switch_command(self, name: str, state: Optional[bool] = None) -> None:
|
||||||
"""Change plugin command state or simply switch it if `state` is None
|
"""Change plugin command state or simply switch it if `state` is None
|
||||||
|
|
||||||
@ -166,7 +198,8 @@ class PluginManager:
|
|||||||
for command in plugin.commands:
|
for command in plugin.commands:
|
||||||
self.cmd_manager.switch_command(command.name, state)
|
self.cmd_manager.switch_command(command.name, state)
|
||||||
|
|
||||||
def switch_nlprocessor(self, name: str, state: Optional[bool] = None) -> None:
|
def switch_nlprocessor(self, name: str,
|
||||||
|
state: Optional[bool] = None) -> None:
|
||||||
"""Change plugin nlprocessor state or simply switch it if `state` is None
|
"""Change plugin nlprocessor state or simply switch it if `state` is None
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -181,41 +214,42 @@ class PluginManager:
|
|||||||
self.nlp_manager.switch_nlprocessor(processor, state)
|
self.nlp_manager.switch_nlprocessor(processor, state)
|
||||||
|
|
||||||
|
|
||||||
def load_plugin(module_name: str) -> Optional[Plugin]:
|
def load_plugin(module_path: str) -> Optional[Plugin]:
|
||||||
"""
|
"""Load a module as a plugin
|
||||||
Load a module as a plugin.
|
|
||||||
|
Args:
|
||||||
:param module_name: name of module to import
|
module_path (str): path of module to import
|
||||||
:return: successful or not
|
|
||||||
|
Returns:
|
||||||
|
Optional[Plugin]: Plugin object loaded
|
||||||
"""
|
"""
|
||||||
|
# Make sure tmp is clean
|
||||||
|
_tmp_command.clear()
|
||||||
|
_tmp_nl_processor.clear()
|
||||||
|
_tmp_event_handler.clear()
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module(module_name)
|
module = importlib.import_module(module_path)
|
||||||
name = getattr(module, '__plugin_name__', None)
|
name = getattr(module, '__plugin_name__', None)
|
||||||
usage = getattr(module, '__plugin_usage__', None)
|
usage = getattr(module, '__plugin_usage__', None)
|
||||||
commands = set()
|
commands = _tmp_command.copy()
|
||||||
nl_processors = set()
|
nl_processors = _tmp_nl_processor.copy()
|
||||||
event_handlers = set()
|
event_handlers = _tmp_event_handler.copy()
|
||||||
for attr in dir(module):
|
plugin = Plugin(module, name, usage, commands, nl_processors,
|
||||||
func = getattr(module, attr)
|
event_handlers)
|
||||||
if isinstance(func, Command):
|
PluginManager.add_plugin(module_path, plugin)
|
||||||
commands.add(func)
|
logger.info(f'Succeeded to import "{module_path}"')
|
||||||
elif isinstance(func, NLProcessor):
|
|
||||||
nl_processors.add(func)
|
|
||||||
elif isinstance(func, EventHandler):
|
|
||||||
event_handlers.add(func)
|
|
||||||
plugin = Plugin(module, name, usage, commands, nl_processors, event_handlers)
|
|
||||||
PluginManager.add_plugin(plugin)
|
|
||||||
logger.info(f'Succeeded to import "{module_name}"')
|
|
||||||
return plugin
|
return plugin
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Failed to import "{module_name}", error: {e}')
|
logger.error(f'Failed to import "{module_path}", error: {e}')
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
# TODO: plugin重加载
|
def reload_plugin(module_path: str) -> Optional[Plugin]:
|
||||||
def reload_plugin(module_name: str) -> Optional[Plugin]:
|
result = PluginManager.remove_plugin(module_path)
|
||||||
pass
|
if not result:
|
||||||
|
return None
|
||||||
|
return load_plugin(module_path)
|
||||||
|
|
||||||
|
|
||||||
def load_plugins(plugin_dir: str, module_prefix: str) -> Set[Plugin]:
|
def load_plugins(plugin_dir: str, module_prefix: str) -> Set[Plugin]:
|
||||||
@ -262,4 +296,121 @@ def get_loaded_plugins() -> Set[Plugin]:
|
|||||||
|
|
||||||
:return: a set of Plugin objects
|
:return: a set of Plugin objects
|
||||||
"""
|
"""
|
||||||
return set(PluginManager._plugins.values()) | PluginManager._anonymous_plugins
|
return set(PluginManager._plugins.values())
|
||||||
|
|
||||||
|
|
||||||
|
def on_command(name: Union[str, CommandName_T],
|
||||||
|
*,
|
||||||
|
aliases: Union[Iterable[str], str] = (),
|
||||||
|
permission: int = perm.EVERYBODY,
|
||||||
|
only_to_me: bool = True,
|
||||||
|
privileged: bool = False,
|
||||||
|
shell_like: bool = False) -> Callable:
|
||||||
|
"""
|
||||||
|
Decorator to register a function as a command.
|
||||||
|
|
||||||
|
:param name: command name (e.g. 'echo' or ('random', 'number'))
|
||||||
|
:param aliases: aliases of command name, for convenient access
|
||||||
|
:param permission: permission required by the command
|
||||||
|
:param only_to_me: only handle messages to me
|
||||||
|
:param privileged: can be run even when there is already a session
|
||||||
|
:param shell_like: use shell-like syntax to split arguments
|
||||||
|
"""
|
||||||
|
|
||||||
|
def deco(func: CommandHandler_T) -> CommandHandler_T:
|
||||||
|
if not isinstance(name, (str, tuple)):
|
||||||
|
raise TypeError('the name of a command must be a str or tuple')
|
||||||
|
if not name:
|
||||||
|
raise ValueError('the name of a command must not be empty')
|
||||||
|
|
||||||
|
cmd_name = (name,) if isinstance(name, str) else name
|
||||||
|
|
||||||
|
cmd = Command(name=cmd_name,
|
||||||
|
func=func,
|
||||||
|
permission=permission,
|
||||||
|
only_to_me=only_to_me,
|
||||||
|
privileged=privileged)
|
||||||
|
|
||||||
|
if shell_like:
|
||||||
|
|
||||||
|
async def shell_like_args_parser(session):
|
||||||
|
session.args['argv'] = shlex.split(session.current_arg)
|
||||||
|
|
||||||
|
cmd.args_parser_func = shell_like_args_parser
|
||||||
|
|
||||||
|
CommandManager.add_command(cmd_name, cmd)
|
||||||
|
CommandManager.add_aliases(aliases, cmd)
|
||||||
|
|
||||||
|
_tmp_command.add(cmd)
|
||||||
|
func.args_parser = cmd.args_parser
|
||||||
|
|
||||||
|
return func
|
||||||
|
|
||||||
|
return deco
|
||||||
|
|
||||||
|
|
||||||
|
def on_natural_language(
|
||||||
|
keywords: Union[Optional[Iterable], str, Callable] = None,
|
||||||
|
*,
|
||||||
|
permission: int = perm.EVERYBODY,
|
||||||
|
only_to_me: bool = True,
|
||||||
|
only_short_message: bool = True,
|
||||||
|
allow_empty_message: bool = False) -> Callable:
|
||||||
|
"""
|
||||||
|
Decorator to register a function as a natural language processor.
|
||||||
|
|
||||||
|
:param keywords: keywords to respond to, if None, respond to all messages
|
||||||
|
:param permission: permission required by the processor
|
||||||
|
:param only_to_me: only handle messages to me
|
||||||
|
:param only_short_message: only handle short messages
|
||||||
|
:param allow_empty_message: handle empty messages
|
||||||
|
"""
|
||||||
|
|
||||||
|
def deco(func: Callable) -> Callable:
|
||||||
|
nl_processor = NLProcessor(
|
||||||
|
func=func,
|
||||||
|
keywords=keywords, # type: ignore
|
||||||
|
permission=permission,
|
||||||
|
only_to_me=only_to_me,
|
||||||
|
only_short_message=only_short_message,
|
||||||
|
allow_empty_message=allow_empty_message)
|
||||||
|
NLPManager.add_nl_processor(nl_processor)
|
||||||
|
_tmp_nl_processor.add(nl_processor)
|
||||||
|
return func
|
||||||
|
|
||||||
|
if isinstance(keywords, Callable):
|
||||||
|
# here "keywords" is the function to be decorated
|
||||||
|
return on_natural_language()(keywords)
|
||||||
|
else:
|
||||||
|
if isinstance(keywords, str):
|
||||||
|
keywords = (keywords,)
|
||||||
|
return deco
|
||||||
|
|
||||||
|
|
||||||
|
def _make_event_deco(post_type: str) -> Callable:
|
||||||
|
|
||||||
|
def deco_deco(arg: Optional[Union[str, Callable]] = None,
|
||||||
|
*events: str) -> Callable:
|
||||||
|
|
||||||
|
def deco(func: Callable) -> Callable:
|
||||||
|
if isinstance(arg, str):
|
||||||
|
events_tmp = list(
|
||||||
|
map(lambda x: f"{post_type}.{x}", [arg] + list(events)))
|
||||||
|
for e in events_tmp:
|
||||||
|
_bus.subscribe(e, func)
|
||||||
|
handler = EventHandler(events_tmp, func)
|
||||||
|
else:
|
||||||
|
_bus.subscribe(post_type, func)
|
||||||
|
handler = EventHandler([post_type], func)
|
||||||
|
_tmp_event_handler.add(handler)
|
||||||
|
return func
|
||||||
|
|
||||||
|
if isinstance(arg, Callable):
|
||||||
|
return deco(arg) # type: ignore
|
||||||
|
return deco
|
||||||
|
|
||||||
|
return deco_deco
|
||||||
|
|
||||||
|
|
||||||
|
on_notice = _make_event_deco('notice')
|
||||||
|
on_request = _make_event_deco('request')
|
||||||
|
@ -5,6 +5,7 @@ except ImportError:
|
|||||||
AsyncIOScheduler = None
|
AsyncIOScheduler = None
|
||||||
|
|
||||||
if AsyncIOScheduler:
|
if AsyncIOScheduler:
|
||||||
|
|
||||||
class Scheduler(AsyncIOScheduler):
|
class Scheduler(AsyncIOScheduler):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
@ -24,7 +24,9 @@ class BaseSession:
|
|||||||
def self_id(self) -> int:
|
def self_id(self) -> int:
|
||||||
return self.event.self_id
|
return self.event.self_id
|
||||||
|
|
||||||
async def send(self, message: Message_T, *,
|
async def send(self,
|
||||||
|
message: Message_T,
|
||||||
|
*,
|
||||||
at_sender: bool = False,
|
at_sender: bool = False,
|
||||||
ensure_private: bool = False,
|
ensure_private: bool = False,
|
||||||
ignore_failure: bool = True,
|
ignore_failure: bool = True,
|
||||||
@ -38,7 +40,10 @@ class BaseSession:
|
|||||||
:param ignore_failure: if any CQHttpError raised, ignore it
|
:param ignore_failure: if any CQHttpError raised, ignore it
|
||||||
:return: the result returned by CQHTTP
|
:return: the result returned by CQHTTP
|
||||||
"""
|
"""
|
||||||
return await send(self.bot, self.event, message,
|
return await send(self.bot,
|
||||||
|
self.event,
|
||||||
|
message,
|
||||||
at_sender=at_sender,
|
at_sender=at_sender,
|
||||||
ensure_private=ensure_private,
|
ensure_private=ensure_private,
|
||||||
ignore_failure=ignore_failure, **kwargs)
|
ignore_failure=ignore_failure,
|
||||||
|
**kwargs)
|
||||||
|
@ -5,5 +5,6 @@ Message_T = Union[str, Dict[str, Any], List[Dict[str, Any]]]
|
|||||||
Expression_T = Union[str, Sequence[str], Callable]
|
Expression_T = Union[str, Sequence[str], Callable]
|
||||||
CommandName_T = Tuple[str, ...]
|
CommandName_T = Tuple[str, ...]
|
||||||
CommandArgs_T = Dict[str, Any]
|
CommandArgs_T = Dict[str, Any]
|
||||||
|
CommandHandler_T = Callable[["CommandSession"], Any]
|
||||||
State_T = Dict[str, Any]
|
State_T = Dict[str, Any]
|
||||||
Filter_T = Callable[[Any], Union[Any, Awaitable[Any]]]
|
Filter_T = Callable[[Any], Union[Any, Awaitable[Any]]]
|
||||||
|
Loading…
Reference in New Issue
Block a user