melobot.di

依赖注入部件

class melobot.di.Depends[源代码]

基类:Generic[T, U]

__init__(dep: SyncOrAsyncCallable[(), Any] | Depends[Any], sub_getter: SyncOrAsyncCallable[typing_extensions.Any, Any] | None = None, cache: bool = False, recursive: bool = True) None[源代码]

初始化一个依赖项

参数:
  • dep (SyncOrAsyncCallable[(), Any] | Depends[Any]) -- 依赖来源(可调用对象,异步可调用对象,或依赖项)

  • sub_getter (SyncOrAsyncCallable[(typing_extensions.Any,), Any] | None) -- 子获取器(可调用对象,异步可调用对象或空),在获得依赖之后,于其上继续获取

  • cache (bool) -- 是否启用缓存

  • recursive (bool) -- 是否启用递归满足(默认启用,如果 depsub_getter 为可调用对象,会自动被 {func}`.inject_deps` 装饰;关闭可节约性能)

返回类型:

None

class melobot.di.CbDepends[源代码]

基类:Depends, BetterABC, Generic[T]

回调型依赖

依赖项,但在依赖满足后,执行内部的回调

__init__(dep: SyncOrAsyncCallable[(), Any], cache: bool = False, recursive: bool = False) None[源代码]
参数:
返回类型:

None

abstract async deps_callback(val: Any) T[源代码]

所有子类必须实现该抽象方法

参数:

val (Any) -- 依赖项被满足后的值

返回:

处理后的值,作为依赖项最终的值

返回类型:

T

melobot.di.inject_deps(injectee: SyncOrAsyncCallable[..., T], manual_arg: bool = False, avoid_repeat: bool = False) AsyncCallable[..., T][源代码]

依赖注入标记装饰器,标记当前对象需要被依赖注入

可以标记的对象类别有: 同步函数,异步函数,匿名函数,同步生成器函数,异步生成器函数,实例方法、类方法、静态方法

参数:
  • injectee (SyncOrAsyncCallable[..., T]) -- 需要被注入的对象

  • manual_arg (bool) -- 当前对象标记需要依赖注入后,是否还可以给某些参数手动传参

  • avoid_repeat (bool) -- 是否避免在多层装饰时重复注入。检查内层装饰链,若内层装饰已有注入则放弃本次注入。 但需要所有内层装饰使用 functools.wraps() 进行包装,否则无法检测

返回:

异步可调用对象,但保留原始参数和返回值签名

返回类型:

AsyncCallable[..., T]

依赖注入元数据标记

依赖注入时用作 Annotated 元数据,只能对自动依赖使用。也就是说不能和 Depends 同时放在 Annotated 中。

class melobot.di.Exclude[源代码]

基类:object

数据类。types 指定的类别会在依赖注入时被排除

# 假设有 B 继承于 A, C 继承于 A, D 继承于 A
# 表示不包括 B 和 C 类别的 A 的所有子类型:
NewTypeHint = Annotated[A, Exclude(types=[B, C])]
# 当然,依然会兼容 A 类型
types: Sequence[type]
class melobot.di.Reflect[源代码]

基类:object

数据类。指定不直接获取当前依赖项,而是获取对应的一个反射代理

这适用于希望依赖会随着上下文改变,而动态变化的情况。例如动态引用会话流程中的事件对象

# 注入一个依赖时进一步包装为反射依赖
ReflectedEvent = Annotated[Event, Reflect()]
event_proxy: RefelectedEvent
# 就像使用 event 一样使用 event_proxy
event_proxy.attr_xxx
event_proxy.method_xxx()

# 不过 event_proxy 不是完美的代理
# 因此 isinstance 类似的操作,使用 __origin__ 获取原始对象
isinstance(event_proxy.__origin__, SomeEventType)
# 或者是作为运行逻辑未知的函数的参数
dont_know_what_this_do(event_proxy.__origin__)
class melobot.di.MatchEvent[源代码]

基类:object

数据类。指定从当前事件的上下文中获取依赖

默认情况下,获取 Adapter 依赖都会直接尝试遍历所有可能的对象。

即尽最大可能获取指定类型的对象。但有时需要实现这样的需求:

# 假设 bot 已经加载了两个适配器:ObAdapter 和 XxAdapter
from melobot.handle import on_event
# 期待事件来自 ObAdapter 时,调用这个
@on_event()
async def on_onebot_event(adapter: ObAdapter) -> None: ...
# 期待事件来自 XxAdapter 时,调用这个
@on_event()
async def on_xx_event(adapter: XxAdapter) -> None: ...

# 但默认的逻辑是:bot 只要加载了对应的适配器,依赖就可以满足
# 所以实际上他们都会被调用,没有任何区分效果

# 使用 MatchEvent 来改变依赖获取的逻辑:
# 事件的来源适配器必须和 MatchEvent 中指定的类型匹配,依赖才能满足
@on_event()
async def on_onebot_event(adapter: Annotated[ObAdapter, MatchEvent()]) -> None: ...
@on_event()
async def on_xx_event(adapter: Annotated[XxAdapter, MatchEvent()]) -> None: ...