feat: 使算法能被自动注册

This commit is contained in:
2026-05-04 13:55:57 +08:00
parent 37a05874b2
commit 190699b447
11 changed files with 101 additions and 139 deletions

View File

@@ -70,7 +70,7 @@ uv sync --all-extras # 同步开发运行环境
uv run heurams # 验证包安装 uv run heurams # 验证包安装
uv run tui # 启动 TUI uv run heurams-tui # 启动 TUI
# 如果决定使用原生 python 环境 (不推荐, 但我们保留了这种方式以便在不便支持 uv 与硬链接的环境和文件系统(例如 termux)运行 HeurAMS) # 如果决定使用原生 python 环境 (不推荐, 但我们保留了这种方式以便在不便支持 uv 与硬链接的环境和文件系统(例如 termux)运行 HeurAMS)
@@ -79,7 +79,7 @@ python3 -m pip install -r requirements.txt
python3 -m pip install -e . python3 -m pip install -e .
python3 -m heurams # 验证安装 python3 -m heurams # 验证安装
python3 -m heurams.__interface__ # 启动 TUI python3 -m heurams.interface # 启动 TUI
``` ```
## 许可证与外部引用 ## 许可证与外部引用

View File

@@ -7,14 +7,14 @@
## 项目结构 ## 项目结构
这个仓库 "潜进" 的核心程序库在 python 语言下的实现 仓库 "潜进" 的核心程序库在 python 语言下的实现
包含数据模型与框架, 并内置了基于 textual 框架的前端实现 (interface 子模块) 包含数据模型与框架, 并内置了基于 textual 框架的前端实现 (interface 子模块)
除了通过内置前端进行学习外, 开发者也能在 python 环境中导入 `heurams` 库或使用 `RPC``heurams` 程序库实例通讯, 使用框架构建其他辅助记忆功能前端或其他应用程序 除了通过内置前端进行学习外, 开发者也能在 python 环境中导入 `heurams` 库或使用 `RPC``heurams` 程序库实例通讯, 使用框架构建其他辅助记忆功能前端或其他应用程序
> [!NOTE] > [!NOTE]
> 我们已经开始着手于基于 KDE 用户界面框架 `Kirigami` 的现代跨平台前端开发, 称作 "KiriMemo", 包名是 "org.kde.kirimemo", 但其并非 KDE 项目 > 我们已经开始着手于基于 KDE 用户界面框架 `Kirigami` 的现代跨平台前端开发, 称作 "KiriMemo", 包名是 "org.kde.kirimemo", 但其并非 KDE 项目
> 它通过 `PyOtherSide` 直接复用 python 内核, 为 Windows, Linux, macOS, Android 和 Plasma Mobile 提供现代用户界面 > 它通过 `PyOtherSide` 直接复用 python 内核, 为 Windows, Linux, macOS, Android 和 Plasma Mobile 提供现代用户界面
> 如果您善于开发 C++, QML, Qt 与 KDE 框架, 欢迎加入到 KiriMemo 项目的开发 > 如果您善于开发 C++, QML, Qt 与 KDE 框架, 欢迎加入到 KiriMemo 项目的开发
## 特性 ## 特性
@@ -57,19 +57,22 @@
潜进(heurams) 处于早期开发考虑, 尚未上架 PyPI, 但您可以用我们的基础设施安装稳定版和开发版本. 潜进(heurams) 处于早期开发考虑, 尚未上架 PyPI, 但您可以用我们的基础设施安装稳定版和开发版本.
#### 稳定版本
```
python -m pip install heurams[basic] -i https://pypi.pluv27.top/root/stable/+simple/ # 安装适用于用户体验的可选依赖(推荐)
```
```
python -m pip install heurams[audio-playsound] -i https://pypi.pluv27.top/root/stable/+simple/ # 安装适用于一般计算机的通用音频模块(不适用于 termux, termux 的音频支持是内建的)
```
#### 开发版本
> [!CAUTION] > [!CAUTION]
> 对于部分 Linux 发行版和 Android Termux 用户: > 对于部分 Linux 发行版和 Android Termux 用户:
> 您需要先行安装 `cmake` 和 `libzmq` 才能正确安装项目的 `zmq` 依赖 > 您需要先行安装 `cmake` 和 `libzmq` 才能正确安装项目的 `zmq` 依赖
> 例如在 termux 上先运行 `pkg install cmake clang libzmq` > 例如在 termux 上先运行 `pkg install cmake clang libzmq`
> 项目功能本身不依赖它, 但需要该依赖用于启动可选的调试服务器 > 项目功能本身不依赖它, 但需要该依赖用于启动可选的调试服务器
#### 稳定版本
```
python -m pip install heurams[all] -i https://pypi.pluv27.top/root/stable/+simple/ # 安装全部可选依赖(推荐)
```
#### 开发版本
``` ```
python -m pip install heurams[all] -i https://pypi.pluv27.top/root/dev/+simple/ # 安装全部可选依赖(推荐) python -m pip install heurams[all] -i https://pypi.pluv27.top/root/dev/+simple/ # 安装全部可选依赖(推荐)
@@ -79,34 +82,21 @@ python -m pip install heurams[all] -i https://pypi.pluv27.top/root/dev/+simple/
由于部分依赖只被少数功能需要, 所以我们把可选依赖分得比较细, 前面提供的命令会安装所有可选依赖, 以下是依赖组列表 由于部分依赖只被少数功能需要, 所以我们把可选依赖分得比较细, 前面提供的命令会安装所有可选依赖, 以下是依赖组列表
- 基础依赖: (只能驱动程序库) | 依赖组 | 包含模块 | 说明 |
- tabulate: 终端表格生成 |--------|----------|------|
- toml: TOML 文件加载 | 最小化安装 | tabulate, toml, transitions | 核心驱动程序库,始终必需 |
- transitions: 状态机依赖 | interface | textual, psutil | 基本用户界面依赖 |
- `interface` 依赖组: (基本用户界面依赖) | algo-fsrs | py-fsrs | FSRS 算法模块 |
- textual: 终端用户界面 | tts-edgetts | edge-tts | 微软文本转语音 |
- psutil: 获取系统信息 | llm | openai | OpenAI API 调用 |
- `algo-fsrs` 依赖组: | audio-playsound | playsound, pygobject | 通用音频播放及依赖 |
- py-fsrs: FSRS 算法模块需要 | dev | zmq, pytest, pytest-cov | 开发调试与测试工具 |
- `tts-edgetts` 依赖组: | basic | [tts-edgetts], [llm-openai], [algo-fsrs] | 适用于用户体验的较轻依赖组(推荐) |
- edge-tts微软文本转语音 | all | 以上所有依赖 | 完整安装组 |
- `misc-jieba` 依赖组:
- jieba: 中文智能分词所需
- `llm-openai` 依赖组:
- openai: OpenAI API 所需
- `audio-playsound` 依赖组:
- playsound: 通用音频播放
- pygobject: playsound 依赖
- `dev` 依赖组:
- zmq: 远程调试服务器所需
- pytest: 测试所需
- pytest-cov: 测试所需
- `all` 依赖组:
- 包含以上所有依赖
### 从源码安装 ### 从源码安装
我们提供原生 python 和 uv 两种安装方式.\ 我们提供原生 python 和 uv 两种安装方式.
详见[贡献指南](CONTRIBUTING.md). 详见[贡献指南](CONTRIBUTING.md).
## 项目结构 ## 项目结构
@@ -115,7 +105,8 @@ python -m pip install heurams[all] -i https://pypi.pluv27.top/root/dev/+simple/
## 参与项目 ## 参与项目
欢迎参与到项目协作中! 请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解贡献指南. 欢迎参与到项目协作中!
请参阅[贡献指南](CONTRIBUTING.md).
## 许可证 ## 许可证
@@ -128,15 +119,6 @@ python -m pip install heurams[all] -i https://pypi.pluv27.top/root/dev/+simple/
项目在 `src/heurams/vendor/` 目录下嵌入或在其他位置间接使用了以下第三方代码(可能有修改): 项目在 `src/heurams/vendor/` 目录下嵌入或在其他位置间接使用了以下第三方代码(可能有修改):
#### py-fsrs (open-spaced-repetition)
- 上游版本: 6.3.1
- 引用方式: vendor
- 位置: `src/heurams/vendor/pyfsrs/`
- 原项目: [py-fsrs](https://github.com/open-spaced-repetition/py-fsrs)
- 原版权: Copyright (c) 2026 Open Spaced Repetition Contributors
- 原许可证: MIT License
#### SM.js (slaypni) #### SM.js (slaypni)
- 上游版本: commit `6e3bb4afaf484426deb4a9fa3bcffe42ac066b45` (2015年2月4日上游已停止维护) - 上游版本: commit `6e3bb4afaf484426deb4a9fa3bcffe42ac066b45` (2015年2月4日上游已停止维护)

View File

@@ -2,7 +2,7 @@ provider = "playsound"
_provider_desc = "音频驱动类型" _provider_desc = "音频驱动类型"
[_provider_candidate] [_provider_candidate]
playsound = "python 跨平台音频系统" playsound = "Python 桌面跨平台音频系统, 使用了 playsound3 替代了老旧的 playsound"
termux = "Android Termux 音频系统" termux = "Android Termux 音频系统"
mpg123 = "通用音频系统, 依赖系统 mpg123" mpg123 = "通用音频系统, 依赖系统 mpg123"
pulseaudio = "高级音频路由系统" pulseaudio = "高级音频路由系统"

View File

@@ -29,29 +29,24 @@ algo-fsrs = [
tts-edgetts = [ tts-edgetts = [
"edge-tts>=7.2.8", # 微软 TTS "edge-tts>=7.2.8", # 微软 TTS
] ]
misc-jieba = [ llm = ["openai>=2.32.0"]
"jieba>=0.42.1", # 用于中文智能分词
]
llm-openai = [
"openai>=2.32.0",
]
audio-playsound = [ audio-playsound = [
"playsound==1.2.2", "playsound3==3.3.1",
"pygobject>=3.56.2", # playsound 依赖它 #"pygobject>=3.56.2", # playsound 依赖它
] ]
dev = [ # 调试所需依赖 dev = [ # 调试所需依赖
"zmq>=0.0.0", # 用于 ZMQ 远程调试服务器, 在 linux 上建议先安装 libzmq "zmq>=0.0.0", # 用于 ZMQ 远程调试服务器, 在 linux 上建议先安装 libzmq
"pytest>=8.0.0", # 用于普通测试 "pytest>=8.0.0", # 用于普通测试
"pytest-cov>=6.0.0", "pytest-cov>=6.0.0",
] ]
all = [ all = [
"heurams[algo-fsrs]", "heurams[algo-fsrs]",
"heurams[tts-edgetts]", "heurams[tts-edgetts]",
"heurams[misc-jieba]", "heurams[llm]",
"heurams[llm-openai]",
"heurams[audio-playsound]", "heurams[audio-playsound]",
"heurams[dev]", "heurams[dev]",
] ]
basic = ["heurams[algo-fsrs]", "heurams[tts-edgetts]", "heurams[llm]"]
[project.urls] [project.urls]
Homepage = "https://ams.pluv.top" Homepage = "https://ams.pluv.top"
@@ -59,7 +54,6 @@ Issues = "https://github.com/heurams/heurams/issues"
[project.scripts] [project.scripts]
heurams = "heurams.__main__:main" heurams = "heurams.__main__:main"
tui = "heurams.interface.__main__:main"
heurams-tui = "heurams.interface.__main__:main" heurams-tui = "heurams.interface.__main__:main"
[tool.pytest.ini_options] [tool.pytest.ini_options]

View File

@@ -1,5 +1,4 @@
edge-tts==7.0.2 edge-tts==7.0.2
jieba==0.42.1
openai==1.0.0 openai==1.0.0
playsound==1.2.2 playsound==1.2.2
tabulate>=0.9.0 tabulate>=0.9.0

View File

@@ -12,8 +12,8 @@ python 代指您使用的解释器, 在某些发行版中可能是 python3, 而
尽管项目保留了 requirements.txt, 我们仍不推荐使用系统 python 和原始 venv 进行开发. 尽管项目保留了 requirements.txt, 我们仍不推荐使用系统 python 和原始 venv 进行开发.
项目的推荐开发环境工具是 uv. 项目的推荐开发环境工具是 uv.
如果你的环境已经安装了 uv: 如果你的环境已经安装了 uv:
先运行 uv sync 同步环境, 此命令只需要执行一遍, uv 会自动处理依赖. 先运行 uv sync --all-extras 同步环境, 此命令只需要执行一遍, uv 会自动处理依赖.
然后通过运行 uv run tui 启动内置基本用户界面. 然后通过运行 uv run heurams-tui 启动内置基本用户界面.
此时您的解释器在项目目录里的 .venv/bin 中, 使用 IDE 开发前, 务必切换解释器! 此时您的解释器在项目目录里的 .venv/bin 中, 使用 IDE 开发前, 务必切换解释器!
注意: 一个常见的误区是, 执行 interface 下的 __main__.py 运行基本用户界面, 这会导致 Python 上下文环境异常, 请不要这样做.""" 注意: 一个常见的误区是, 执行 interface 下的 __main__.py 运行基本用户界面, 这会导致 Python 上下文环境异常, 请不要这样做."""
print(prompt) print(prompt)

View File

@@ -1,21 +1,14 @@
import importlib
import pkgutil
from pathlib import Path
from .base import BaseAlgorithm from .base import BaseAlgorithm
from .sm2 import SM2Algorithm
from .sm15m import SM15MAlgorithm
from .nsp0 import NSP0Algorithm
from .fsrs import FSRSAlgorithm
__all__ = [ __path__ = [str(Path(__file__).parent)]
"SM2Algorithm",
"BaseAlgorithm",
"SM15MAlgorithm",
"NSP0Algorithm",
"FSRSAlgorithm",
]
algorithms = { for _finder, _name, _ispkg in pkgutil.iter_modules(__path__):
"SM-2": SM2Algorithm, if _name == "base":
"NSP-0": NSP0Algorithm, continue
"SM-15M": SM15MAlgorithm, importlib.import_module(f".{_name}", __package__)
"FSRS": FSRSAlgorithm,
"Base": BaseAlgorithm, algorithms = BaseAlgorithm.get_registry()
}

View File

@@ -5,11 +5,20 @@ from heurams.services.logger import get_logger
logger = get_logger(__name__) logger = get_logger(__name__)
_registry: dict[str, type["BaseAlgorithm"]] = {}
class BaseAlgorithm: class BaseAlgorithm:
algo_name = "BaseAlgorithm" algo_name = "BaseAlgorithm"
desc = "算法基类" desc = "算法基类"
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
_registry[cls.algo_name] = cls
@classmethod
def get_registry(cls) -> dict[str, type["BaseAlgorithm"]]:
return dict(_registry)
class AlgodataDict(TypedDict): class AlgodataDict(TypedDict):
real_rept: int real_rept: int
rept: int rept: int

View File

@@ -10,7 +10,7 @@ logger = get_logger(__name__)
class NSP0Algorithm(BaseAlgorithm): class NSP0Algorithm(BaseAlgorithm):
algo_name = "NSP-0" algo_name = "NSP-0"
desc = "快速筛选用特殊调度器" desc = "快速筛选用非间隔重复调度器"
class AlgodataDict(TypedDict): class AlgodataDict(TypedDict):
real_rept: int real_rept: int

View File

@@ -10,7 +10,7 @@ logger = get_logger(__name__)
class SM2Algorithm(BaseAlgorithm): class SM2Algorithm(BaseAlgorithm):
algo_name = "SM-2" algo_name = "SM-2"
desc = "经典间隔重复算法" desc = "SuperMemo2 (1987) 简单间隔重复调度器"
class AlgodataDict(TypedDict): class AlgodataDict(TypedDict):
efactor: float efactor: float

91
uv.lock generated
View File

@@ -450,17 +450,19 @@ algo-fsrs = [
all = [ all = [
{ name = "edge-tts" }, { name = "edge-tts" },
{ name = "fsrs" }, { name = "fsrs" },
{ name = "jieba" },
{ name = "openai" }, { name = "openai" },
{ name = "playsound" }, { name = "playsound3" },
{ name = "pygobject" },
{ name = "pytest" }, { name = "pytest" },
{ name = "pytest-cov" }, { name = "pytest-cov" },
{ name = "zmq" }, { name = "zmq" },
] ]
audio-playsound = [ audio-playsound = [
{ name = "playsound" }, { name = "playsound3" },
{ name = "pygobject" }, ]
basic = [
{ name = "edge-tts" },
{ name = "fsrs" },
{ name = "openai" },
] ]
dev = [ dev = [
{ name = "pytest" }, { name = "pytest" },
@@ -471,12 +473,9 @@ interface = [
{ name = "psutil" }, { name = "psutil" },
{ name = "textual" }, { name = "textual" },
] ]
llm-openai = [ llm = [
{ name = "openai" }, { name = "openai" },
] ]
misc-jieba = [
{ name = "jieba" },
]
tts-edgetts = [ tts-edgetts = [
{ name = "edge-tts" }, { name = "edge-tts" },
] ]
@@ -486,16 +485,16 @@ requires-dist = [
{ name = "edge-tts", marker = "extra == 'tts-edgetts'", specifier = ">=7.2.8" }, { name = "edge-tts", marker = "extra == 'tts-edgetts'", specifier = ">=7.2.8" },
{ name = "fsrs", marker = "extra == 'algo-fsrs'", specifier = ">=6.3.1" }, { name = "fsrs", marker = "extra == 'algo-fsrs'", specifier = ">=6.3.1" },
{ name = "heurams", extras = ["algo-fsrs"], marker = "extra == 'all'" }, { name = "heurams", extras = ["algo-fsrs"], marker = "extra == 'all'" },
{ name = "heurams", extras = ["algo-fsrs"], marker = "extra == 'basic'" },
{ name = "heurams", extras = ["audio-playsound"], marker = "extra == 'all'" }, { name = "heurams", extras = ["audio-playsound"], marker = "extra == 'all'" },
{ name = "heurams", extras = ["dev"], marker = "extra == 'all'" }, { name = "heurams", extras = ["dev"], marker = "extra == 'all'" },
{ name = "heurams", extras = ["llm-openai"], marker = "extra == 'all'" }, { name = "heurams", extras = ["llm"], marker = "extra == 'all'" },
{ name = "heurams", extras = ["misc-jieba"], marker = "extra == 'all'" }, { name = "heurams", extras = ["llm"], marker = "extra == 'basic'" },
{ name = "heurams", extras = ["tts-edgetts"], marker = "extra == 'all'" }, { name = "heurams", extras = ["tts-edgetts"], marker = "extra == 'all'" },
{ name = "jieba", marker = "extra == 'misc-jieba'", specifier = ">=0.42.1" }, { name = "heurams", extras = ["tts-edgetts"], marker = "extra == 'basic'" },
{ name = "openai", marker = "extra == 'llm-openai'", specifier = ">=2.32.0" }, { name = "openai", marker = "extra == 'llm'", specifier = ">=2.32.0" },
{ name = "playsound", marker = "extra == 'audio-playsound'", specifier = "==1.2.2" }, { name = "playsound3", marker = "extra == 'audio-playsound'", specifier = "==3.3.1" },
{ name = "psutil", marker = "extra == 'interface'", specifier = ">=7.2.2" }, { name = "psutil", marker = "extra == 'interface'", specifier = ">=7.2.2" },
{ name = "pygobject", marker = "extra == 'audio-playsound'", specifier = ">=3.56.2" },
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0.0" },
{ name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=6.0.0" }, { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=6.0.0" },
{ name = "tabulate", specifier = ">=0.10.0" }, { name = "tabulate", specifier = ">=0.10.0" },
@@ -504,7 +503,7 @@ requires-dist = [
{ name = "transitions", specifier = ">=0.9.3" }, { name = "transitions", specifier = ">=0.9.3" },
{ name = "zmq", marker = "extra == 'dev'", specifier = ">=0.0.0" }, { name = "zmq", marker = "extra == 'dev'", specifier = ">=0.0.0" },
] ]
provides-extras = ["interface", "algo-fsrs", "tts-edgetts", "misc-jieba", "llm-openai", "audio-playsound", "dev", "all"] provides-extras = ["interface", "algo-fsrs", "tts-edgetts", "llm", "audio-playsound", "dev", "all", "basic"]
[[package]] [[package]]
name = "httpcore" name = "httpcore"
@@ -552,12 +551,6 @@ wheels = [
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, { url = "https://mirrors.ustc.edu.cn/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
] ]
[[package]]
name = "jieba"
version = "0.42.1"
source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" }
sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/c6/cb/18eeb235f833b726522d7ebed54f2278ce28ba9438e3135ab0278d9792a2/jieba-0.42.1.tar.gz", hash = "sha256:055ca12f62674fafed09427f176506079bc135638a14e23e25be909131928db2", size = 19214172, upload-time = "2020-01-20T14:27:23.5Z" }
[[package]] [[package]]
name = "jiter" name = "jiter"
version = "0.14.0" version = "0.14.0"
@@ -817,11 +810,15 @@ wheels = [
] ]
[[package]] [[package]]
name = "playsound" name = "playsound3"
version = "1.2.2" version = "3.3.1"
source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" } source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" }
dependencies = [
{ name = "pywin32", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/6b/93/39f2296a69fe2c70dcc9b9724147ffc9d7f676f67eb3cbad3baa725ae32d/playsound3-3.3.1.tar.gz", hash = "sha256:3f0eb87d5ff2061d07663c4b010b8e7d66c274344712b01d561a0a73447ef41d", size = 608340, upload-time = "2026-01-22T18:05:55.444Z" }
wheels = [ wheels = [
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/f5/16/10d897b0a83fb4b05b03a63d7a2667ab75f857f67f7062fd447dd3f49bf7/playsound-1.2.2-py2.py3-none-any.whl", hash = "sha256:1e83750a5325cbccee03d6e751ba3e78c037ac95b95a3ba1f38d0c5aca9e1a34", size = 5960, upload-time = "2017-06-29T14:08:29.207Z" }, { url = "https://mirrors.ustc.edu.cn/pypi/packages/62/9d/8b97af915bd8a9e2b17b08bb9d62d45cce5c00a28a64b08324bb5895145b/playsound3-3.3.1-py3-none-any.whl", hash = "sha256:8e606115c3630762a7136579ceb25fbf725768a31f7d0bfc2883154d8c50205d", size = 9697, upload-time = "2026-01-22T18:05:53.783Z" },
] ]
[[package]] [[package]]
@@ -945,25 +942,6 @@ wheels = [
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, { url = "https://mirrors.ustc.edu.cn/pypi/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" },
] ]
[[package]]
name = "pycairo"
version = "1.29.0"
source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" }
sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/22/d9/1728840a22a4ef8a8f479b9156aa2943cd98c3907accd3849fb0d5f82bfd/pycairo-1.29.0.tar.gz", hash = "sha256:f3f7fde97325cae80224c09f12564ef58d0d0f655da0e3b040f5807bd5bd3142", size = 665871, upload-time = "2025-11-11T19:13:01.584Z" }
wheels = [
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/f6/28/6363087b9e60af031398a6ee5c248639eefc6cc742884fa2789411b1f73b/pycairo-1.29.0-cp312-cp312-win32.whl", hash = "sha256:91bcd7b5835764c616a615d9948a9afea29237b34d2ed013526807c3d79bb1d0", size = 751486, upload-time = "2025-11-11T19:11:54.451Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/3a/d2/d146f1dd4ef81007686ac52231dd8f15ad54cf0aa432adaefc825475f286/pycairo-1.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:3f01c3b5e49ef9411fff6bc7db1e765f542dc1c9cfed4542958a5afa3a8b8e76", size = 845383, upload-time = "2025-11-11T19:12:01.551Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/01/16/6e6f33bb79ec4a527c9e633915c16dc55a60be26b31118dbd0d5859e8c51/pycairo-1.29.0-cp312-cp312-win_arm64.whl", hash = "sha256:eafe3d2076f3533535ad4a361fa0754e0ee66b90e548a3a0f558fed00b1248f2", size = 694518, upload-time = "2025-11-11T19:12:06.561Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/f0/21/3f477dc318dd4e84a5ae6301e67284199d7e5a2384f3063714041086b65d/pycairo-1.29.0-cp313-cp313-win32.whl", hash = "sha256:3eb382a4141591807073274522f7aecab9e8fa2f14feafd11ac03a13a58141d7", size = 750949, upload-time = "2025-11-11T19:12:12.198Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/43/34/7d27a333c558d6ac16dbc12a35061d389735e99e494ee4effa4ec6d99bed/pycairo-1.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:91114e4b3fbf4287c2b0788f83e1f566ce031bda49cf1c3c3c19c3e986e95c38", size = 844149, upload-time = "2025-11-11T19:12:19.171Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/15/43/e782131e23df69e5c8e631a016ed84f94bbc4981bf6411079f57af730a23/pycairo-1.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:09b7f69a5ff6881e151354ea092137b97b0b1f0b2ab4eb81c92a02cc4a08e335", size = 693595, upload-time = "2025-11-11T19:12:23.445Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/2d/fa/87eaeeb9d53344c769839d7b2854db7ff2cd596211e00dd1b702eeb1838f/pycairo-1.29.0-cp314-cp314-win32.whl", hash = "sha256:69e2a7968a3fbb839736257bae153f547bca787113cc8d21e9e08ca4526e0b6b", size = 767198, upload-time = "2025-11-11T19:12:42.336Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/3c/90/3564d0f64d0a00926ab863dc3c4a129b1065133128e96900772e1c4421f8/pycairo-1.29.0-cp314-cp314-win_amd64.whl", hash = "sha256:e91243437a21cc4c67c401eff4433eadc45745275fa3ade1a0d877e50ffb90da", size = 871579, upload-time = "2025-11-11T19:12:48.982Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/5e/91/93632b6ba12ad69c61991e3208bde88486fdfc152be8cfdd13444e9bc650/pycairo-1.29.0-cp314-cp314-win_arm64.whl", hash = "sha256:b72200ea0e5f73ae4c788cd2028a750062221385eb0e6d8f1ecc714d0b4fdf82", size = 719537, upload-time = "2025-11-11T19:12:55.016Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/93/23/37053c039f8d3b9b5017af9bc64d27b680c48a898d48b72e6d6583cf0155/pycairo-1.29.0-cp314-cp314t-win_amd64.whl", hash = "sha256:5e45fce6185f553e79e4ef1722b8e98e6cde9900dbc48cb2637a9ccba86f627a", size = 874015, upload-time = "2025-11-11T19:12:28.47Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/d7/54/123f6239685f5f3f2edc123f1e38d2eefacebee18cf3c532d2f4bd51d0ef/pycairo-1.29.0-cp314-cp314t-win_arm64.whl", hash = "sha256:caba0837a4b40d47c8dfb0f24cccc12c7831e3dd450837f2a356c75f21ce5a15", size = 721404, upload-time = "2025-11-11T19:12:36.919Z" },
]
[[package]] [[package]]
name = "pycparser" name = "pycparser"
version = "3.0" version = "3.0"
@@ -1072,15 +1050,6 @@ wheels = [
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, { url = "https://mirrors.ustc.edu.cn/pypi/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
] ]
[[package]]
name = "pygobject"
version = "3.56.2"
source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" }
dependencies = [
{ name = "pycairo" },
]
sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/a2/80/09247a2be28af2c2240132a0af6c1005a2b1d089242b13a2cd782d2de8d7/pygobject-3.56.2.tar.gz", hash = "sha256:b816098969544081de9eecedb94ad6ac59c77e4d571fe7051f18bebcec074313", size = 1409059, upload-time = "2026-03-25T16:14:04.008Z" }
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "9.0.3" version = "9.0.3"
@@ -1111,6 +1080,22 @@ wheels = [
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, { url = "https://mirrors.ustc.edu.cn/pypi/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" },
] ]
[[package]]
name = "pywin32"
version = "311"
source = { registry = "https://mirrors.ustc.edu.cn/pypi/simple" }
wheels = [
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" },
{ url = "https://mirrors.ustc.edu.cn/pypi/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
]
[[package]] [[package]]
name = "pyzmq" name = "pyzmq"
version = "27.1.0" version = "27.1.0"