aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--pyproject.toml2
-rw-r--r--src/infini/doc.py22
-rw-r--r--src/infini/generator.py2
-rw-r--r--src/infini/internal.py16
-rw-r--r--src/infini/loader.py22
-rw-r--r--src/infini/register.py125
-rw-r--r--src/infini/router.py33
-rw-r--r--src/infini/typing.py1
-rw-r--r--tests/test_input.py2
9 files changed, 168 insertions, 57 deletions
diff --git a/pyproject.toml b/pyproject.toml
index 90b9718c..eda4752d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "infini"
-version = "2.1.3"
+version = "2.1.4"
description = "Infini 内容输入输出流框架"
authors = [
{ name = "苏向夜", email = "fu050409@163.com" },
diff --git a/src/infini/doc.py b/src/infini/doc.py
new file mode 100644
index 00000000..d5e4aea3
--- /dev/null
+++ b/src/infini/doc.py
@@ -0,0 +1,22 @@
+from typing import Dict, Optional, TypedDict
+
+
+class Annotation(TypedDict):
+ usage: Optional[str]
+ description: Optional[str]
+ epilog: Optional[str]
+
+
+class Doc:
+ pre_interceptors: Dict[str, Annotation]
+ handlers: Dict[str, Annotation]
+ events: Dict[str, Annotation]
+ global_variables: Dict[str, Annotation]
+ interceptors: Dict[str, Annotation]
+
+ def __init__(self) -> None:
+ self.pre_interceptors = {}
+ self.handlers = {}
+ self.events = {}
+ self.global_variables = {}
+ self.interceptors = {}
diff --git a/src/infini/generator.py b/src/infini/generator.py
index 254f0cdd..e2730ca3 100644
--- a/src/infini/generator.py
+++ b/src/infini/generator.py
@@ -1,5 +1,5 @@
from infini.output import Output
-from infini.typing import Type, Dict, Callable, Union, Optional
+from infini.typing import Dict, Callable, Union, Optional
from infini.exceptions import UnknownEvent, UnknownEventType
from infini.injector import Injector
from jinja2 import Template
diff --git a/src/infini/internal.py b/src/infini/internal.py
index e30bda63..67b77b2a 100644
--- a/src/infini/internal.py
+++ b/src/infini/internal.py
@@ -1,3 +1,4 @@
+from infini.core import Core
from infini.loader import Loader
from infini.register import Register
from infini.typing import List, Optional
@@ -25,3 +26,18 @@ def require(name: str, paths: Optional[List] = None) -> Register:
caller_frame.f_globals[f"{name}_register"] = register
return register
+
+
+def acquire_core() -> Core:
+ caller_frame = inspect.stack()[1][0]
+ caller_file: str = caller_frame.f_globals["__file__"]
+ top_name, *_ = caller_file.split(".")
+ try:
+ core = getattr(sys.modules[top_name], "__infini__")["core"]
+ if not isinstance(core, Core):
+ raise ValueError("Infini stack returned a mismatch instance.")
+ return core
+ except Exception as err:
+ raise RuntimeError(
+ "Infini Runtime is not accessible, perhaps infini core is down."
+ ) from err
diff --git a/src/infini/loader.py b/src/infini/loader.py
index f02dd910..4c1d38fe 100644
--- a/src/infini/loader.py
+++ b/src/infini/loader.py
@@ -99,6 +99,8 @@ class Loader:
interceptors: List[RouterType]
generators: Dict[str, BaseGenerator]
+ _core: Core
+
def __init__(self) -> None:
self.pre_interceptors = []
self.handlers = []
@@ -125,12 +127,15 @@ class Loader:
return register_variables
def prepare(self) -> None:
+ self._core = Core()
_install()
def load(self, name: str) -> ModuleType:
self.prepare()
module = importlib.import_module(name)
+ vars(module)["__infini__"] = {"core": self._core, "loader": self}
+
registers = self._find_register_variables(module)
self.load_from_registers(registers)
if not registers:
@@ -171,7 +176,7 @@ class Loader:
def close(self):
_uninstall()
- def inject_core(self, core: Core):
+ def into_core(self) -> Core:
pre_interceptor = Interceptor()
handler = Handler()
generator = TextGenerator()
@@ -184,16 +189,13 @@ class Loader:
self.inject_generator(generator)
self.inject_interceptor(interceptor)
self.inject_injector(injector)
- core.pre_interceptor = pre_interceptor
- core.handler = handler
- core.generator = generator
- core.interceptor = interceptor
- core.injector = injector
+ self._core.pre_interceptor = pre_interceptor
+ self._core.handler = handler
+ self._core.generator = generator
+ self._core.interceptor = interceptor
+ self._core.injector = injector
- def into_core(self) -> Core:
- core = Core()
- self.inject_core(core)
- return core
+ return self._core
def inject_register(self, register: Register):
register.pre_interceptors = self.pre_interceptors
diff --git a/src/infini/register.py b/src/infini/register.py
index 0d85c3c0..ab6762e7 100644
--- a/src/infini/register.py
+++ b/src/infini/register.py
@@ -1,3 +1,4 @@
+from infini.doc import Doc
from infini.typing import List, Dict, Any, Callable, RouterType, Optional, Union, Type
from infini.input import Input
from infini.output import Output
@@ -14,6 +15,8 @@ class Register:
interceptors: List[RouterType]
generators: Dict[str, BaseGenerator]
+ doc: Doc
+
def __init__(self) -> None:
self.pre_interceptors = []
self.handlers = []
@@ -21,89 +24,151 @@ class Register:
self.global_variables = {}
self.interceptors = []
self.generators = {}
-
- def pre_interceptor(self, router: Union[Router, str], priority: int = 0):
+ self.doc = Doc()
+
+ def pre_interceptor(
+ self,
+ router: Union[Router, str],
+ *,
+ priority: int = 0,
+ namespace: Optional[str] = None,
+ usage: Optional[str] = None,
+ description: Optional[str] = None,
+ epilog: Optional[str] = None,
+ ):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs) -> Union[Input, Output]:
return func(*args, **kwargs)
+ _router = Contains(router) if isinstance(router, str) else router
self.pre_interceptors.append(
{
"priority": priority,
- "router": Contains(router) if isinstance(router, str) else router,
+ "router": _router,
"handler": wrapper,
}
)
+ self.doc.pre_interceptors[
+ namespace or _router.namespace or func.__name__
+ ] = {
+ "usage": usage,
+ "description": description,
+ "epilog": epilog,
+ }
return wrapper
return decorator
- def handler(self, router: Union[Router, str], priority: int = 0):
+ def handler(
+ self,
+ router: Union[Router, str],
+ *,
+ priority: int = 0,
+ namespace: Optional[str] = None,
+ usage: Optional[str] = None,
+ description: Optional[str] = None,
+ epilog: Optional[str] = None,
+ ):
+ """注册一个业务函数"""
+
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs) -> Output:
return func(*args, **kwargs)
+ _router = Contains(router) if isinstance(router, str) else router
self.handlers.append(
{
"priority": priority,
- "router": Contains(router) if isinstance(router, str) else router,
+ "router": _router,
"handler": wrapper,
}
)
+ self.doc.handlers[namespace or _router.namespace or func.__name__] = {
+ "usage": usage,
+ "description": description,
+ "epilog": epilog,
+ }
return wrapper
return decorator
- def regist_textevent(self, name: str, text: str):
- import warnings
-
- warnings.warn(
- "Infini will soon deprecated `regist_textevent`, "
- "use `register_textevent` instead."
- )
- self.events[name] = text
-
- def register_textevent(self, name: str, text: str):
+ def register_textevent(
+ self, name: str, text: str, *, description: Optional[str] = None
+ ):
self.events[name] = text
-
- def regist_variable(self, name: str, data: Any):
- import warnings
-
- warnings.warn(
- "Infini will soon deprecated `regist_variable`, "
- "use `register_variable` instead."
- )
+ self.doc.events[name] = {
+ "usage": None,
+ "description": description,
+ "epilog": None,
+ }
+
+ def register_variable(
+ self,
+ name: str,
+ data: Any,
+ *,
+ usage: Optional[str] = None,
+ description: Optional[str] = None,
+ ):
self.global_variables[name] = data
-
- def register_variable(self, name: str, data: Any):
- self.global_variables[name] = data
-
- def dynamic_variable(self, name: Optional[str] = None):
+ self.doc.global_variables[name] = {
+ "usage": usage,
+ "description": description,
+ "epilog": None,
+ }
+
+ def dynamic_variable(
+ self,
+ name: Optional[str] = None,
+ *,
+ usage: Optional[str] = None,
+ description: Optional[str] = None,
+ ):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs) -> str:
return func(*args, **kwargs)
self.global_variables[name or func.__name__] = wrapper
+ self.doc.global_variables[name or func.__name__] = {
+ "usage": usage,
+ "description": description,
+ "epilog": None,
+ }
return wrapper
return decorator
- def interceptor(self, router: Union[Router, str], priority: int = 0):
+ def interceptor(
+ self,
+ router: Union[Router, str],
+ *,
+ priority: int = 0,
+ namespace: Optional[str] = None,
+ usage: Optional[str] = None,
+ description: Optional[str] = None,
+ epilog: Optional[str] = None,
+ ):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs) -> Union[Input, Output]:
return func(*args, **kwargs)
+ _router = Contains(router) if isinstance(router, str) else router
self.interceptors.append(
{
"priority": priority,
- "router": Contains(router) if isinstance(router, str) else router,
+ "router": _router,
"handler": wrapper,
}
)
+ self.doc.interceptors[namespace or _router.namespace or func.__name__] = {
+ "usage": usage,
+ "description": description,
+ "epilog": epilog,
+ }
return wrapper
return decorator
diff --git a/src/infini/router.py b/src/infini/router.py
index 71da44e2..4e025a15 100644
--- a/src/infini/router.py
+++ b/src/infini/router.py
@@ -1,14 +1,16 @@
-from infini.typing import Sequence, Literal
+from typing import Optional
+from infini.typing import Sequence, Literal, Tuple
from infini.input import Input
class Router:
- type: Literal["normal"] = "normal"
- signs: set[str]
+ type: Literal["text"] = "text"
+ signs: Tuple[str, ...]
def __init__(self, sign: str, alias: Sequence[str] = []) -> None:
- self.signs = {sign}
- self.signs.update(alias)
+ signs = {sign}
+ signs.update(alias)
+ self.signs = tuple(signs)
def __eq__(self, __router: "Router") -> bool:
return __router.type == self.type and __router.signs == self.signs
@@ -17,9 +19,13 @@ class Router:
text = plain_text.strip()
return any([text == sign for sign in self.signs])
+ @property
+ def namespace(self) -> Optional[str]:
+ return self.signs[0] if self.signs else None
+
class Startswith(Router):
- type: Literal["startswith"] = "startswith"
+ name: Literal["startswith"] = "startswith"
def match(self, plain_text: str) -> bool:
text = plain_text.strip()
@@ -27,14 +33,14 @@ class Startswith(Router):
class Contains(Router):
- type: Literal["contains"] = "contains"
+ name: Literal["contains"] = "contains"
def match(self, plain_text: str) -> bool:
return any([sign in plain_text for sign in self.signs])
class Endswith(Router):
- type: Literal["endswith"] = "endswith"
+ name: Literal["endswith"] = "endswith"
def match(self, input: Input) -> bool:
text = input.get_plain_text().strip()
@@ -42,14 +48,13 @@ class Endswith(Router):
class Command(Router):
- type: Literal["command"] = "command"
- prefix: tuple = (".", "/")
+ name: Literal["command"] = "command"
+ prefix: tuple = (".", "/", "。", "!", "!")
def match(self, input: Input) -> bool:
text = input.get_plain_text().strip()
- if text:
- if text.startswith(self.prefix):
- text = text[1:]
- return any([text.startswith(sign) for sign in self.signs])
+ if text.startswith(self.prefix):
+ text = text[1:]
+ return any([text.startswith(sign) for sign in self.signs])
return False
diff --git a/src/infini/typing.py b/src/infini/typing.py
index 14c219fc..6ba7f7f4 100644
--- a/src/infini/typing.py
+++ b/src/infini/typing.py
@@ -3,6 +3,7 @@ from typing import (
Dict as Dict,
List as List,
Any as Any,
+ Tuple as Tuple,
Type as Type,
Optional as Optional,
Generic as Generic,
diff --git a/tests/test_input.py b/tests/test_input.py
index 5f44ca1e..88a7ceb5 100644
--- a/tests/test_input.py
+++ b/tests/test_input.py
@@ -13,4 +13,4 @@ def test_new_input_with_session_id():
def test_new_input_without_session_id():
input = Input("test plain_str", variables={"user_id": "test"})
- assert input.get_session_id() == "session_unknown_test"
+ assert input.get_session_id() == "test"