arclet-letoderea


Namearclet-letoderea JSON
Version 0.13.3 PyPI version JSON
download
home_pageNone
SummaryA high-performance, simple-structured event system, relies on asyncio
upload_time2024-12-14 07:56:47
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseMIT
keywords asyncio event-system dispatch dependency-injection
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Letoderea
[![Licence](https://img.shields.io/github/license/ArcletProject/Letoderea)](https://github.com/ArcletProject/Letoderea/blob/master/LICENSE)
[![PyPI](https://img.shields.io/pypi/v/arclet-letoderea)](https://pypi.org/project/arclet-letoderea)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/arclet-letoderea)](https://www.python.org/)

一个高性能,结构简洁,依赖于 Python内置库`asyncio` 的事件系统, 设计灵感来自[`Graia BroadcastControl`](https://github.com/GraiaProject/BroadcastControl)。

项目仍处于开发阶段,部分内容可能会有较大改变

## 安装
### 从 PyPI 安装
``` bash
pip install arclet-letoderea
```

## 样例

### 基本使用
```python
import asyncio
from arclet.letoderea import es, make_event

@make_event
class TestEvent:
    name = "Letoderea"

@es.on()
async def test_subscriber(name: str):
    print(name)

async def main():
    await es.publish(TestEvent())

asyncio.run(main())
```

### 依赖注入
```python
import asyncio
from arclet.letoderea import es, make_event, Depends

@make_event
class TestEvent:
    name = "Letoderea"

async def get_msg(event):
    return f"Hello, {event.name}"
    
@es.on(TestEvent)
async def test_subscriber(msg: str = Depends(get_msg)):
    print(msg)
    
async def main():
    await es.publish(TestEvent())
     
asyncio.run(main())
```

### 通信
```python
import asyncio
import random
from dataclasses import dataclass
from arclet.letoderea import es, make_event

@make_event
@dataclass
class Event:
    name: str

@dataclass
class RandomData:
    seed: int
    
    __result_type__ = float

@es.define("rand", RandomData).register()
def random_subscriber(seed: int):
    return random.Random(seed).random()

@es.on(Event)
async def event_subscriber(event: Event):
    print(f"Event: {event.name}")
    result = await es.post(RandomData(42))
    if result:
        print(f"Random: {result.value}")

async def main():
    await es.publish(Event("Letoderea"))
    
asyncio.run(main())
```

## 说明

### 事件

- 事件可以是任何对象,只要实现了 `gather` 异步方法, 或使用 `EventSystem.define` 并传入 `supplier` 参数
- `gather` 方法的参数为 `Contexts` 类型,用于传递上下文信息
- 事件可以通过 `gather` 方法将自身想要传递的信息整合进 `Contexts` 中
- 事件可以携带 `Provider` 与 `Auxiliary`,它们会在事件被订阅时注入到订阅者中
- 订阅子类事件时,父类事件的 `Provider` 与 `Auxiliary` 会被继承
- 订阅父类事件时,其子类事件也会被分发给订阅者

### 订阅

- 通过 `Publisher.register`, `EventSystem.on`, `EventSystem.use` 或 `subscribe` 装饰器可以将一个函数注册为事件的订阅者
- 上述方法会返回 `Subscriber` 类型对象,可以通过其 `.dispose` 方法取消订阅
- 订阅者的参数可以是任何类型,事件系统会尝试从 `Contexts` 中查找对应的值并注入
- 默认情况下 `event` 为名字的参数会被注入为事件的实例
- 订阅者可以设置优先级,值越小优先级越高

### 上下文

- `Contexts` 类型是一个 `dict` 的子类,用于传递上下文信息,除此之外与 `dict` 没有区别
- `Contexts` 默认包含 `$event` 键,其值为事件的实例
- `Contexts` 默认包含 `$subscriber` 键,其值为订阅者的实例
- 在订阅者的函数执行后,其结果会被存储在 `Contexts` 中,键为 `$result`
- 若在解析参数时抛出异常,异常值会被存储在 `Contexts` 中,键为 `$error`


### 依赖注入

- `Provider[T]` 负责管理参数的注入, 其会尝试从 `Contexts` 中选择需求的参数返回
- 对于订阅者的每个参数,在订阅者注册后,事件系统会遍历该订阅者拥有的所有 `Provider`,
    并依次调用 `Provider.validate` 方法,如果返回 `True`,则将该 `Provider` 绑定到该参数上。
    当进行依赖解析时,事件系统会遍历该参数绑定的所有 `Provider`,并依次调用 `Provider.__call__` 方法,
    如果返回值不为 `None`,则将该返回值注入到该参数中。
- `Provider.validate` 方法用于验证订阅函数的参数是否为该 `Provider` 可绑定的参数。默认实现为检查目标参数的类型声明是否为 `T`。
    也可以通过重写该方法来实现自定义的验证逻辑。
- `Provider.__call__` 方法用于从 `Contexts` 中获取参数
- 原则上 `Provider` 只负责注入单一类型的参数。若想处理多个类型的参数,可以声明自己为 `Provider[Union[A, B, ...]]` 类型,
    并在 `Provider.validate` 方法中进行自定义的逻辑判断。但更推荐的做法是构造多个 `Provider`,并将其绑定到同一个参数上。
- 对于特殊的辅助器 `Depend`,事件系统会将其作为特殊的 `Provider` 处理,绑定了 `Depend` 的参数在解析时将直接调用设置在
    `Depend` 上的方法。
- `Provider` 可以设置优先级,值越小优先级越高
- 另有 `ProviderFactory`,用于集成多个 `Provider` 的分配,以方便 `event.providers` 的设置

### 事件发布

- 一般情况下通过 `EventSystem.publish` 或 `EventSystem.post` 方法可以发布一个事件让事件系统进行处理
- `publish` 会处理所有合适的订阅者,而 `post` 会在某一个订阅者返回了有效值后停止处理,并返回该值
- `Publisher` 类负责管理订阅者与事件的交互
- `Publisher.validate` 方法用于验证该事件是否为该发布者的订阅者所关注的事件
- `Publisher.emit` 和 `Publisher.bail` 方法用于将事件直接分发给属于自身的订阅者,`emit` 与 `bail` 的区别类似于 `publish` 与 `post`
- `Publisher.supply` 方法用于让事件系统主动获取事件并分发给所有订阅者
- `EventSystem.use`, `EventSystem.publish` 和 `EventSystem.post` 可以指定 `Publisher`
- 通过 `EventSystem.define` 可以便捷的定义发布者,并在 `.use` 等处通过定义的名字引用

### 辅助

- `Auxiliary` 提供了一系列辅助方法,方便事件的处理
- `Auxiliary` 分为 `Judge`, `Supply` 两类:
    - `Judge`: 用于判断此时是否应该处理事件
    - `Supply`: 用于为 `Contexts` 提供额外的信息
- `Auxiliary.scopes` 声明了 `Auxiliary` 的作用域:
    - `prepare`: 表示该 `Auxiliary` 会在依赖注入之前执行
    - `complete`: 表示该 `Auxiliary` 会在依赖注入完成后执行
    - `cleanup`: 表示该 `Auxiliary` 会在事件处理完成后执行
- `Auxiliary` 可以设置优先级,值越小优先级越高
- `Auxiliary` 的 `__call__` 方法多增加了一个 `Interface` 参数,可用于操作 `Contexts` 或 `Provider`, 获取已执行的 `Auxiliary` 等

## 开源协议
本实现以 MIT 为开源协议。

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "arclet-letoderea",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "asyncio, event-system, dispatch, dependency-injection",
    "author": null,
    "author_email": "RF-Tar-Railt <rf_tar_railt@qq.com>",
    "download_url": "https://files.pythonhosted.org/packages/cd/c2/0a51fc3ea27d361c5f37f804e65c90a44cf9af3bdc16ef5c51df99195342/arclet_letoderea-0.13.3.tar.gz",
    "platform": null,
    "description": "# Letoderea\n[![Licence](https://img.shields.io/github/license/ArcletProject/Letoderea)](https://github.com/ArcletProject/Letoderea/blob/master/LICENSE)\n[![PyPI](https://img.shields.io/pypi/v/arclet-letoderea)](https://pypi.org/project/arclet-letoderea)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/arclet-letoderea)](https://www.python.org/)\n\n\u4e00\u4e2a\u9ad8\u6027\u80fd\uff0c\u7ed3\u6784\u7b80\u6d01\uff0c\u4f9d\u8d56\u4e8e Python\u5185\u7f6e\u5e93`asyncio` \u7684\u4e8b\u4ef6\u7cfb\u7edf, \u8bbe\u8ba1\u7075\u611f\u6765\u81ea[`Graia BroadcastControl`](https://github.com/GraiaProject/BroadcastControl)\u3002\n\n\u9879\u76ee\u4ecd\u5904\u4e8e\u5f00\u53d1\u9636\u6bb5\uff0c\u90e8\u5206\u5185\u5bb9\u53ef\u80fd\u4f1a\u6709\u8f83\u5927\u6539\u53d8\n\n## \u5b89\u88c5\n### \u4ece PyPI \u5b89\u88c5\n``` bash\npip install arclet-letoderea\n```\n\n## \u6837\u4f8b\n\n### \u57fa\u672c\u4f7f\u7528\n```python\nimport asyncio\nfrom arclet.letoderea import es, make_event\n\n@make_event\nclass TestEvent:\n    name = \"Letoderea\"\n\n@es.on()\nasync def test_subscriber(name: str):\n    print(name)\n\nasync def main():\n    await es.publish(TestEvent())\n\nasyncio.run(main())\n```\n\n### \u4f9d\u8d56\u6ce8\u5165\n```python\nimport asyncio\nfrom arclet.letoderea import es, make_event, Depends\n\n@make_event\nclass TestEvent:\n    name = \"Letoderea\"\n\nasync def get_msg(event):\n    return f\"Hello, {event.name}\"\n    \n@es.on(TestEvent)\nasync def test_subscriber(msg: str = Depends(get_msg)):\n    print(msg)\n    \nasync def main():\n    await es.publish(TestEvent())\n     \nasyncio.run(main())\n```\n\n### \u901a\u4fe1\n```python\nimport asyncio\nimport random\nfrom dataclasses import dataclass\nfrom arclet.letoderea import es, make_event\n\n@make_event\n@dataclass\nclass Event:\n    name: str\n\n@dataclass\nclass RandomData:\n    seed: int\n    \n    __result_type__ = float\n\n@es.define(\"rand\", RandomData).register()\ndef random_subscriber(seed: int):\n    return random.Random(seed).random()\n\n@es.on(Event)\nasync def event_subscriber(event: Event):\n    print(f\"Event: {event.name}\")\n    result = await es.post(RandomData(42))\n    if result:\n        print(f\"Random: {result.value}\")\n\nasync def main():\n    await es.publish(Event(\"Letoderea\"))\n    \nasyncio.run(main())\n```\n\n## \u8bf4\u660e\n\n### \u4e8b\u4ef6\n\n- \u4e8b\u4ef6\u53ef\u4ee5\u662f\u4efb\u4f55\u5bf9\u8c61\uff0c\u53ea\u8981\u5b9e\u73b0\u4e86 `gather` \u5f02\u6b65\u65b9\u6cd5, \u6216\u4f7f\u7528 `EventSystem.define` \u5e76\u4f20\u5165 `supplier` \u53c2\u6570\n- `gather` \u65b9\u6cd5\u7684\u53c2\u6570\u4e3a `Contexts` \u7c7b\u578b\uff0c\u7528\u4e8e\u4f20\u9012\u4e0a\u4e0b\u6587\u4fe1\u606f\n- \u4e8b\u4ef6\u53ef\u4ee5\u901a\u8fc7 `gather` \u65b9\u6cd5\u5c06\u81ea\u8eab\u60f3\u8981\u4f20\u9012\u7684\u4fe1\u606f\u6574\u5408\u8fdb `Contexts` \u4e2d\n- \u4e8b\u4ef6\u53ef\u4ee5\u643a\u5e26 `Provider` \u4e0e `Auxiliary`\uff0c\u5b83\u4eec\u4f1a\u5728\u4e8b\u4ef6\u88ab\u8ba2\u9605\u65f6\u6ce8\u5165\u5230\u8ba2\u9605\u8005\u4e2d\n- \u8ba2\u9605\u5b50\u7c7b\u4e8b\u4ef6\u65f6\uff0c\u7236\u7c7b\u4e8b\u4ef6\u7684 `Provider` \u4e0e `Auxiliary` \u4f1a\u88ab\u7ee7\u627f\n- \u8ba2\u9605\u7236\u7c7b\u4e8b\u4ef6\u65f6\uff0c\u5176\u5b50\u7c7b\u4e8b\u4ef6\u4e5f\u4f1a\u88ab\u5206\u53d1\u7ed9\u8ba2\u9605\u8005\n\n### \u8ba2\u9605\n\n- \u901a\u8fc7 `Publisher.register`, `EventSystem.on`, `EventSystem.use` \u6216 `subscribe` \u88c5\u9970\u5668\u53ef\u4ee5\u5c06\u4e00\u4e2a\u51fd\u6570\u6ce8\u518c\u4e3a\u4e8b\u4ef6\u7684\u8ba2\u9605\u8005\n- \u4e0a\u8ff0\u65b9\u6cd5\u4f1a\u8fd4\u56de `Subscriber` \u7c7b\u578b\u5bf9\u8c61\uff0c\u53ef\u4ee5\u901a\u8fc7\u5176 `.dispose` \u65b9\u6cd5\u53d6\u6d88\u8ba2\u9605\n- \u8ba2\u9605\u8005\u7684\u53c2\u6570\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\uff0c\u4e8b\u4ef6\u7cfb\u7edf\u4f1a\u5c1d\u8bd5\u4ece `Contexts` \u4e2d\u67e5\u627e\u5bf9\u5e94\u7684\u503c\u5e76\u6ce8\u5165\n- \u9ed8\u8ba4\u60c5\u51b5\u4e0b `event` \u4e3a\u540d\u5b57\u7684\u53c2\u6570\u4f1a\u88ab\u6ce8\u5165\u4e3a\u4e8b\u4ef6\u7684\u5b9e\u4f8b\n- \u8ba2\u9605\u8005\u53ef\u4ee5\u8bbe\u7f6e\u4f18\u5148\u7ea7\uff0c\u503c\u8d8a\u5c0f\u4f18\u5148\u7ea7\u8d8a\u9ad8\n\n### \u4e0a\u4e0b\u6587\n\n- `Contexts` \u7c7b\u578b\u662f\u4e00\u4e2a `dict` \u7684\u5b50\u7c7b\uff0c\u7528\u4e8e\u4f20\u9012\u4e0a\u4e0b\u6587\u4fe1\u606f\uff0c\u9664\u6b64\u4e4b\u5916\u4e0e `dict` \u6ca1\u6709\u533a\u522b\n- `Contexts` \u9ed8\u8ba4\u5305\u542b `$event` \u952e\uff0c\u5176\u503c\u4e3a\u4e8b\u4ef6\u7684\u5b9e\u4f8b\n- `Contexts` \u9ed8\u8ba4\u5305\u542b `$subscriber` \u952e\uff0c\u5176\u503c\u4e3a\u8ba2\u9605\u8005\u7684\u5b9e\u4f8b\n- \u5728\u8ba2\u9605\u8005\u7684\u51fd\u6570\u6267\u884c\u540e\uff0c\u5176\u7ed3\u679c\u4f1a\u88ab\u5b58\u50a8\u5728 `Contexts` \u4e2d\uff0c\u952e\u4e3a `$result`\n- \u82e5\u5728\u89e3\u6790\u53c2\u6570\u65f6\u629b\u51fa\u5f02\u5e38\uff0c\u5f02\u5e38\u503c\u4f1a\u88ab\u5b58\u50a8\u5728 `Contexts` \u4e2d\uff0c\u952e\u4e3a `$error`\n\n\n### \u4f9d\u8d56\u6ce8\u5165\n\n- `Provider[T]` \u8d1f\u8d23\u7ba1\u7406\u53c2\u6570\u7684\u6ce8\u5165, \u5176\u4f1a\u5c1d\u8bd5\u4ece `Contexts` \u4e2d\u9009\u62e9\u9700\u6c42\u7684\u53c2\u6570\u8fd4\u56de\n- \u5bf9\u4e8e\u8ba2\u9605\u8005\u7684\u6bcf\u4e2a\u53c2\u6570\uff0c\u5728\u8ba2\u9605\u8005\u6ce8\u518c\u540e\uff0c\u4e8b\u4ef6\u7cfb\u7edf\u4f1a\u904d\u5386\u8be5\u8ba2\u9605\u8005\u62e5\u6709\u7684\u6240\u6709 `Provider`\uff0c\n    \u5e76\u4f9d\u6b21\u8c03\u7528 `Provider.validate` \u65b9\u6cd5\uff0c\u5982\u679c\u8fd4\u56de `True`\uff0c\u5219\u5c06\u8be5 `Provider` \u7ed1\u5b9a\u5230\u8be5\u53c2\u6570\u4e0a\u3002\n    \u5f53\u8fdb\u884c\u4f9d\u8d56\u89e3\u6790\u65f6\uff0c\u4e8b\u4ef6\u7cfb\u7edf\u4f1a\u904d\u5386\u8be5\u53c2\u6570\u7ed1\u5b9a\u7684\u6240\u6709 `Provider`\uff0c\u5e76\u4f9d\u6b21\u8c03\u7528 `Provider.__call__` \u65b9\u6cd5\uff0c\n    \u5982\u679c\u8fd4\u56de\u503c\u4e0d\u4e3a `None`\uff0c\u5219\u5c06\u8be5\u8fd4\u56de\u503c\u6ce8\u5165\u5230\u8be5\u53c2\u6570\u4e2d\u3002\n- `Provider.validate` \u65b9\u6cd5\u7528\u4e8e\u9a8c\u8bc1\u8ba2\u9605\u51fd\u6570\u7684\u53c2\u6570\u662f\u5426\u4e3a\u8be5 `Provider` \u53ef\u7ed1\u5b9a\u7684\u53c2\u6570\u3002\u9ed8\u8ba4\u5b9e\u73b0\u4e3a\u68c0\u67e5\u76ee\u6807\u53c2\u6570\u7684\u7c7b\u578b\u58f0\u660e\u662f\u5426\u4e3a `T`\u3002\n    \u4e5f\u53ef\u4ee5\u901a\u8fc7\u91cd\u5199\u8be5\u65b9\u6cd5\u6765\u5b9e\u73b0\u81ea\u5b9a\u4e49\u7684\u9a8c\u8bc1\u903b\u8f91\u3002\n- `Provider.__call__` \u65b9\u6cd5\u7528\u4e8e\u4ece `Contexts` \u4e2d\u83b7\u53d6\u53c2\u6570\n- \u539f\u5219\u4e0a `Provider` \u53ea\u8d1f\u8d23\u6ce8\u5165\u5355\u4e00\u7c7b\u578b\u7684\u53c2\u6570\u3002\u82e5\u60f3\u5904\u7406\u591a\u4e2a\u7c7b\u578b\u7684\u53c2\u6570\uff0c\u53ef\u4ee5\u58f0\u660e\u81ea\u5df1\u4e3a `Provider[Union[A, B, ...]]` \u7c7b\u578b\uff0c\n    \u5e76\u5728 `Provider.validate` \u65b9\u6cd5\u4e2d\u8fdb\u884c\u81ea\u5b9a\u4e49\u7684\u903b\u8f91\u5224\u65ad\u3002\u4f46\u66f4\u63a8\u8350\u7684\u505a\u6cd5\u662f\u6784\u9020\u591a\u4e2a `Provider`\uff0c\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230\u540c\u4e00\u4e2a\u53c2\u6570\u4e0a\u3002\n- \u5bf9\u4e8e\u7279\u6b8a\u7684\u8f85\u52a9\u5668 `Depend`\uff0c\u4e8b\u4ef6\u7cfb\u7edf\u4f1a\u5c06\u5176\u4f5c\u4e3a\u7279\u6b8a\u7684 `Provider` \u5904\u7406\uff0c\u7ed1\u5b9a\u4e86 `Depend` \u7684\u53c2\u6570\u5728\u89e3\u6790\u65f6\u5c06\u76f4\u63a5\u8c03\u7528\u8bbe\u7f6e\u5728\n    `Depend` \u4e0a\u7684\u65b9\u6cd5\u3002\n- `Provider` \u53ef\u4ee5\u8bbe\u7f6e\u4f18\u5148\u7ea7\uff0c\u503c\u8d8a\u5c0f\u4f18\u5148\u7ea7\u8d8a\u9ad8\n- \u53e6\u6709 `ProviderFactory`\uff0c\u7528\u4e8e\u96c6\u6210\u591a\u4e2a `Provider` \u7684\u5206\u914d\uff0c\u4ee5\u65b9\u4fbf `event.providers` \u7684\u8bbe\u7f6e\n\n### \u4e8b\u4ef6\u53d1\u5e03\n\n- \u4e00\u822c\u60c5\u51b5\u4e0b\u901a\u8fc7 `EventSystem.publish` \u6216 `EventSystem.post` \u65b9\u6cd5\u53ef\u4ee5\u53d1\u5e03\u4e00\u4e2a\u4e8b\u4ef6\u8ba9\u4e8b\u4ef6\u7cfb\u7edf\u8fdb\u884c\u5904\u7406\n- `publish` \u4f1a\u5904\u7406\u6240\u6709\u5408\u9002\u7684\u8ba2\u9605\u8005\uff0c\u800c `post` \u4f1a\u5728\u67d0\u4e00\u4e2a\u8ba2\u9605\u8005\u8fd4\u56de\u4e86\u6709\u6548\u503c\u540e\u505c\u6b62\u5904\u7406\uff0c\u5e76\u8fd4\u56de\u8be5\u503c\n- `Publisher` \u7c7b\u8d1f\u8d23\u7ba1\u7406\u8ba2\u9605\u8005\u4e0e\u4e8b\u4ef6\u7684\u4ea4\u4e92\n- `Publisher.validate` \u65b9\u6cd5\u7528\u4e8e\u9a8c\u8bc1\u8be5\u4e8b\u4ef6\u662f\u5426\u4e3a\u8be5\u53d1\u5e03\u8005\u7684\u8ba2\u9605\u8005\u6240\u5173\u6ce8\u7684\u4e8b\u4ef6\n- `Publisher.emit` \u548c `Publisher.bail` \u65b9\u6cd5\u7528\u4e8e\u5c06\u4e8b\u4ef6\u76f4\u63a5\u5206\u53d1\u7ed9\u5c5e\u4e8e\u81ea\u8eab\u7684\u8ba2\u9605\u8005\uff0c`emit` \u4e0e `bail` \u7684\u533a\u522b\u7c7b\u4f3c\u4e8e `publish` \u4e0e `post`\n- `Publisher.supply` \u65b9\u6cd5\u7528\u4e8e\u8ba9\u4e8b\u4ef6\u7cfb\u7edf\u4e3b\u52a8\u83b7\u53d6\u4e8b\u4ef6\u5e76\u5206\u53d1\u7ed9\u6240\u6709\u8ba2\u9605\u8005\n- `EventSystem.use`, `EventSystem.publish` \u548c `EventSystem.post` \u53ef\u4ee5\u6307\u5b9a `Publisher`\n- \u901a\u8fc7 `EventSystem.define` \u53ef\u4ee5\u4fbf\u6377\u7684\u5b9a\u4e49\u53d1\u5e03\u8005\uff0c\u5e76\u5728 `.use` \u7b49\u5904\u901a\u8fc7\u5b9a\u4e49\u7684\u540d\u5b57\u5f15\u7528\n\n### \u8f85\u52a9\n\n- `Auxiliary` \u63d0\u4f9b\u4e86\u4e00\u7cfb\u5217\u8f85\u52a9\u65b9\u6cd5\uff0c\u65b9\u4fbf\u4e8b\u4ef6\u7684\u5904\u7406\n- `Auxiliary` \u5206\u4e3a `Judge`, `Supply` \u4e24\u7c7b:\n    - `Judge`: \u7528\u4e8e\u5224\u65ad\u6b64\u65f6\u662f\u5426\u5e94\u8be5\u5904\u7406\u4e8b\u4ef6\n    - `Supply`: \u7528\u4e8e\u4e3a `Contexts` \u63d0\u4f9b\u989d\u5916\u7684\u4fe1\u606f\n- `Auxiliary.scopes` \u58f0\u660e\u4e86 `Auxiliary` \u7684\u4f5c\u7528\u57df:\n    - `prepare`: \u8868\u793a\u8be5 `Auxiliary` \u4f1a\u5728\u4f9d\u8d56\u6ce8\u5165\u4e4b\u524d\u6267\u884c\n    - `complete`: \u8868\u793a\u8be5 `Auxiliary` \u4f1a\u5728\u4f9d\u8d56\u6ce8\u5165\u5b8c\u6210\u540e\u6267\u884c\n    - `cleanup`: \u8868\u793a\u8be5 `Auxiliary` \u4f1a\u5728\u4e8b\u4ef6\u5904\u7406\u5b8c\u6210\u540e\u6267\u884c\n- `Auxiliary` \u53ef\u4ee5\u8bbe\u7f6e\u4f18\u5148\u7ea7\uff0c\u503c\u8d8a\u5c0f\u4f18\u5148\u7ea7\u8d8a\u9ad8\n- `Auxiliary` \u7684 `__call__` \u65b9\u6cd5\u591a\u589e\u52a0\u4e86\u4e00\u4e2a `Interface` \u53c2\u6570\uff0c\u53ef\u7528\u4e8e\u64cd\u4f5c `Contexts` \u6216 `Provider`, \u83b7\u53d6\u5df2\u6267\u884c\u7684 `Auxiliary` \u7b49\n\n## \u5f00\u6e90\u534f\u8bae\n\u672c\u5b9e\u73b0\u4ee5 MIT \u4e3a\u5f00\u6e90\u534f\u8bae\u3002\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A high-performance, simple-structured event system, relies on asyncio",
    "version": "0.13.3",
    "project_urls": {
        "Homepage": "https://github.com/ArcletProject/Letoderea",
        "Repository": "https://github.com/ArcletProject/Letoderea"
    },
    "split_keywords": [
        "asyncio",
        " event-system",
        " dispatch",
        " dependency-injection"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "152da5768178fce6e013667db4bf239e856987da747a8fd6c865a4b51bbde6c5",
                "md5": "457f5cc1413afc380583bc438c5a296f",
                "sha256": "9d82ada4809c278bc235292962fc8c1ae8bf9378f1b10970d99961161c2c5dcf"
            },
            "downloads": -1,
            "filename": "arclet_letoderea-0.13.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "457f5cc1413afc380583bc438c5a296f",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 24005,
            "upload_time": "2024-12-14T07:56:44",
            "upload_time_iso_8601": "2024-12-14T07:56:44.845138Z",
            "url": "https://files.pythonhosted.org/packages/15/2d/a5768178fce6e013667db4bf239e856987da747a8fd6c865a4b51bbde6c5/arclet_letoderea-0.13.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "cdc20a51fc3ea27d361c5f37f804e65c90a44cf9af3bdc16ef5c51df99195342",
                "md5": "a0983b563ad4cac885a9c03c4c099c97",
                "sha256": "eb8267e7875b76e99fc5b61d2b12e09129a7755e6255ca9b0dc5c69061879ad5"
            },
            "downloads": -1,
            "filename": "arclet_letoderea-0.13.3.tar.gz",
            "has_sig": false,
            "md5_digest": "a0983b563ad4cac885a9c03c4c099c97",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 25531,
            "upload_time": "2024-12-14T07:56:47",
            "upload_time_iso_8601": "2024-12-14T07:56:47.687296Z",
            "url": "https://files.pythonhosted.org/packages/cd/c2/0a51fc3ea27d361c5f37f804e65c90a44cf9af3bdc16ef5c51df99195342/arclet_letoderea-0.13.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-14 07:56:47",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ArcletProject",
    "github_project": "Letoderea",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "arclet-letoderea"
}
        
Elapsed time: 0.40774s