aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author简律纯 <i@jyunko.cn>2023-12-15 10:15:59 +0800
committerGitHub <noreply@github.com>2023-12-15 10:15:59 +0800
commit5cf3a4a5ca8adc6db3e95a1cd01502b5167bb88f (patch)
tree7ded1b558cc5c7ca0b7ac5973f447ea8c590c581
parent4dafb0f0a81255193f2a44df5d203239325e2236 (diff)
parentf7f775b4c529b1d65e55a12ee6b4e7c6c636f004 (diff)
downloadinfini-5cf3a4a5ca8adc6db3e95a1cd01502b5167bb88f.tar.gz
infini-5cf3a4a5ca8adc6db3e95a1cd01502b5167bb88f.zip
Merge pull request #40 from HydroRoll-Team/sourcery/pull-39
🎉 阶段性完成 (Sourcery refactored)
-rw-r--r--README.md35
-rw-r--r--codehere.bat2
-rw-r--r--mkdocs.yml2
-rw-r--r--pyproject.toml6
-rw-r--r--src/infini/__main__.py56
-rw-r--r--src/infini/consts/templates.py74
-rw-r--r--src/infini/event.py30
-rw-r--r--src/infini/exceptions.py12
-rw-r--r--src/infini/handler.py47
-rw-r--r--src/infini/logging.py15
-rw-r--r--src/infini/matcher.py31
-rw-r--r--src/infini/utils/cli.py23
-rw-r--r--src/infini/utils/gui.py2
13 files changed, 243 insertions, 92 deletions
diff --git a/README.md b/README.md
index 5b69d574..1a43f5ac 100644
--- a/README.md
+++ b/README.md
@@ -41,25 +41,16 @@
2. 创建规则包实例
- 创建`cli.py`并写入以下内容:
-
- ```python
- import infini
-
- client = infini.Cli()
- client.parse_args()
- ```
-
- 打开终端并执行:
+ 确保你的`infini`正确安装后,打开终端并执行:
``` shell
- python cli.py --new --path MyRule
+ python -m infini new MyRule
```
- 你可以在生成的 `MyRule\rule.py` 创建一个或者多个 `rule` 实例并继承 `Rule` 基类, 通过编写合适的相关方法与类注册规则包实现规则的自定义。
+ 你可以在生成的 `MyRule\rule.py` 创建一个或者多个继承 `Handler` 基类的实例, 通过编写合适的相关方法与类注册规则包实现规则的自定义。
``` python
- from infini import Rule, Result, Dice
+ from infini import Handler, Result
class MyRule(Rule):
"""自设规则包"""
@@ -70,14 +61,24 @@
def __init__(self) -> None:
"""初始化你的规则包"""
- def check(self, dice: Dice) -> Result:
- """声明规则包检定方式"""
+ def process(self, **kwargs) -> Result:
+ """声明规则包运行方式"""
return Result("event1", True)
```
- `check`函数应当返回一个`Result`对象,它应当包含一个消息事件名(例如示例中的`event1`),该消息事件名应当在 `MyRule\event.py` 中被注册。消息事件的动态内容通过`{name}`的方式声明并通过`name="内容"`的方式实现。
+ `process`函数应当返回一个`Result`对象,它应当包含一个消息事件名(例如示例中的`event1`),该消息事件名应当在 `MyRule\event.py` 中被注册。消息事件的动态内容通过`{name}`的方式声明并通过`name="内容"`的方式实现。
+
+3. 创建你的测试文件
-3. 合理修改你的 `config.toml` 配置文件,完成注册!
+ 在 `MyRule\tests.py` 中的 `test` 函数中给出测试函数,并返回一个 `list`,应当包含所有异常内容。
+
+4. 测试你的规则包
+
+ 执行指令:
+
+ ```bash
+ python -m infini test MyRule
+ ```
### 🎍Sites
diff --git a/codehere.bat b/codehere.bat
new file mode 100644
index 00000000..976c1ef2
--- /dev/null
+++ b/codehere.bat
@@ -0,0 +1,2 @@
+@echo off
+code . \ No newline at end of file
diff --git a/mkdocs.yml b/mkdocs.yml
index e44d97d7..5c80514e 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,4 +1,4 @@
-site_name: infini 核心文档
+site_name: Infini 核心文档
repo_url: https://github.com/HydroRoll-Team/infini
repo_name: HydroRoll-Team/infini
edit_uri: edit/master/docs/
diff --git a/pyproject.toml b/pyproject.toml
index a7f20ffd..22d90c98 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,10 @@
[project]
name = "infini"
version = "1.0.4"
-description = "The `Core` of `HydroRoll`, the `Loader` of your rules packages."
-authors = [{ name = "简律纯", email = "i@jyunko.cn" }]
+description = "Infini 核心标准输入输出模块"
+authors = [{ name = "简律纯", email = "i@jyunko.cn" }, { name = "苏向夜", email = "fu050409@163.com" }]
dependencies = ["reportlab[pycairo]>=4.0.5", "pydantic>=2.4.2", "loguru>=0.7.2"]
-requires-python = ">=3.8"
+requires-python = ">=3.9"
readme = "README.md"
license = { text = "MIT" }
diff --git a/src/infini/__main__.py b/src/infini/__main__.py
new file mode 100644
index 00000000..5c4dc2eb
--- /dev/null
+++ b/src/infini/__main__.py
@@ -0,0 +1,56 @@
+from pathlib import Path
+from .utils.cli import parse_args
+from .consts import templates
+from .logging import logger
+
+import os
+import importlib
+import sys
+
+
+def main():
+ args = parse_args()
+
+ if args.gui:
+ logger.critical("选项[--gui]尚未被支持!")
+ sys.exit(1)
+
+ path = Path(args.path).resolve() if args.path else Path(os.getcwd()).resolve()
+
+ if args.operate == "new":
+ if path.exists() and not args.force:
+ logger.error("指定的文件夹已经存在!")
+ sys.exit(1)
+
+ path.mkdir(parents=True, exist_ok=True)
+ (path / "handler.py").write_text(templates.RULE, encoding="utf-8")
+ (path / "event.py").write_text(templates.EVENT, encoding="utf-8")
+ (path / "tests.py").write_text(templates.TEST, encoding="utf-8")
+
+ logger.success("HydroRoll 规则包模板已创建!")
+
+ if args.operate == "test":
+ logger.info(f"开始测试规则包: {path.name}...")
+ sys.path.append(str(path))
+ logger.info("初始化规则包中...")
+ try:
+ importlib.import_module("event")
+ importlib.import_module("handler")
+ except Exception as error:
+ if args.verbose:
+ logger.exception(error)
+ logger.critical(f"初始化规则包时出现异常: {error}")
+ return
+ try:
+ errors = importlib.import_module("tests").test()
+ except Exception as error:
+ if args.verbose:
+ logger.exception(error)
+ logger.critical(f"测试规则包时出现异常: {error}")
+ return
+ sys.path.remove(str(path))
+ logger.info(f"测试规则包 {path.name} 出现 {len(errors)} 个异常, 测试完成.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/infini/consts/templates.py b/src/infini/consts/templates.py
index e2edc2d6..d25894ae 100644
--- a/src/infini/consts/templates.py
+++ b/src/infini/consts/templates.py
@@ -1,69 +1,37 @@
-RULE = """from infini import Rule, Result, Dice
+RULE = """from infini import Handler, Result
+__handlers__ = ["HandlerRule"]
-class MyRule(Rule):
- \"\"\"自设规则包\"\"\"
- name = "MyRule"
- priority: int = 0
+class HandlerRule(Handler):
+ \"\"\"自设业务函数\"\"\"
- def __init__(self) -> None:
- \"\"\"初始化你的规则包\"\"\"
+ name = "MyRule" # 规则包名
+ priority: int = 0 # 规则包权重
- def check(self, dice: Dice) -> Result:
+ def process(self, **kwargs) -> Result:
\"\"\"声明规则包检定方式\"\"\"
- return Result("myevent.event1", True)
+ return Result("event1", True)
"""
-EVENT = """from infini import Event
+EVENT = """from infini import MessageEvent
__events__ = ["MyEvent"]
-class MyEvent(Event):
+class MyEvent(MessageEvent):
name = "event1"
output = "检定成功!"
"""
-DICE = """from infini import Dice
-
-import random
-import re
-
-
-class BaseDice(Dice):
- \"\"\"多面骰\"\"\"
-
- def __init__(self, roll_string: str = "") -> None:
- self.roll_string = roll_string
- self.parse()
-
- def parse(self) -> "Dice":
- self.dices = []
- split = re.split(r"[dD]", self.roll_string)
-
- if split[0]:
- self.a = int(split[0])
- else:
- self.a = 1
-
- if split[1]:
- self.b = int(split[1])
- else:
- self.b = 100
-
- self.db = f"{self.a}D{self.b}"
- self.dices += [f"D{self.b}"] * self.a
- return self
-
- def roll(self) -> int:
- self.results = []
-
- for _ in range(self.a):
- result = random.randint(1, self.b)
-
- self.results.append(result)
-
- self.outcome = sum(self.results)
- return self.outcome
-"""
+TEST = """from infini.matcher import matcher, MatcherEvent
+
+def test():
+ event = MatcherEvent("MyRule")
+ try:
+ matcher.run(event)
+ except Exception as error:
+ return [error]
+ finally:
+ return []
+""" \ No newline at end of file
diff --git a/src/infini/event.py b/src/infini/event.py
index 9ce34bd9..0363ac96 100644
--- a/src/infini/event.py
+++ b/src/infini/event.py
@@ -1,9 +1,10 @@
+from abc import ABCMeta
from .typing import Dict
-from .logging import logger
+from .exceptions import UnknownMessageEvent
import re
-__all__ = ["Event", "events"]
+__all__ = ["MessageEvent", "events"]
class Events:
@@ -17,8 +18,7 @@ class Events:
def process(self, name: str, **kwargs) -> str:
if string := self._events.get(name.lower()):
return self._format(string, **kwargs)
- logger.warning(f"事件[{name.lower()}]不存在,将返回空字符串!")
- return ""
+ raise UnknownMessageEvent(f"事件[{name.lower()}]不存在!")
def _format(self, string: str, **kwargs):
pattern = r"{(.*?)}"
@@ -30,8 +30,8 @@ class Events:
return string
-class Event:
- """事件基类"""
+class MessageEvent(metaclass=ABCMeta):
+ """消息事件基类"""
name: str
output: str
@@ -40,4 +40,20 @@ class Event:
events.regist(cls.name, cls.output)
-events = Events()
+class MatcherEvent:
+ """Matcher 事件"""
+
+ name: str
+ string: str
+ kwargs: dict
+
+ def __init__(self, event_name: str, string: str | None = None, **kwargs):
+ self.name = event_name
+ self.string = string or ""
+ self.kwargs = kwargs
+
+ def __repr__(self) -> str:
+ return f"<MatcherEvent [{self.name}]>"
+
+
+events = Events() \ No newline at end of file
diff --git a/src/infini/exceptions.py b/src/infini/exceptions.py
index 62c88fa1..e7c87b36 100644
--- a/src/infini/exceptions.py
+++ b/src/infini/exceptions.py
@@ -4,3 +4,15 @@ class HydroError(Exception):
class RuleLoadError(HydroError):
"""规则导入错误"""
+
+
+class EventError(HydroError):
+ """事件处理时异常"""
+
+
+class UnknownMatcherEvent(EventError):
+ """未知的给入实现"""
+
+
+class UnknownMessageEvent(EventError):
+ """未知的给出实现""" \ No newline at end of file
diff --git a/src/infini/handler.py b/src/infini/handler.py
new file mode 100644
index 00000000..06d5c5fa
--- /dev/null
+++ b/src/infini/handler.py
@@ -0,0 +1,47 @@
+from abc import ABCMeta, abstractmethod
+from .event import MatcherEvent
+from .typing import Dict
+
+__all__ = ["Result", "Handler"]
+
+
+class Result(metaclass=ABCMeta):
+ """规则包运行结果基类"""
+
+ event: str
+ status: bool
+ kwargs: dict = {}
+
+ def __init__(self, event: str, status: bool, **kwargs) -> None:
+ self.event = event
+ self.status = status
+ self.kwargs = kwargs
+
+
+class Handler:
+ """规则包业务基类"""
+
+ name: str
+ priority: int = 0
+
+ def __init_subclass__(cls) -> None:
+ handlers.regist(cls.name, cls())
+
+ @abstractmethod
+ def process(self, event: MatcherEvent) -> Result:
+ raise NotImplementedError
+
+
+class Handlers:
+ """规则包业务集合"""
+
+ _handlers: Dict[str, Handler] = {}
+
+ def regist(self, name: str, handler: Handler) -> None:
+ self._handlers[name.lower()] = handler
+
+ def match(self, name: str) -> Handler | None:
+ return self._handlers.get(name.lower())
+
+
+handlers = Handlers()
diff --git a/src/infini/logging.py b/src/infini/logging.py
index a1458ef4..3c3d2b02 100644
--- a/src/infini/logging.py
+++ b/src/infini/logging.py
@@ -1,6 +1,6 @@
-"""infini 日志。
+"""Infini 日志。
-infini 使用 [loguru](https://github.com/Delgan/loguru) 来记录日志信息。
+Infini 使用 [loguru](https://github.com/Delgan/loguru) 来记录日志信息。
自定义 logger 请参考 [loguru](https://github.com/Delgan/loguru) 文档。
"""
from datetime import datetime
@@ -12,7 +12,7 @@ from .settings import DEBUG
__all__ = ["logger", "error_or_exception"]
logger = multilogger(
- name="HydroRoll", payload="Core", level="DEBUG" if DEBUG else "INFO"
+ name="Infini", payload="Core", level="DEBUG" if DEBUG else "INFO"
)
current_path = Path(__file__).resolve().parent
LOG_PATH = current_path / "logs"
@@ -26,15 +26,8 @@ logger.add(
def error_or_exception(message: str, exception: Exception, verbose: bool = True):
- # 弃用的方法
- # logger.remove()
- # logger.add(
- # sys.stderr,
- # format="<magenta>{time:YYYY-MM-DD HH:mm:ss.SSS}</magenta> <level>[{level}]</level> > <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
- # )
-
if verbose:
logger.exception(exception)
logger.critical(message)
else:
- logger.critical(f"{message} {exception!r}")
+ logger.critical(f"{message} {exception!r}") \ No newline at end of file
diff --git a/src/infini/matcher.py b/src/infini/matcher.py
new file mode 100644
index 00000000..7fc5b88a
--- /dev/null
+++ b/src/infini/matcher.py
@@ -0,0 +1,31 @@
+from .event import MatcherEvent, Events, events
+from .handler import Handlers, Handler, handlers
+from .exceptions import UnknownMatcherEvent
+
+
+class Matcher:
+ """事件处理单元"""
+
+ events: Events
+ handlers: Handlers
+
+ def __init__(
+ self, _events: Events | None = None, _handlers: Handlers | None = None
+ ) -> None:
+ self.events = _events if _events else events
+ self.handlers = _handlers if _handlers else handlers
+
+ def match(self, name: str) -> Handler:
+ if handler := self.handlers.match(name):
+ return handler
+ else:
+ raise UnknownMatcherEvent(f"未知的规则包: {name}")
+
+ def run(self, event: MatcherEvent) -> str:
+ result = self.match(event.name).process(event)
+ return self.events.process(
+ result.event, **result.kwargs if result.kwargs else event.kwargs
+ )
+
+
+matcher = Matcher()
diff --git a/src/infini/utils/cli.py b/src/infini/utils/cli.py
new file mode 100644
index 00000000..6a4f9128
--- /dev/null
+++ b/src/infini/utils/cli.py
@@ -0,0 +1,23 @@
+import argparse
+import sys
+
+
+def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
+ parser = argparse.ArgumentParser(prog="Infini CLI", description="Infini 命令行工具")
+
+ parser.add_argument("--gui", action="store_true", help="启用 GUI 模式")
+
+ subparsers = parser.add_subparsers(title="功能件", dest="operate")
+
+ # 子命令 `new`
+ new_parser = subparsers.add_parser("new", help="创建一个 Infini 规则包模板")
+ new_parser.add_argument("path", help="目标位置")
+ new_parser.add_argument("-v", "--verbose", action="store_true", help="异常追踪")
+ new_parser.add_argument("-f", "--force", action="store_true", help="强制创建")
+
+ # 子命令 `test`
+ test_parser = subparsers.add_parser("test", help="测试 Infini 规则包")
+ test_parser.add_argument("path", help="目标位置")
+ test_parser.add_argument("-v", "--verbose", action="store_true", help="异常追踪")
+
+ return parser.parse_args(argv if argv else sys.argv[1:])
diff --git a/src/infini/utils/gui.py b/src/infini/utils/gui.py
new file mode 100644
index 00000000..d7bc24ae
--- /dev/null
+++ b/src/infini/utils/gui.py
@@ -0,0 +1,2 @@
+"""Infini 核心图形界面"""
+# TODO