🔀 Merge pull request #45

add pre and post processors
This commit is contained in:
Ju4tCode 2020-11-07 17:56:01 +08:00 committed by GitHub
commit b87df479a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 159 additions and 24 deletions

View File

@ -110,7 +110,7 @@ sidebarDepth: 0
## `PreProcessor` ## `EventPreProcessor`
* **类型** * **类型**
@ -121,7 +121,55 @@ sidebarDepth: 0
* **说明** * **说明**
消息预处理函数 PreProcessor 类型 事件预处理函数 EventPreProcessor 类型
## `EventPostProcessor`
* **类型**
`Callable[[Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]`
* **说明**
事件预处理函数 EventPostProcessor 类型
## `RunPreProcessor`
* **类型**
`Callable[[Matcher, Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]`
* **说明**
事件响应器运行前预处理函数 RunPreProcessor 类型
## `RunPostProcessor`
* **类型**
`Callable[[Matcher, List[Any], Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]`
* **说明**
事件响应器运行前预处理函数 RunPostProcessor 类型,第二个参数包含运行时产生的错误以及 `ExpiredException`, `StopPropagation` (如果存在)

View File

@ -5,19 +5,37 @@ from nonebot.log import logger
from nonebot.rule import TrieRule from nonebot.rule import TrieRule
from nonebot.utils import escape_tag from nonebot.utils import escape_tag
from nonebot.matcher import matchers from nonebot.matcher import matchers
from nonebot.typing import Set, Type, Union, NoReturn
from nonebot.typing import Bot, Event, Matcher, PreProcessor
from nonebot.exception import IgnoredException, ExpiredException from nonebot.exception import IgnoredException, ExpiredException
from nonebot.exception import StopPropagation, _ExceptionContainer from nonebot.exception import StopPropagation, _ExceptionContainer
from nonebot.typing import Set, Type, Union, NoReturn, Bot, Event, Matcher
from nonebot.typing import EventPreProcessor, RunPreProcessor, EventPostProcessor, RunPostProcessor
_event_preprocessors: Set[PreProcessor] = set() _event_preprocessors: Set[EventPreProcessor] = set()
_event_postprocessors: Set[EventPostProcessor] = set()
_run_preprocessors: Set[RunPreProcessor] = set()
_run_postprocessors: Set[RunPostProcessor] = set()
def event_preprocessor(func: PreProcessor) -> PreProcessor: def event_preprocessor(func: EventPreProcessor) -> EventPreProcessor:
_event_preprocessors.add(func) _event_preprocessors.add(func)
return func return func
def event_postprocessor(func: EventPostProcessor) -> EventPostProcessor:
_event_postprocessors.add(func)
return func
def run_preprocessor(func: RunPreProcessor) -> RunPreProcessor:
_run_preprocessors.add(func)
return func
def run_postprocessor(func: RunPostProcessor) -> RunPostProcessor:
_run_postprocessors.add(func)
return func
async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event, async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event,
state: dict) -> Union[None, NoReturn]: state: dict) -> Union[None, NoReturn]:
if Matcher.expire_time and datetime.now() > Matcher.expire_time: if Matcher.expire_time and datetime.now() > Matcher.expire_time:
@ -35,7 +53,24 @@ async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event,
logger.info(f"Event will be handled by {Matcher}") logger.info(f"Event will be handled by {Matcher}")
matcher = Matcher() matcher = Matcher()
# TODO: BeforeMatcherRun
coros = list(
map(lambda x: x(matcher, bot, event, state), _run_preprocessors))
if coros:
try:
await asyncio.gather(*coros)
except IgnoredException:
logger.opt(colors=True).info(
f"Matcher {matcher} running is <b>cancelled</b>")
return
except Exception as e:
logger.opt(colors=True, exception=e).error(
"<r><bg #f8bbd0>Error when running RunPreProcessors. "
"Running cancelled!</bg #f8bbd0></r>")
return
exceptions = []
try: try:
logger.debug(f"Running matcher {matcher}") logger.debug(f"Running matcher {matcher}")
await matcher.run(bot, event, state) await matcher.run(bot, event, state)
@ -43,12 +78,24 @@ async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event,
logger.opt(colors=True, exception=e).error( logger.opt(colors=True, exception=e).error(
f"<r><bg #f8bbd0>Running matcher {matcher} failed.</bg #f8bbd0></r>" f"<r><bg #f8bbd0>Running matcher {matcher} failed.</bg #f8bbd0></r>"
) )
exceptions.append(e)
exceptions = []
if Matcher.temp: if Matcher.temp:
exceptions.append(ExpiredException) exceptions.append(ExpiredException)
if Matcher.block: if Matcher.block:
exceptions.append(StopPropagation) exceptions.append(StopPropagation)
coros = list(
map(lambda x: x(matcher, exceptions, bot, event, state),
_run_postprocessors))
if coros:
try:
await asyncio.gather(*coros)
except Exception as e:
logger.opt(colors=True, exception=e).error(
"<r><bg #f8bbd0>Error when running RunPostProcessors</bg #f8bbd0></r>"
)
if exceptions: if exceptions:
raise _ExceptionContainer(exceptions) raise _ExceptionContainer(exceptions)
@ -77,10 +124,8 @@ async def handle_event(bot: Bot, event: Event):
if show_log: if show_log:
logger.opt(colors=True).info(log_msg) logger.opt(colors=True).info(log_msg)
coros = []
state = {} state = {}
for preprocessor in _event_preprocessors: coros = list(map(lambda x: x(bot, event, state), _event_preprocessors))
coros.append(preprocessor(bot, event, state))
if coros: if coros:
try: try:
logger.debug("Running PreProcessors...") logger.debug("Running PreProcessors...")
@ -89,6 +134,11 @@ async def handle_event(bot: Bot, event: Event):
logger.opt( logger.opt(
colors=True).info(f"Event {event.name} is <b>ignored</b>") colors=True).info(f"Event {event.name} is <b>ignored</b>")
return return
except Exception as e:
logger.opt(colors=True, exception=e).error(
"<r><bg #f8bbd0>Error when running EventPreProcessors. "
"Event ignored!</bg #f8bbd0></r>")
return
# Trie Match # Trie Match
_, _ = TrieRule.get_value(bot, event, state) _, _ = TrieRule.get_value(bot, event, state)
@ -121,3 +171,13 @@ async def handle_event(bot: Bot, event: Event):
) )
del matchers[priority][index - i] del matchers[priority][index - i]
i += 1 i += 1
coros = list(map(lambda x: x(bot, event, state), _event_postprocessors))
if coros:
try:
logger.debug("Running PostProcessors...")
await asyncio.gather(*coros)
except Exception as e:
logger.opt(colors=True, exception=e).error(
"<r><bg #f8bbd0>Error when running EventPostProcessors</bg #f8bbd0></r>"
)

View File

@ -92,14 +92,41 @@ MessageSegment = TypeVar("MessageSegment", bound="BaseMessageSegment")
所有 MessageSegment 的基类 所有 MessageSegment 的基类
""" """
PreProcessor = Callable[[Bot, Event, dict], Union[Awaitable[None], EventPreProcessor = Callable[[Bot, Event, dict], Union[Awaitable[None],
Awaitable[NoReturn]]] Awaitable[NoReturn]]]
""" """
:类型: ``Callable[[Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]`` :类型: ``Callable[[Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]``
:说明: :说明:
消息预处理函数 PreProcessor 类型 事件预处理函数 EventPreProcessor 类型
"""
EventPostProcessor = Callable[[Bot, Event, dict], Union[Awaitable[None],
Awaitable[NoReturn]]]
"""
:类型: ``Callable[[Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]``
:说明:
事件预处理函数 EventPostProcessor 类型
"""
RunPreProcessor = Callable[["Matcher", Bot, Event, dict],
Union[Awaitable[None], Awaitable[NoReturn]]]
"""
:类型: ``Callable[[Matcher, Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]``
:说明:
事件响应器运行前预处理函数 RunPreProcessor 类型
"""
RunPostProcessor = Callable[["Matcher", List[Any], Bot, Event, dict],
Union[Awaitable[None], Awaitable[NoReturn]]]
"""
:类型: ``Callable[[Matcher, List[Any], Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]``
:说明:
事件响应器运行前预处理函数 RunPostProcessor 类型第二个参数包含运行时产生的错误以及 ``ExpiredException``, ``StopPropagation`` (如果存在)
""" """
Matcher = TypeVar("Matcher", bound="MatcherClass") Matcher = TypeVar("Matcher", bound="MatcherClass")

20
poetry.lock generated
View File

@ -73,15 +73,15 @@ reference = "aliyun"
[[package]] [[package]]
name = "attrs" name = "attrs"
version = "20.2.0" version = "20.3.0"
description = "Classes Without Boilerplate" description = "Classes Without Boilerplate"
category = "main" category = "main"
optional = true optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras] [package.extras]
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"]
docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] docs = ["furo", "sphinx", "zope.interface"]
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
@ -630,7 +630,7 @@ reference = "aliyun"
[[package]] [[package]]
name = "nb-cli" name = "nb-cli"
version = "0.1.0" version = "0.2.0"
description = "CLI for nonebot2" description = "CLI for nonebot2"
category = "main" category = "main"
optional = true optional = true
@ -641,7 +641,7 @@ click = ">=7.1.2,<8.0.0"
colorama = ">=0.4.3,<0.5.0" colorama = ">=0.4.3,<0.5.0"
cookiecutter = ">=1.7.2,<2.0.0" cookiecutter = ">=1.7.2,<2.0.0"
docker-compose = ">=1.27.2,<2.0.0" docker-compose = ">=1.27.2,<2.0.0"
nonebot2 = ">=2.0.0-alpha.1,<3.0.0" nonebot2 = ">=2.0.0-alpha.4,<3.0.0"
pyfiglet = ">=0.8.post1,<0.9" pyfiglet = ">=0.8.post1,<0.9"
pyinquirer = "1.0.3" pyinquirer = "1.0.3"
@ -1515,7 +1515,7 @@ test = ["nonebot-test"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.7" python-versions = "^3.7"
content-hash = "70521f44e1004cf7bc3863c5d249e18d31ff526bf4420f38cd1f81ae2cf561fb" content-hash = "3760d7d6c8119c6fa29e171cabbecc5e705d2bb3faff82f7211a19e27925abfe"
[metadata.files] [metadata.files]
aiofiles = [ aiofiles = [
@ -1535,8 +1535,8 @@ arrow = [
{file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"}, {file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"},
] ]
attrs = [ attrs = [
{file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"},
{file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"},
] ]
babel = [ babel = [
{file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"}, {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"},
@ -1761,8 +1761,8 @@ markupsafe = [
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
] ]
nb-cli = [ nb-cli = [
{file = "nb-cli-0.1.0.tar.gz", hash = "sha256:5106212dd0bae270fc547a59f8c75e20951b9fbd87af263d647f8474677a2e26"}, {file = "nb-cli-0.2.0.tar.gz", hash = "sha256:d53ab571beee259af99a8cb4574ef85b6c1d821549f857eb45c83b3cb4f903a4"},
{file = "nb_cli-0.1.0-py3-none-any.whl", hash = "sha256:a5b5f72bd68b48da446d56623e16b08a3483c84840b3a191771cd9b3e6fde8e9"}, {file = "nb_cli-0.2.0-py3-none-any.whl", hash = "sha256:c0975f18bb19da99278ea60c48b668fc6e5fa371b118e8e86d42e989933186ba"},
] ]
nonebot-test = [ nonebot-test = [
{file = "nonebot-test-0.1.0.tar.gz", hash = "sha256:f83bc095927f55e55cfe61c2ccc388e2536980d6d40412879009a16484487af4"}, {file = "nonebot-test-0.1.0.tar.gz", hash = "sha256:f83bc095927f55e55cfe61c2ccc388e2536980d6d40412879009a16484487af4"},