├── .env.example
├── .github
├── FUNDING.yml
└── workflows
│ └── pypi-publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── examples
└── external_example
│ ├── README.md
│ ├── __init__.py
│ ├── bg_provider.py
│ ├── collectors.py
│ └── templates
│ ├── __init__.py
│ └── example_template
│ ├── __init__.py
│ └── res
│ └── index.html.jinja
├── nonebot_plugin_picstatus
├── __init__.py
├── __main__.py
├── bg_provider.py
├── collectors
│ ├── __init__.py
│ ├── bot.py
│ ├── cpu.py
│ ├── disk.py
│ ├── mem.py
│ ├── misc.py
│ ├── network.py
│ └── process.py
├── config.py
├── debug.py
├── misc_statistics.py
├── res
│ ├── assets
│ │ ├── default_avatar.webp
│ │ └── default_bg.webp
│ └── js
│ │ ├── globalThis.d.ts
│ │ ├── init-global.js
│ │ ├── lazy-load.js
│ │ └── load-plugin.js
├── templates
│ ├── __init__.py
│ ├── default
│ │ ├── __init__.py
│ │ └── res
│ │ │ ├── css
│ │ │ ├── index.css
│ │ │ ├── no-blur.css
│ │ │ ├── no-radius.css
│ │ │ ├── no-shadow.css
│ │ │ └── theme-dark.css
│ │ │ └── templates
│ │ │ ├── index.html.jinja
│ │ │ └── macros.html.jinja
│ └── pw_render.py
└── util.py
├── pdm.lock
└── pyproject.toml
/.env.example:
--------------------------------------------------------------------------------
1 | # ====================
2 | # 全局设置
3 |
4 | # 用来测试访问网址时的代理(默认为空)
5 | PROXY="http://127.0.0.1:7890"
6 |
7 | # ====================
8 | # 行为设置
9 |
10 | # 要使用的图片模板
11 | # 目前只有 default 可用
12 | # 关于模板的特定配置请见下方
13 | PS_TEMPLATE=default
14 |
15 | # 触发插件功能的指令列表(可不填)
16 | PS_COMMAND=["运行状态", "状态", "zt", "yxzt", "status"]
17 |
18 | # 是否只能由 SUPERUSER 触发指令(可不填)
19 | PS_ONLY_SU=False
20 |
21 | # 触发指令是否需要 @Bot(可不填)
22 | PS_NEED_AT=False
23 |
24 | # 是否回复目标用户(可不填)
25 | # 使用 QQ 官方机器人时需要关闭此项(官方尚未支持回复),否则可能导致报错!
26 | PS_REPLY_TARGET=True
27 |
28 | # 请求头像等其他 URL 时的超时时间(秒)(可不填)
29 | PS_REQ_TIMEOUT=10
30 |
31 | # ====================
32 | # 全局个性化设置
33 |
34 | # 图片背景图来源(可不填)
35 | # 当背景图获取失败时,会自动 fallback 到 "local" 来源
36 | # 图片来源列表:
37 | # - "loli": LoliApi (https://docs.loliapi.com/api-shi-yong-wen-dang/sui-ji-er-ci-yuan-tu-pian/shou-ji-duan-sui-ji-tu-pian)
38 | # - "lolicon": Lolicon API (https://api.lolicon.app/#/setu)
39 | # > 注: 此来源会直接从 Pixiv 而不是反代站获取图片,如遇网络问题请自备代理
40 | # - "local": 本地图片
41 | # - "none": 无背景图
42 | PS_BG_PROVIDER=loli
43 |
44 | # 背景图预载数量(可不填)
45 | PS_BG_PRELOAD_COUNT=1
46 |
47 | # Lolicon API 背景图来源获取图片的 R18 类型(可不填)
48 | # 可用值:0 (哒咩 R18!)、1 (就要 R18!)、2 (U18 / R18 混合)
49 | PS_BG_LOLICON_R18_TYPE=0
50 |
51 | # 本地背景图来源 ("local") 使用的图片文件 / 文件夹路径(默认为插件自带背景图)
52 | # 如路径不存在,会 fallback 到插件自带默认背景图
53 | PS_BG_LOCAL_PATH=
54 |
55 | # 当获取 Bot 头像失败时使用的默认头像路径(可不填)
56 | PS_DEFAULT_AVATAR=
57 |
58 | # ====================
59 | # 数据收集设置
60 |
61 | # == 基础设置 ==
62 |
63 | # PeriodicCollector 的调用间隔,单位秒
64 | PS_COLLECT_INTERVAL=2
65 |
66 | # PeriodicCollector 中 deque 的默认大小
67 | PS_DEFAULT_COLLECT_CACHE_SIZE=1
68 |
69 | # 设置特定 PeriodicCollector 中 deque 的大小,{ [name: string]: number }
70 | PS_COLLECT_CACHE_SIZE={}
71 |
72 | # == header ==
73 |
74 | # 使用 .env 中配置的 NICKNAME 作为图片上的 Bot 昵称(可不填)
75 | PS_USE_ENV_NICK=False
76 |
77 | # 仅显示当前 Bot(可不填)
78 | PS_SHOW_CURRENT_BOT_ONLY=False
79 |
80 | # 是否对适配器为 OneBot V11 的 Bot 调用 get_status 获取收发消息数
81 | PS_OB_V11_USE_GET_STATUS=True
82 |
83 | # 是否使用 message_sent 事件(OneBot V11),或 user_id 为自身的消息事件统计发送消息数
84 | # 为 False 时全局禁用,为 True 时全局启用,
85 | # 为适配器名称列表(如 ["OneBot V11", "Telegram"])仅对指定的适配器启用
86 | PS_COUNT_MESSAGE_SENT_EVENT=False
87 |
88 | # 是否在 Bot 断开链接时清空收发消息计数
89 | PS_DISCONNECT_RESET_COUNTER=True
90 |
91 | # == disk ==
92 |
93 | # 分区列表里忽略的盘符(挂载点)(可不填)
94 | # 使用正则表达式匹配
95 | # 由于配置项使用JSON解析,所以需要使用双反斜杠转义,
96 | # 如:"sda\\d" 解析为 sda\d(代表 sda<一位阿拉伯数字>);
97 | # "C:\\\\Windows" 解析为 C:\\Windows(代表 C:\Windows)
98 | PS_IGNORE_PARTS=[]
99 |
100 | # 忽略获取容量状态失败的磁盘分区(可不填)
101 | PS_IGNORE_BAD_PARTS=False
102 |
103 | # 是否排序分区列表(按照已用大小比例倒序)(可不填)
104 | PS_SORT_PARTS=True
105 |
106 | # 是否反转分区列表排序(可不填)
107 | PS_SORT_PARTS_REVERSE=False
108 |
109 | # 磁盘 IO 统计列表中忽略的磁盘名(可不填)
110 | # 使用正则表达式匹配(注意事项同上)
111 | PS_IGNORE_DISK_IOS=[]
112 |
113 | # 是否忽略 IO 都为 0B/s 的磁盘(可不填)
114 | PS_IGNORE_NO_IO_DISK=False
115 |
116 | # 是否排序磁盘 IO 统计列表(按照读写速度总和倒序)(可不填)
117 | PS_SORT_DISK_IOS=True
118 |
119 | # == network ==
120 |
121 | # 网速列表中忽略的网络名称(可不填)
122 | # 使用正则表达式匹配(注意事项同上)
123 | PS_IGNORE_NETS=["^lo$", "^Loopback"]
124 |
125 | # 是否忽略上下行都为 0B/s 的网卡(可不填)
126 | PS_IGNORE_0B_NET=False
127 |
128 | # 是否排序网速列表(按照上下行速度总和倒序)(可不填)
129 | PS_SORT_NETS=True
130 |
131 | # 需要进行测试响应速度的网址列表(可不填)
132 | # 字段说明:
133 | # - name: 显示名称
134 | # - url: 测试网址
135 | # - use_proxy: 是否使用插件配置中的代理访问(可不填,默认为 false)
136 | PS_TEST_SITES='
137 | [
138 | {"name": "百度", "url": "https://www.baidu.com/"},
139 | {"name": "谷歌", "url": "https://www.google.com/", "use_proxy": true}
140 | ]
141 | '
142 |
143 | # 是否将测试网址的结果排序(按照响应时间正序)(可不填)
144 | PS_SORT_SITES=True
145 |
146 | # 网址测试访问时的超时时间(秒)(可不填)
147 | PS_TEST_TIMEOUT=5
148 |
149 | # == process ==
150 |
151 | # 进程列表的最大项目数量(可不填)
152 | PS_PROC_LEN=5
153 |
154 | # 要忽略的进程名(可不填)
155 | # 使用正则表达式匹配(注意事项同上)
156 | PS_IGNORE_PROCS=[]
157 |
158 | # 进程列表的排序方式(可不填)
159 | # 可选:cpu、mem
160 | PS_PROC_SORT_BY=cpu
161 |
162 | # 是否将进程 CPU 占用率显示为类似 Windows 任务管理器的百分比(最高 100%)(可不填)
163 | # 例:当你的 CPU 总共有 4 线程时,如果该进程吃满了两个线程,
164 | # Linux 会显示为 200%(每个线程算 100%),而 Windows 会显示为 50%(总占用率算 100%)
165 | PS_PROC_CPU_MAX_100P=False
166 |
167 | # ====================
168 | # default 模板特定配置
169 |
170 | # 图片中渲染的组件列表及其排列顺序(可不填)
171 | # 默认启用全部组件
172 | # 组件介绍:
173 | # - "header": 已连接的 Bot 信息、NoneBot 运行时间、系统运行时间
174 | # - "cpu_mem": CPU、MEM、SWAP 使用率圆环图
175 | # - "disk": 分区占用情况、磁盘 IO 情况
176 | # - "network": 网络 IO 情况、网络响应速度测试
177 | # - "process": 进程 CPU、MEM 占用情况
178 | # - "footer": NoneBot 与 PicStatus 版本、当前时间、Python 实现及版本、系统名称及架构
179 | PS_DEFAULT_COMPONENTS=["header", "cpu_mem", "disk", "network", "process", "footer"]
180 |
181 | # 向模板中附加的 CSS 路径列表(默认为空)
182 | # 如要使用插件内置 CSS,请使用 res: 前缀
183 | # 内置 CSS 列表:
184 | # - "res:theme-dark.css": 深色主题
185 | # - "res:no-blur.css": 禁用卡片毛玻璃效果
186 | # - “res:no-radius.css”: 禁用圆角
187 | # - “res:no-shadow.css”: 禁用阴影
188 | # Tip:
189 | # 可以在 Bot 工作目录下新建一个名为 debug 的文件夹,
190 | # 当检测到存在此文件夹时,渲染出来的 HTML 会被写进 debug/picstatus 文件夹中,方便调试
191 | PS_DEFAULT_ADDITIONAL_CSS=[]
192 |
193 | # 向模板中附加的 JS 脚本路径列表(默认为空)
194 | # 暂无内置 JS 脚本可供使用
195 | # 编写方式请参考 res/js/index.js
196 | PS_DEFAULT_ADDITIONAL_SCRIPT=[]
197 |
198 | # 输出的图片格式(可不填)
199 | # 可选:jpeg、png
200 | PS_DEFAULT_PIC_FORMAT=jpeg
201 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | custom: ["https://afdian.net/@lgc2333/"]
4 |
--------------------------------------------------------------------------------
/.github/workflows/pypi-publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish Python 🐍 distributions 📦 to PyPI
2 |
3 | on:
4 | release:
5 | types: [published]
6 | workflow_dispatch:
7 |
8 | jobs:
9 | build-n-publish:
10 | name: Use PDM to Build and publish Python 🐍 distributions 📦 to PyPI
11 | runs-on: ubuntu-latest
12 |
13 | permissions:
14 | # IMPORTANT: this permission is mandatory for trusted publishing
15 | id-token: write
16 |
17 | steps:
18 | - name: Checkout
19 | uses: actions/checkout@master
20 | with:
21 | submodules: true
22 |
23 | - name: Setup PDM
24 | uses: pdm-project/setup-pdm@v3
25 |
26 | - name: Build and Publish distribution 📦 to PyPI
27 | run: pdm publish
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.vscode/
2 | /.idea/
3 | /.run/
4 | /venv/
5 | /testnb2/
6 | .pdm-python
7 | build/
8 | __pycache__
9 | /nonebot_plugin_picstatus/res/picstatus-debug.html
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 LgCookie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
50 |
51 | ## 📖 介绍
52 |
53 | 不多说,直接看图!
54 |
55 | ### 效果图
56 |
57 |
58 | 点击展开
59 |
60 | 
61 | 
62 |
63 |
64 |
65 | ## 💿 安装
66 |
67 | 以下提到的方法 任选**其一** 即可
68 |
69 |
70 | [推荐] 使用 nb-cli 安装
71 | 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
72 |
73 | ```bash
74 | nb plugin install nonebot-plugin-picstatus
75 | ```
76 |
77 |
78 |
79 |
80 | 使用包管理器安装
81 | 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
82 |
83 |
84 | pip
85 |
86 | ```bash
87 | pip install nonebot-plugin-picstatus
88 | ```
89 |
90 |
91 |
92 | pdm
93 |
94 | ```bash
95 | pdm add nonebot-plugin-picstatus
96 | ```
97 |
98 |
99 |
100 | poetry
101 |
102 | ```bash
103 | poetry add nonebot-plugin-picstatus
104 | ```
105 |
106 |
107 |
108 | conda
109 |
110 | ```bash
111 | conda install nonebot-plugin-picstatus
112 | ```
113 |
114 |
115 |
116 | 打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分的 `plugins` 项里追加写入
117 |
118 | ```toml
119 | [tool.nonebot]
120 | plugins = [
121 | # ...
122 | "nonebot_plugin_picstatus"
123 | ]
124 | ```
125 |
126 |
127 |
128 | ## ⚙️ 配置
129 |
130 | ### 见 [.env.example](https://github.com/lgc2333/nonebot-plugin-picstatus/blob/master/.env.example)
131 |
132 | ## 🎨 扩展
133 |
134 | 想知道如何为插件新增数据源、图片模板与背景图来源的话,请参考下方示例
135 |
136 | ### 见 [examples/external_example](https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/tree/master/examples/external_example)
137 |
138 | ## 🎉 使用
139 |
140 | 使用指令 `运行状态`(或者 `状态` / `zt` / `yxzt` / `status`,可修改)来触发插件功能
141 | 可以在消息后面跟一张图片或者回复一张图片来自定义背景图,默认为随机背景图
142 | 更多自定义项参见 [配置](#️-配置)
143 |
144 | ## 📞 联系
145 |
146 | QQ:3076823485
147 | Telegram:[@lgc2333](https://t.me/lgc2333)
148 | 吹水群:[1105946125](https://jq.qq.com/?_wv=1027&k=Z3n1MpEp)
149 | 邮箱:
150 |
151 | ## 💡 鸣谢
152 |
153 | ### [nonebot/plugin-alconna](https://github.com/nonebot/plugin-alconna)
154 |
155 | - 强大的命令解析库,和多平台适配方案
156 |
157 | ### [noneplugin/nonebot-plugin-userinfo](https://github.com/noneplugin/nonebot-plugin-userinfo)
158 |
159 | - 多平台用户信息获取方案
160 |
161 | ### [kexue-z/nonebot-plugin-htmlrender](https://github.com/kexue-z/nonebot-plugin-htmlrender)
162 |
163 | - HTML 渲染方案
164 |
165 | ### [LoliApi](https://docs.loliapi.com/) & [Lolicon API](https://api.lolicon.app/)
166 |
167 | - 背景图来源
168 |
169 | ## 💰 赞助
170 |
171 | **[赞助我](https://blog.lgc2333.top/donate)**
172 |
173 | 感谢大家的赞助!你们的赞助将是我继续创作的动力!
174 |
175 | ## 📝 更新日志
176 |
177 | ### 2.1.3
178 |
179 | - 兼容 HTTPX 0.28
180 |
181 | ### 2.1.2
182 |
183 | - fix [#49](https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/issues/49)
184 |
185 | ### 2.1.1
186 |
187 | - 重新加入指令带图/回复图自定义背景功能
188 |
189 | ### 2.1.0
190 |
191 | - 优化代码结构,现在理论上可以使用其他插件往本插件内添加数据源、图片模板与背景图来源了
192 | - 添加背景图预载功能,理论可以加快出图速度
193 | - 删除 `gm` 背景图源,默认图源改为 `loli`
194 | - 配置项变动:
195 | - 新增 `PS_BG_PRELOAD_COUNT`
196 | - 新增 `PS_DEFAULT_PIC_FORMAT`
197 | - `PS_BG_PROVIDER` 默认值变动
198 | - `PS_COUNT_MESSAGE_SENT_EVENT` 接受类型变动
199 |
200 | ### 2.0.0
201 |
202 | - 代码重构,现在开发者可以更自由灵活的添加新状态图片样式
203 | - 配置项变动:
204 | - 新增 `PS_TEMPLATE`
205 | - 新增 `PS_COLLECT_INTERVAL`
206 | - 新增 `PS_DEFAULT_COLLECT_CACHE_SIZE`
207 | - 新增 `PS_COLLECT_CACHE_SIZE`
208 | - 新增 `PS_COUNT_MESSAGE_SENT_EVENT`
209 | - 新增 `PS_DISCONNECT_RESET_COUNTER`
210 | - 重命名 `PS_COMPONENTS` -> `PS_DEFAULT_COMPONENTS`
211 | - 重命名 `PS_ADDITIONAL_CSS` -> `PS_DEFAULT_ADDITIONAL_CSS`
212 | - 重命名 `PS_ADDITIONAL_SCRIPT` -> `PS_DEFAULT_ADDITIONAL_SCRIPT`
213 |
214 |
215 | v1 更新日志(点击展开)
216 |
217 | ### 1.1.1
218 |
219 | - 新增内置 CSS `theme-vanilla.css`
220 | - 微调默认 CSS
221 |
222 | ### 1.1.0
223 |
224 | - 支持 Pydantic V2
225 |
226 | ### 1.0.3
227 |
228 | - 修复了当有读取数据出错的分区时图片无法正常渲染的 Bug
229 |
230 | ### 1.0.2
231 |
232 | - 修复了背景图还没加载就出图的 Bug(希望),顺带调整了一下附加 JS 的写法
233 |
234 | ### 1.0.1
235 |
236 | - impl [#38](https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/issues/38),新增配置 `PS_OB_V11_USE_GET_STATUS`
237 |
238 | ### 1.0.0
239 |
240 | 重构项目:
241 |
242 | - 换用 alconna 与 userinfo 适配多平台
243 | - 换用 htmlrender 渲染图片
244 | - 删除消息附带图片作为自定义背景图功能
245 | - 配置项改动:
246 | - 添加 `PS_COMPONENTS`
247 | - 添加 `PS_ADDITIONAL_CSS`
248 | - 添加 `PS_ADDITIONAL_SCRIPT`
249 | - 添加 `PS_BG_PROVIDER`
250 | - 添加 `PS_BG_LOLICON_R18_TYPE`
251 | - 添加 `PS_BG_LOCAL_PATH`
252 | - 添加 `PS_SHOW_CURRENT_BOT_ONLY`
253 | - 删除 `PS_FONT`
254 | - 删除 `PS_CUSTOM_BG`
255 | - 删除 `PS_BG_COLOR`
256 | - 删除 `PS_MASK_COLOR`
257 | - 删除 `PS_BLUR_RADIUS`
258 | - 删除 `PS_FOOTER_SIZE`
259 | - 删除 `PS_MAX_TEXT_LEN`
260 | - 删除 `PS_DEFAULT_BG`
261 |
262 |
263 |
264 |
265 | v0 更新日志(点击展开)
266 |
267 | ### 0.5.7
268 |
269 | - 修复 Bot 刚连接时收发数为未知的问题
270 |
271 | ### 0.5.6
272 |
273 | - 修复 Bot 连接时间与收发数显示不正确的问题
274 |
275 | ### 0.5.5
276 |
277 | - 一些不影响使用的小更改
278 | - 添加配置项 `PS_DEFAULT_AVATAR`、`PS_DEFAULT_BG`、`PS_COMMAND`
279 |
280 | ### 0.5.4
281 |
282 | - 针对性修复 Shamrock 获取状态信息报错的问题 ([#34](https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/issues/34))
283 |
284 | ### 0.5.3
285 |
286 | - 修改了读取 Linux 发行版名称与版本的方式
287 |
288 | ### 0.5.2
289 |
290 | - 修正读取分区信息错误时的提示信息 \([#33](https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/issues/33)\)
291 |
292 | ### 0.5.1
293 |
294 | - 使用 SAA 向 Telegram 平台发送消息
295 |
296 | ### 0.5.0
297 |
298 | - 先获取状态信息再进行画图,可以获取到更精准的状态信息
299 | - 添加进程占用信息的展示
300 | - 测试网站结果状态码后面会带上 `reason`,如 `200 OK` / `404 Not Found`
301 | - 添加了一些配置项(`PS_SORT_PARTS`, `PS_SORT_PARTS_REVERSE`, `PS_SORT_DISK_IOS`, `PS_SORT_NETS`, `PS_SORT_SITES`, `PS_PROC_LEN`, `PS_IGNORE_PROCS`, `PS_PROC_SORT_BY`, `PS_PROC_CPU_MAX_100P`, `PS_REPLY_TARGET`, `PS_TG_MAX_FILE_SIZE`)
302 |
303 | ### 0.4.2
304 |
305 | - 添加配置项 `PS_REQ_TIMEOUT` ([#25](https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/issues/25))
306 |
307 | ### 0.4.1
308 |
309 | - 现在默认使用 `pil_utils` 自动选择系统内支持中文的字体,删除插件内置字体
310 | - 使用 `pil_utils` 写 Bot 昵称,可以显示 Emoji 等特殊字符
311 | - 测试网站出错时不会往日志里甩错误堆栈了
312 |
313 | ### 0.4.0
314 |
315 | - 使用 [nonebot-plugin-send-anything-anywhere](https://github.com/felinae98/nonebot-plugin-send-anything-anywhere) 兼容多平台发送,并对 OneBot V11 和 Telegram 做了特殊兼容
316 | - 将状态图片保存为 `jpg` 格式,缩减体积
317 | - 测试网站现在按照配置文件中的顺序排序
318 | - 随机图来源换回 [故梦 API](https://api.gumengya.com)
319 | - `aiohttp` 与 `aiofiles` 换成了 `httpx` 与 `anyio`
320 |
321 | ### 0.3.3
322 |
323 | - 修了点 bug
324 | - 新配置 `PS_MAX_TEXT_LEN`
325 |
326 | ### 0.3.2
327 |
328 | - 只有当 `nickname` 配置项填写后,插件才会使用该项作为图片中 Bot 的显示名称
329 |
330 | ### 0.3.1
331 |
332 | - 修复一处 Py 3.10 以下无法正常运行的代码
333 |
334 | ### 0.3.0
335 |
336 | 配置项更新详见 [配置](#️-配置)
337 |
338 | - 更新配置项 `PS_TEST_SITES` `PS_TEST_TIMEOUT`
339 | - 修复`PS_NEED_AT`配置无效的 bug
340 | - 现在只有命令完全匹配时才会触发
341 |
342 | ### 0.2.5
343 |
344 | - 更新配置项 `PS_FOOTER_SIZE`
345 |
346 | ### 0.2.4
347 |
348 | - 支持自定义默认背景图
349 | - 一些配置项类型更改(不影响原先配置)
350 |
351 | ### 0.2.3
352 |
353 | - 尝试修复磁盘列表的潜在 bug
354 |
355 | ### 0.2.2
356 |
357 | 此版本在图片脚注中显示的版本还是`0.2.1`,抱歉,我大意了没有改版本号
358 |
359 | - 添加配置项`PS_IGNORE_NO_IO_DISK`用于忽略 IO 为 0B/s 的磁盘
360 | - 添加配置项`PS_IGNORE_0B_NET`用于忽略上下行都为 0B/s 的网卡
361 | - 添加触发指令`zt` `yxzt` `status`
362 | - 获取信息收发量兼容旧版 GoCQ ,即使获取失败也不会报错而显示`未知`
363 | - 将忽略 IO 统计磁盘名独立出一个配置项`PS_IGNORE_DISK_IOS`
364 | - 忽略 磁盘容量盘符/IO 统计磁盘名/网卡名称 改为匹配正则表达式
365 | - 配置项`PS_IGNORE_NETS`添加默认值`["^lo$", "^Loopback"]`
366 | - 修复空闲内存显示错误的问题
367 |
368 | ### 0.2.1
369 |
370 | - 尝试修复`type object is not subscriptable`报错
371 |
372 | ### 0.2.0
373 |
374 | - 新增磁盘 IO、网络 IO 状态显示
375 | - SWAP 大小为 0 时占用率将会显示`未部署`而不是`0%`
376 | - CPU 等占用下方灰色字排板更改
377 | - 获取失败的磁盘分区占用率修改为`未知%`
378 | - 图片下方脚注修改为居中文本,字号调小,优化显示的系统信息
379 | - 修改随机背景图 API 为[故梦 API 随机二次元壁纸](https://api.gmit.vip)
380 | - 现在会分 QQ 记录 Bot 连接时间(不同的 QQ 连接同一个 NoneBot 显示的连接时间将不同)
381 | - 背景图增加遮罩,颜色可配置
382 | - 可以配置各模块的背景底色
383 | - 可以配置分区列表中忽略的盘符(挂载点)
384 | - 可以忽略获取容量状态失败的分区
385 | - 可以使用`.env.*`文件中配置的`NICKNAME`作为图片中的 Bot 昵称
386 | - 添加必须 @Bot 才能触发指令的配置
387 | - 其他小优化/更改
388 |
389 |
390 |
--------------------------------------------------------------------------------
/examples/external_example/README.md:
--------------------------------------------------------------------------------
1 | # External Example
2 |
3 | 这是一个如何为本插件增加自定义内容的插件示例
4 |
5 | 你可以直接把此文件夹当做插件包扔给 nonebot2 加载,并按照下方说明更改配置项查看效果
6 |
7 | ```properties
8 | PS_TEMPLATE=example_template
9 | PS_BG_PROVIDER=lgc_icon
10 | ```
11 |
--------------------------------------------------------------------------------
/examples/external_example/__init__.py:
--------------------------------------------------------------------------------
1 | # ruff: noqa: E402
2 |
3 | from nonebot import require
4 |
5 | require("nonebot_plugin_picstatus") # 别忘 require
6 |
7 | from . import (
8 | bg_provider as bg_provider,
9 | collectors as collectors,
10 | templates as templates,
11 | )
12 |
--------------------------------------------------------------------------------
/examples/external_example/bg_provider.py:
--------------------------------------------------------------------------------
1 | from httpx import AsyncClient
2 | from nonebot_plugin_picstatus.bg_provider import BgData, bg_provider, resp_to_bg_data
3 | from nonebot_plugin_picstatus.config import config
4 |
5 | # 添加自定义背景源演示
6 | # 实际应用例请见 https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/blob/master/nonebot_plugin_picstatus/bg_provider.py
7 |
8 |
9 | # 需要用 bg_provider 装饰器注册函数为背景源
10 | # 背景源名称默认为函数名,当然你也可以手动指定名称,比如
11 | # @bg_provider("lgc_icon")
12 | @bg_provider()
13 | async def lgc_icon() -> BgData:
14 | async with AsyncClient(
15 | follow_redirects=True,
16 | proxy=config.proxy,
17 | timeout=config.ps_req_timeout,
18 | ) as cli:
19 | return resp_to_bg_data(
20 | (
21 | await cli.get("https://blog.lgc2333.top/assets/favicon.png")
22 | ).raise_for_status(),
23 | )
24 |
--------------------------------------------------------------------------------
/examples/external_example/collectors.py:
--------------------------------------------------------------------------------
1 | import random
2 | from typing_extensions import override
3 |
4 | from nonebot_plugin_picstatus.collectors import (
5 | TimeBasedCounterCollector,
6 | collector,
7 | first_time_collector,
8 | normal_collector,
9 | periodic_collector,
10 | )
11 |
12 | # 添加自定义数据源展示
13 | # 实际应用例请见 https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/tree/master/nonebot_plugin_picstatus/collectors
14 |
15 | # PicStatus 内置了三种可以直接用装饰器注册的 collector
16 |
17 | # region 1. normal_collector
18 |
19 | counter_count = 0
20 |
21 |
22 | # 该 collector 在每次生成状态图片时都会被调用
23 | # 使用该装饰器时,默认使用函数名作为数据源名称,你也可以手动指定,例如
24 | # @normal_collector("counter")
25 | @normal_collector()
26 | async def counter():
27 | global counter_count
28 | counter_count += 1
29 | return counter_count
30 |
31 |
32 | # endregion
33 |
34 | # region 2. first_time_collector
35 |
36 | first_time_counter_count = 0
37 |
38 |
39 | # 该 collector 只会在 nonebot 启动时被调用一次并缓存结果
40 | # 下面的例子中,该 collector 的结果将会始终为 1
41 | # 装饰器使用教程同上
42 | @first_time_collector()
43 | async def first_time_counter():
44 | global first_time_counter_count
45 | first_time_counter_count += 1
46 | return first_time_counter_count
47 |
48 |
49 | # endregion
50 |
51 | # region 3. periodic_collector
52 |
53 | periodic_counter_count = 0
54 |
55 |
56 | # 该 collector 每隔一定时间被调用一次,并保存一定数量的结果在 deque 中
57 | # 调用的间隔与保留的结果数量可以在 PicStatus 的配置中找到
58 | # 装饰器使用教程同上
59 | @periodic_collector()
60 | async def periodic_counter():
61 | global periodic_counter_count
62 | periodic_counter_count += 1
63 | return periodic_counter_count
64 |
65 |
66 | # endregion
67 |
68 |
69 | # 此外 PicStatus 内置了另外一种较特殊的 collector
70 | # 它不可以直接用装饰器装饰一个函数使用
71 |
72 |
73 | # region 4. TimeBasedCounterCollector
74 |
75 |
76 | # 该 collector 基于 PeriodicCollector
77 | # 它会记录该次调用与上次调用的时间间隔
78 | # 你可以根据这段时间间隔来计算你希望展示并缓存的值
79 | # 这对展示 IO 速度等数据可能会很有帮助
80 |
81 |
82 | # 使用此 collector 你需要继承两个 abstract method
83 | # 并使用 collector 装饰器注册,注意在这里 collector 名称必须手动指定
84 | # 你也可以使用 collector 装饰器来注册上述 collector,不过具体操作请自行看插件源码理解
85 | @collector("time_counter")
86 | class TestTimeBasedCounter(TimeBasedCounterCollector[int, str]):
87 | @override
88 | async def _calc(self, past: int, now: int, time_passed: float) -> str:
89 | """
90 | 此方法计算你最终想要返回的结果
91 |
92 | Args:
93 | past: 上次调用时返回的原始结果
94 | now: 本次调用时返回的原始结果
95 | time_passed: 从上次调用到本次调用的时间间隔(秒)
96 |
97 | Returns:
98 | 处理后的结果,和 PeriodicCollector 一样保存在 deque 中
99 | """
100 | return f"{(now - past) / time_passed:.2f}/s"
101 |
102 | @override
103 | async def _get_obj(self) -> int:
104 | """此方法返回传入 _calc 方法中的原始结果"""
105 | return random.randint(0, 100)
106 |
107 |
108 | # endregion
109 |
--------------------------------------------------------------------------------
/examples/external_example/templates/__init__.py:
--------------------------------------------------------------------------------
1 | def _import():
2 | from pathlib import Path
3 |
4 | from cookit import auto_import
5 |
6 | auto_import(Path(__file__).parent, __package__)
7 |
8 |
9 | _import()
10 | del _import
11 |
--------------------------------------------------------------------------------
/examples/external_example/templates/example_template/__init__.py:
--------------------------------------------------------------------------------
1 | # ruff: noqa: E402
2 |
3 | import json
4 | from collections import deque
5 | from pathlib import Path
6 | from typing import TYPE_CHECKING, Any, Optional
7 |
8 | import jinja2 as jj
9 | from cookit.jinja import make_register_jinja_filter_deco
10 | from nonebot import get_plugin_config, require
11 | from nonebot_plugin_picstatus.templates import pic_template
12 | from nonebot_plugin_picstatus.templates.pw_render import (
13 | ROUTE_URL,
14 | add_background_router,
15 | add_root_router,
16 | base_router_group,
17 | register_global_filter_to,
18 | )
19 | from pydantic import BaseModel
20 |
21 | # 添加自定义图片模板示例
22 | # 示例应用例请见 https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/blob/master/nonebot_plugin_picstatus/templates/default/__init__.py
23 |
24 | # 可以使用你喜欢的任意库来绘图
25 | # 示例使用 playwright,你也可以使用 Pillow 等
26 | # 本插件中自带一些使用 playwright 时绘图有帮助的工具函数
27 | # 详见 https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus/blob/master/nonebot_plugin_picstatus/templates/pw_render.py
28 |
29 | require("nonebot_plugin_htmlrender")
30 |
31 | from nonebot_plugin_htmlrender import get_new_page
32 |
33 | if TYPE_CHECKING:
34 | from nonebot_plugin_picstatus.bg_provider import BgData
35 |
36 | RES_DIR = Path(__file__).parent / "res"
37 |
38 | template_env = jj.Environment(
39 | loader=jj.FileSystemLoader(RES_DIR),
40 | autoescape=True,
41 | enable_async=True,
42 | )
43 | # 将插件提供的实用模板 filter 注册到模板环境中
44 | register_global_filter_to(template_env)
45 |
46 |
47 | jinja_filter = make_register_jinja_filter_deco(template_env)
48 |
49 |
50 | @jinja_filter
51 | def json_dumps(obj: Any, **kwargs) -> str:
52 | if isinstance(obj, dict):
53 | obj = {k: list(v) if isinstance(v, deque) else v for k, v in obj.items()}
54 | return json.dumps(obj, **kwargs)
55 |
56 |
57 | # 复制一份插件自带的路由组以便在该份代码范围中增删
58 | template_router_group = base_router_group.copy()
59 |
60 |
61 | # 可以把模板特定配置项声明在这里
62 | # 你也可以不在这里写,换成写到插件的 config.py 文件中,看个人喜好了
63 | class TemplateConfig(BaseModel):
64 | ps_example_template_example_config: Optional[str] = "example"
65 |
66 |
67 | template_config = get_plugin_config(TemplateConfig)
68 |
69 |
70 | # 注册模板渲染函数
71 | # name 参数为模板名称,不提供时使用函数名
72 | # collecting 传入需要启用的 collector 名称集合,如不提供则启用所有 collector
73 | @pic_template(
74 | collecting={
75 | "counter",
76 | "first_time_counter",
77 | "periodic_counter",
78 | "time_counter",
79 | },
80 | )
81 | async def example_template(collected: dict[str, Any], bg: "BgData", **_):
82 | template = template_env.get_template("index.html.jinja")
83 | html = await template.render_async(d=collected, config=template_config)
84 |
85 | # copy 一份以添加这次图片渲染中特定的 router
86 | router_group = template_router_group.copy()
87 | add_root_router(router_group, html) # 注册根路由,访问返回渲好的 html
88 | add_background_router(router_group, bg) # 注册背景图片路由
89 |
90 | async with get_new_page() as page:
91 | await router_group.apply(page)
92 | await page.goto(f"{ROUTE_URL}/", wait_until="load")
93 | elem = await page.wait_for_selector("main")
94 | assert elem
95 | return await elem.screenshot(type="jpeg")
96 |
--------------------------------------------------------------------------------
/examples/external_example/templates/example_template/res/index.html.jinja:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
Example Template
30 |
This is an example status picture template.
31 |
32 |
33 |
d = {{ d | json_dumps(indent=2) }}
34 |
config = {{ config.model_dump_json(indent=2) }}
35 |
36 |
37 |
38 |

39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/__init__.py:
--------------------------------------------------------------------------------
1 | # ruff: noqa: E402
2 |
3 | from nonebot import get_driver, require
4 | from nonebot.plugin import PluginMetadata, inherit_supported_adapters
5 |
6 | require("nonebot_plugin_apscheduler")
7 | require("nonebot_plugin_alconna")
8 | require("nonebot_plugin_userinfo")
9 |
10 | from . import __main__ as __main__, misc_statistics as misc_statistics
11 | from .bg_provider import bg_preloader
12 | from .collectors import (
13 | enable_collectors,
14 | load_builtin_collectors,
15 | registered_collectors,
16 | )
17 | from .config import ConfigModel, config
18 | from .templates import load_builtin_templates, loaded_templates
19 |
20 | driver = get_driver()
21 |
22 |
23 | # lazy load builtin templates and collectors
24 | @driver.on_startup
25 | async def _():
26 | if config.ps_template not in loaded_templates:
27 | load_builtin_templates()
28 | current_template = loaded_templates.get(config.ps_template)
29 | if current_template is None:
30 | raise ValueError(f"Template {config.ps_template} not found")
31 |
32 | if (current_template.collectors is None) or any(
33 | (x not in registered_collectors) for x in current_template.collectors
34 | ):
35 | load_builtin_collectors()
36 |
37 | collectors = (
38 | set(registered_collectors)
39 | if current_template.collectors is None
40 | else current_template.collectors
41 | )
42 | await enable_collectors(*collectors)
43 |
44 | bg_preloader.start_preload()
45 |
46 |
47 | usage = f"指令:{' / '.join(config.ps_command)}"
48 | if config.ps_need_at:
49 | usage += "\n注意:使用指令时需要@机器人"
50 | if config.ps_only_su:
51 | usage += "\n注意:仅SuperUser可以使用此指令"
52 |
53 | __version__ = "2.1.3.post1"
54 | __plugin_meta__ = PluginMetadata(
55 | name="PicStatus",
56 | description="以图片形式显示当前设备的运行状态",
57 | usage=usage,
58 | type="application",
59 | homepage="https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus",
60 | config=ConfigModel,
61 | supported_adapters=inherit_supported_adapters(
62 | "nonebot_plugin_alconna",
63 | "nonebot_plugin_userinfo",
64 | ),
65 | extra={"License": "MIT", "Author": "LgCookie"},
66 | )
67 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/__main__.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from contextlib import suppress
3 | from typing import Optional
4 |
5 | from nonebot import logger, on_command
6 | from nonebot.adapters import Bot as BaseBot, Event as BaseEvent, Message as BaseMessage
7 | from nonebot.matcher import current_bot, current_event, current_matcher
8 | from nonebot.params import CommandArg, Depends
9 | from nonebot.permission import SUPERUSER
10 | from nonebot.rule import Rule, to_me
11 | from nonebot_plugin_alconna.uniseg import Image, Reply, UniMessage, UniMsg, image_fetch
12 |
13 | from .bg_provider import BgData, bg_preloader
14 | from .collectors import collect_all
15 | from .config import config
16 | from .misc_statistics import cache_bot_info
17 | from .templates import render_current_template
18 |
19 |
20 | def check_empty_arg_rule(arg: BaseMessage = CommandArg()):
21 | return not arg.extract_plain_text()
22 |
23 |
24 | def trigger_rule():
25 | rule = Rule(check_empty_arg_rule)
26 | if config.ps_need_at:
27 | rule &= to_me()
28 | return rule
29 |
30 |
31 | _cmd, *_alias = config.ps_command
32 | stat_matcher = on_command(
33 | _cmd,
34 | aliases=set(_alias),
35 | rule=trigger_rule(),
36 | permission=SUPERUSER if config.ps_only_su else None,
37 | )
38 |
39 |
40 | async def _msg_pic(msg: UniMsg) -> Optional[BgData]:
41 | msg = (
42 | r
43 | if (
44 | Reply in msg
45 | and isinstance((r_org := msg[Reply, 0].msg), BaseMessage)
46 | and Image in (r := await UniMessage.generate(message=r_org))
47 | )
48 | else msg
49 | )
50 | if Image not in msg:
51 | return None
52 | img = msg[Image, 0]
53 | data = await image_fetch(
54 | current_event.get(),
55 | current_bot.get(),
56 | current_matcher.get().state,
57 | img,
58 | )
59 | if not data:
60 | return None
61 | return BgData(data=data, mime=img.mimetype or "image")
62 |
63 |
64 | def MsgPic(): # noqa: N802
65 | return Depends(_msg_pic)
66 |
67 |
68 | @stat_matcher.handle()
69 | async def _(bot: BaseBot, event: BaseEvent, msg_pic: Optional[BgData] = MsgPic()):
70 | with suppress(Exception):
71 | await cache_bot_info(bot, event)
72 |
73 | async def get_bg():
74 | return msg_pic or (await bg_preloader.get())
75 |
76 | try:
77 | bg, collected = await asyncio.gather(get_bg(), collect_all())
78 | ret = await render_current_template(collected=collected, bg=bg)
79 | except Exception:
80 | logger.exception("获取运行状态图失败")
81 | await UniMessage("获取运行状态图片失败,请检查后台输出").send(
82 | reply_to=config.ps_reply_target,
83 | )
84 | else:
85 | await UniMessage.image(raw=ret).send(reply_to=config.ps_reply_target)
86 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/bg_provider.py:
--------------------------------------------------------------------------------
1 | import asyncio as aio
2 | import mimetypes
3 | import random
4 | from collections.abc import Awaitable
5 | from typing import TYPE_CHECKING, Callable, NamedTuple, Optional, TypeVar
6 |
7 | import anyio
8 | from httpx import AsyncClient, Response
9 | from nonebot import logger
10 |
11 | from .config import DEFAULT_BG_PATH, config
12 |
13 | if TYPE_CHECKING:
14 | from pathlib import Path
15 |
16 |
17 | class BgData(NamedTuple):
18 | data: bytes
19 | mime: str
20 |
21 |
22 | BGProviderType = Callable[[], Awaitable[BgData]]
23 | TBP = TypeVar("TBP", bound=BGProviderType)
24 |
25 | registered_bg_providers: dict[str, BGProviderType] = {}
26 |
27 |
28 | def get_bg_files() -> list["Path"]:
29 | if not config.ps_bg_local_path.exists():
30 | logger.warning("Custom background path does not exist, fallback to default")
31 | return [DEFAULT_BG_PATH]
32 | if config.ps_bg_local_path.is_file():
33 | return [config.ps_bg_local_path]
34 |
35 | files = [x for x in config.ps_bg_local_path.glob("*") if x.is_file()]
36 | if not files:
37 | logger.warning("Custom background dir has no file in it, fallback to default")
38 | return [DEFAULT_BG_PATH]
39 | return files
40 |
41 |
42 | BG_FILES = get_bg_files()
43 |
44 |
45 | def bg_provider(name: Optional[str] = None):
46 | def deco(func: TBP) -> TBP:
47 | provider_name = name or func.__name__
48 | if provider_name in registered_bg_providers:
49 | raise ValueError(f"Duplicate bg provider name `{provider_name}`")
50 | registered_bg_providers[provider_name] = func
51 | return func
52 |
53 | return deco
54 |
55 |
56 | def resp_to_bg_data(resp: Response):
57 | return BgData(
58 | resp.content,
59 | (resp.headers.get("Content-Type") or "application/octet-stream"),
60 | )
61 |
62 |
63 | @bg_provider()
64 | async def loli():
65 | async with AsyncClient(
66 | follow_redirects=True,
67 | proxy=config.proxy,
68 | timeout=config.ps_req_timeout,
69 | ) as cli:
70 | return resp_to_bg_data(
71 | (await cli.get("https://www.loliapi.com/acg/pe/")).raise_for_status(),
72 | )
73 |
74 |
75 | @bg_provider()
76 | async def lolicon():
77 | async with AsyncClient(
78 | follow_redirects=True,
79 | proxy=config.proxy,
80 | timeout=config.ps_req_timeout,
81 | ) as cli:
82 | resp = await cli.get(
83 | "https://api.lolicon.app/setu/v2",
84 | params={
85 | "r18": config.ps_bg_lolicon_r18_type,
86 | "proxy": "false",
87 | "excludeAI": "true",
88 | },
89 | )
90 | url = resp.raise_for_status().json()["data"][0]["urls"]["original"]
91 | resp = await cli.get(
92 | url,
93 | headers={
94 | "User-Agent": (
95 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
96 | "AppleWebKit/537.36 (KHTML, like Gecko) "
97 | "Chrome/119.0.0.0 "
98 | "Safari/537.36"
99 | ),
100 | "Referer": "https://www.pixiv.net/",
101 | },
102 | )
103 | return resp_to_bg_data(resp)
104 |
105 |
106 | @bg_provider()
107 | async def local():
108 | file = random.choice(BG_FILES)
109 | logger.debug(f"Choice background file `{file}`")
110 | return BgData(
111 | await anyio.Path(file).read_bytes(),
112 | mimetypes.guess_type(file)[0] or "application/octet-stream",
113 | )
114 |
115 |
116 | @bg_provider()
117 | async def none():
118 | return BgData(b"", "application/octet-stream")
119 |
120 |
121 | async def fetch_bg() -> BgData:
122 | if config.ps_bg_provider in registered_bg_providers:
123 | try:
124 | return await registered_bg_providers[config.ps_bg_provider]()
125 | except Exception:
126 | logger.exception("Error when getting background, fallback to local")
127 | else:
128 | logger.warning(
129 | f"Unknown background provider `{config.ps_bg_provider}`, fallback to local",
130 | )
131 | return await local()
132 |
133 |
134 | class BgPreloader:
135 | def __init__(self, preload_count: int):
136 | if preload_count < 1:
137 | raise ValueError("preload_count must be greater than 0")
138 | self.preload_count = preload_count
139 | self.backgrounds: list[BgData] = []
140 | self.tasks: list[aio.Task[None]] = []
141 | self.task_signal: Optional[aio.Future[None]] = None
142 | self.signal_wait_lock = aio.Lock()
143 |
144 | def _get_signal(self) -> aio.Future[None]:
145 | if (not self.task_signal) or self.task_signal.done():
146 | self.task_signal = aio.Future()
147 | return self.task_signal
148 |
149 | def _wait_signal(self):
150 | async def inner():
151 | async with self.signal_wait_lock:
152 | await self._get_signal()
153 |
154 | return aio.wait_for(inner(), timeout=15)
155 |
156 | def create_preload_task(self):
157 | async def task_func():
158 | logger.debug("Started a preload background task")
159 | try:
160 | bg = await fetch_bg()
161 | except Exception as e:
162 | # fetch_bg has fallback so it should ensure we can get a bg
163 | # if error occurred this should be an unexpected error
164 | # need to let this error raise
165 | logger.opt(exception=e).debug("Exception when preloading")
166 | if not (s := self._get_signal()).done():
167 | s.set_exception(e)
168 | else:
169 | logger.debug("A preload task done")
170 | self.backgrounds.append(bg)
171 | if not (s := self._get_signal()).done():
172 | s.set_result(None)
173 | finally:
174 | self.tasks.remove(task)
175 |
176 | task = aio.create_task(task_func())
177 | self.tasks.append(task)
178 |
179 | def start_preload(self, create_when_full: bool = False):
180 | task_count = self.preload_count - len(self.backgrounds) - len(self.tasks)
181 | if task_count <= 0:
182 | if not create_when_full:
183 | return
184 | task_count = 1
185 | logger.debug(f"Will preload {task_count} backgrounds")
186 | for _ in range(task_count):
187 | self.create_preload_task()
188 |
189 | async def get(self) -> BgData:
190 | if not self.backgrounds:
191 | self.start_preload(create_when_full=True)
192 | if self.tasks:
193 | await self._wait_signal()
194 | if not self.backgrounds:
195 | raise RuntimeError("Failed to wait background")
196 | bg = self.backgrounds.pop(0)
197 | self.start_preload()
198 | return bg
199 |
200 |
201 | bg_preloader = BgPreloader(config.ps_bg_preload_count)
202 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/collectors/__init__.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import importlib
3 | import time
4 | from abc import abstractmethod
5 | from collections import deque
6 | from collections.abc import Awaitable
7 | from pathlib import Path
8 | from typing import Any, Callable, Generic, Optional, TypeVar, Union
9 | from typing_extensions import override
10 |
11 | from nonebot import logger
12 | from nonebot_plugin_apscheduler import scheduler
13 |
14 | from ..config import config
15 |
16 | T = TypeVar("T")
17 | TI = TypeVar("TI")
18 | TR = TypeVar("TR")
19 | TC = TypeVar("TC", bound="Collector")
20 | TCF = TypeVar("TCF", bound=Callable[[], Awaitable[Any]])
21 | R = TypeVar("R")
22 |
23 | Undefined = type("Undefined", (), {})
24 |
25 |
26 | class SkipCollectError(Exception):
27 | pass
28 |
29 |
30 | class Collector(Generic[TI, TR]):
31 | @abstractmethod
32 | async def _get(self) -> TI: ...
33 |
34 | @abstractmethod
35 | async def get(self) -> TR: ...
36 |
37 |
38 | class BaseNormalCollector(Collector[T, T], Generic[T]):
39 | def __init__(self) -> None:
40 | super().__init__()
41 |
42 | @override
43 | async def get(self) -> T:
44 | return await self._get()
45 |
46 |
47 | class BaseFirstTimeCollector(Collector[T, T], Generic[T]):
48 | def __init__(self) -> None:
49 | super().__init__()
50 | self._cached: Union[T, Undefined] = Undefined()
51 |
52 | @override
53 | async def get(self) -> T:
54 | if not isinstance(self._cached, Undefined):
55 | return self._cached
56 | data = await self._get()
57 | self._cached = data
58 | return data
59 |
60 |
61 | class BasePeriodicCollector(Collector[T, deque[T]], Generic[T]):
62 | def __init__(self, size: int = config.ps_default_collect_cache_size) -> None:
63 | super().__init__()
64 | self.data = deque(maxlen=size)
65 |
66 | @override
67 | async def get(self) -> deque[T]:
68 | return self.data
69 |
70 | async def collect(self):
71 | try:
72 | data = await self._get()
73 | except SkipCollectError:
74 | return
75 | except Exception:
76 | logger.exception("Error occurred while collecting data")
77 | else:
78 | self.data.append(data)
79 |
80 |
81 | registered_collectors: dict[str, type[Collector]] = {}
82 | enabled_collectors: dict[str, Collector] = {}
83 |
84 |
85 | def collector(name: str):
86 | def deco(cls: type[TC]) -> type[TC]:
87 | if name in registered_collectors:
88 | raise ValueError(f"Collector {name} already exists")
89 | registered_collectors[name] = cls
90 | logger.debug(f"Registered collector {name}")
91 | return cls
92 |
93 | return deco
94 |
95 |
96 | def _enable_collector(name: str):
97 | if name not in registered_collectors:
98 | raise ValueError(f"Collector {name} not found")
99 | cls = registered_collectors[name]
100 | if issubclass(cls, BasePeriodicCollector) and name in config.ps_collect_cache_size:
101 | instance = cls(size=config.ps_collect_cache_size[name])
102 | else:
103 | instance = cls()
104 | enabled_collectors[name] = instance
105 |
106 |
107 | async def enable_collectors(*names: str):
108 | for name in names:
109 | _enable_collector(name)
110 | await init_first_time_collectors()
111 | await collect_perodic_collectors()
112 |
113 |
114 | def functional_collector(cls: type[Collector], name: Optional[str] = None):
115 | def deco(func: TCF) -> TCF:
116 | collector_name = name or func.__name__
117 | if not collector_name:
118 | raise ValueError("name must be provided")
119 |
120 | class Collector(cls):
121 | async def _get(self) -> Any:
122 | return await func()
123 |
124 | collector(collector_name)(Collector)
125 | return func
126 |
127 | return deco
128 |
129 |
130 | def normal_collector(name: Optional[str] = None):
131 | return functional_collector(BaseNormalCollector, name)
132 |
133 |
134 | def first_time_collector(name: Optional[str] = None):
135 | return functional_collector(BaseFirstTimeCollector, name)
136 |
137 |
138 | def periodic_collector(name: Optional[str] = None):
139 | return functional_collector(BasePeriodicCollector, name)
140 |
141 |
142 | class TimeBasedCounterCollector(BasePeriodicCollector[R], Generic[T, R]):
143 | def __init__(self, size: int = config.ps_default_collect_cache_size) -> None:
144 | super().__init__(size)
145 | self.last_obj: Union[Undefined, T] = Undefined()
146 | self.last_time: float = 0
147 |
148 | @abstractmethod
149 | async def _calc(self, past: T, now: T, time_passed: float) -> R: ...
150 |
151 | @abstractmethod
152 | async def _get_obj(self) -> T: ...
153 |
154 | @override
155 | async def _get(self) -> R:
156 | past = self.last_obj
157 | past_time = self.last_time
158 | time_now = time.time()
159 | time_passed = time_now - past_time
160 |
161 | self.last_time = time_now
162 | self.last_obj = await self._get_obj()
163 | if isinstance(past, Undefined):
164 | raise SkipCollectError
165 | return await self._calc(past, self.last_obj, time_passed)
166 |
167 |
168 | async def collect_all() -> dict[str, Any]:
169 | async def get(name: str):
170 | return name, await enabled_collectors[name].get()
171 |
172 | res = await asyncio.gather(*(get(name) for name in enabled_collectors))
173 | return dict(res)
174 |
175 |
176 | def load_builtin_collectors():
177 | for module in Path(__file__).parent.iterdir():
178 | if not module.name.startswith("_"):
179 | importlib.import_module(f".{module.stem}", __package__)
180 |
181 |
182 | async def init_first_time_collectors():
183 | await asyncio.gather(
184 | *(
185 | x.get()
186 | for x in enabled_collectors.values()
187 | if isinstance(x, BaseFirstTimeCollector)
188 | ),
189 | )
190 |
191 |
192 | @scheduler.scheduled_job("interval", seconds=config.ps_collect_interval)
193 | async def collect_perodic_collectors():
194 | await asyncio.gather(
195 | *(
196 | x.collect()
197 | for x in enabled_collectors.values()
198 | if isinstance(x, BasePeriodicCollector)
199 | ),
200 | )
201 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/collectors/bot.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from dataclasses import dataclass
3 | from datetime import datetime
4 | from typing import TYPE_CHECKING, Optional
5 |
6 | from nonebot import get_bots, logger
7 | from nonebot.matcher import current_bot
8 |
9 | from ..config import config
10 | from ..misc_statistics import (
11 | bot_connect_time,
12 | bot_info_cache,
13 | recv_num,
14 | send_num,
15 | )
16 | from ..util import format_timedelta
17 | from . import normal_collector
18 |
19 | if TYPE_CHECKING:
20 | from nonebot.adapters import Bot as BaseBot
21 |
22 | try:
23 | from nonebot.adapters.onebot.v11 import Bot as OBV11Bot
24 | except ImportError:
25 | OBV11Bot = None
26 |
27 |
28 | @dataclass
29 | class BotStatus:
30 | self_id: str
31 | adapter: str
32 | nick: str
33 | bot_connected: str
34 | msg_rec: str
35 | msg_sent: str
36 |
37 |
38 | async def get_ob11_msg_num(bot: "BaseBot") -> tuple[Optional[int], Optional[int]]:
39 | if not (config.ps_ob_v11_use_get_status and OBV11Bot and isinstance(bot, OBV11Bot)):
40 | return None, None
41 |
42 | try:
43 | bot_stat = (await bot.get_status()).get("stat")
44 | except Exception as e:
45 | logger.warning(
46 | f"Error when getting bot status: {e.__class__.__name__}: {e}",
47 | )
48 | return None, None
49 | if not bot_stat:
50 | return None, None
51 |
52 | msg_rec = bot_stat.get("message_received") or bot_stat.get(
53 | "MessageReceived",
54 | )
55 | msg_sent = bot_stat.get("message_sent") or bot_stat.get("MessageSent")
56 | return msg_rec, msg_sent
57 |
58 |
59 | async def get_bot_status(bot: "BaseBot", now_time: datetime) -> BotStatus:
60 | nick = (
61 | ((info := bot_info_cache[bot.self_id]).user_displayname or info.user_name)
62 | if (not config.ps_use_env_nick) and (bot.self_id in bot_info_cache)
63 | else next(iter(config.nickname), None)
64 | ) or "Bot"
65 | bot_connected = (
66 | format_timedelta(now_time - t)
67 | if (t := bot_connect_time.get(bot.self_id))
68 | else "未知"
69 | )
70 |
71 | msg_rec, msg_sent = await get_ob11_msg_num(bot)
72 | if msg_rec is None:
73 | msg_rec = recv_num.get(bot.self_id)
74 | if msg_sent is None:
75 | msg_sent = send_num.get(bot.self_id)
76 | msg_rec = "未知" if (msg_rec is None) else str(msg_rec)
77 | msg_sent = "未知" if (msg_sent is None) else str(msg_sent)
78 |
79 | return BotStatus(
80 | self_id=bot.self_id,
81 | adapter=bot.adapter.get_name(),
82 | nick=nick,
83 | bot_connected=bot_connected,
84 | msg_rec=msg_rec,
85 | msg_sent=msg_sent,
86 | )
87 |
88 |
89 | @normal_collector()
90 | async def bots() -> list[BotStatus]:
91 | now_time = datetime.now().astimezone()
92 | return (
93 | [await get_bot_status(current_bot.get(), now_time)]
94 | if config.ps_show_current_bot_only
95 | else await asyncio.gather(
96 | *(get_bot_status(bot, now_time) for bot in get_bots().values()),
97 | )
98 | )
99 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/collectors/cpu.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from typing import Optional, cast
3 |
4 | import psutil
5 | from cpuinfo import get_cpu_info
6 | from nonebot import logger
7 |
8 | from . import first_time_collector, periodic_collector
9 |
10 |
11 | @dataclass
12 | class CpuFreq:
13 | current: Optional[float]
14 | min: Optional[float] # noqa: A003
15 | max: Optional[float] # noqa: A003
16 |
17 |
18 | @first_time_collector()
19 | async def cpu_brand() -> str:
20 | try:
21 | brand = (
22 | cast("str", get_cpu_info().get("brand_raw", ""))
23 | .split("@", maxsplit=1)[0]
24 | .strip()
25 | )
26 | if brand.lower().endswith(("cpu", "processor")):
27 | brand = brand.rsplit(maxsplit=1)[0].strip()
28 | except Exception:
29 | logger.exception("Error when getting CPU brand")
30 | return "未知型号"
31 | else:
32 | return brand
33 |
34 |
35 | @first_time_collector()
36 | async def cpu_count_logical() -> int:
37 | return psutil.cpu_count()
38 |
39 |
40 | @first_time_collector()
41 | async def cpu_count() -> int:
42 | return psutil.cpu_count(logical=False)
43 |
44 |
45 | @periodic_collector()
46 | async def cpu_percent() -> float:
47 | return psutil.cpu_percent()
48 |
49 |
50 | @periodic_collector()
51 | async def cpu_freq() -> CpuFreq:
52 | cpu_freq = psutil.cpu_freq()
53 | return CpuFreq(
54 | current=getattr(cpu_freq, "current", None),
55 | min=getattr(cpu_freq, "min", None),
56 | max=getattr(cpu_freq, "max", None),
57 | )
58 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/collectors/disk.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from typing import Optional, Union
3 |
4 | import psutil
5 | from nonebot import logger
6 | from psutil._common import sdiskio, sdiskpart
7 |
8 | from ..config import config
9 | from ..util import match_list_regexp
10 | from . import TimeBasedCounterCollector, collector, periodic_collector
11 |
12 |
13 | @dataclass
14 | class DiskUsageNormal:
15 | name: str
16 | percent: float
17 | used: int
18 | total: int
19 |
20 |
21 | @dataclass
22 | class DiskUsageWithExc:
23 | name: str
24 | exception: str
25 |
26 |
27 | DiskUsageType = Union[DiskUsageNormal, DiskUsageWithExc]
28 |
29 |
30 | @dataclass
31 | class DiskIO:
32 | name: str
33 | read: float
34 | write: float
35 |
36 |
37 | @periodic_collector()
38 | async def disk_usage() -> list[DiskUsageType]:
39 | def get_one(disk: sdiskpart) -> Optional[DiskUsageType]:
40 | mountpoint = disk.mountpoint
41 |
42 | if match_list_regexp(config.ps_ignore_parts, mountpoint):
43 | # logger.info(f"空间读取 分区 {mountpoint} 匹配 {regex.re.pattern},忽略")
44 | return None
45 |
46 | try:
47 | usage = psutil.disk_usage(mountpoint)
48 | except Exception as e:
49 | logger.exception(f"读取 {mountpoint} 占用失败")
50 | return (
51 | None
52 | if config.ps_ignore_bad_parts
53 | else DiskUsageWithExc(name=mountpoint, exception=str(e))
54 | )
55 |
56 | return DiskUsageNormal(
57 | name=mountpoint,
58 | percent=usage.percent,
59 | used=usage.used,
60 | total=usage.total,
61 | )
62 |
63 | usage = [x for x in map(get_one, psutil.disk_partitions()) if x]
64 | if config.ps_sort_parts:
65 | usage.sort(
66 | key=lambda x: x.percent if isinstance(x, DiskUsageNormal) else -1,
67 | reverse=not config.ps_sort_parts_reverse,
68 | )
69 |
70 | return usage
71 |
72 |
73 | @collector("disk_io")
74 | class DiskIOCollector(TimeBasedCounterCollector[dict[str, sdiskio], list[DiskIO]]):
75 | async def _calc(
76 | self,
77 | past: dict[str, sdiskio],
78 | now: dict[str, sdiskio],
79 | time_passed: float,
80 | ) -> list[DiskIO]:
81 | def calc_one(name: str, past_it: sdiskio, now_it: sdiskio) -> Optional[DiskIO]:
82 | if match_list_regexp(config.ps_ignore_disk_ios, name):
83 | # logger.info(f"IO统计 磁盘 {name} 匹配 {regex.re.pattern},忽略")
84 | return None
85 |
86 | read = (now_it.read_bytes - past_it.read_bytes) / time_passed
87 | write = (now_it.write_bytes - past_it.write_bytes) / time_passed
88 |
89 | if read == 0 and write == 0 and config.ps_ignore_no_io_disk:
90 | # logger.info(f"IO统计 忽略无IO磁盘 {name}")
91 | return None
92 |
93 | return DiskIO(name=name, read=read, write=write)
94 |
95 | res = [calc_one(name, past[name], now[name]) for name in past if name in now]
96 | res = [x for x in res if x]
97 | if config.ps_sort_disk_ios:
98 | res.sort(key=lambda x: x.read + x.write, reverse=True)
99 | return res
100 |
101 | async def _get_obj(self) -> dict[str, sdiskio]:
102 | return psutil.disk_io_counters(perdisk=True)
103 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/collectors/mem.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 |
3 | import psutil
4 |
5 | from . import periodic_collector
6 |
7 |
8 | @dataclass
9 | class MemoryStat:
10 | percent: float
11 | used: int
12 | total: int
13 |
14 |
15 | @periodic_collector()
16 | async def memory_stat() -> MemoryStat:
17 | mem = psutil.virtual_memory()
18 | return MemoryStat(percent=mem.percent, used=mem.used, total=mem.total)
19 |
20 |
21 | @periodic_collector()
22 | async def swap_stat() -> MemoryStat:
23 | swap = psutil.swap_memory()
24 | return MemoryStat(percent=swap.percent, used=swap.used, total=swap.total)
25 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/collectors/misc.py:
--------------------------------------------------------------------------------
1 | import os
2 | import platform
3 | import time
4 | from datetime import datetime
5 | from pathlib import Path
6 | from typing import Optional, Union
7 |
8 | import nonebot
9 | import psutil
10 |
11 | from ..misc_statistics import nonebot_run_time
12 | from ..util import format_time_delta_ps
13 | from . import first_time_collector, normal_collector, periodic_collector
14 |
15 |
16 | def parse_env(env: str) -> dict[str, Optional[str]]:
17 | env_lines = env.strip().splitlines()
18 | env_dict: dict[str, Optional[str]] = {}
19 |
20 | for line in env_lines:
21 | if "=" not in line:
22 | env_dict[line.upper()] = None
23 | continue
24 |
25 | key, value = line.split("=", 1)
26 | env_dict[key.upper()] = value.strip("\"'").strip()
27 |
28 | return env_dict
29 |
30 |
31 | def parse_env_file(env_file: Union[str, Path]) -> Optional[dict[str, Optional[str]]]:
32 | if not isinstance(env_file, Path):
33 | env_file = Path(env_file)
34 | if not env_file.exists():
35 | return None
36 | content = env_file.read_text(encoding="u8")
37 | return parse_env(content)
38 |
39 |
40 | # Thanks to https://github.com/nonedesktop/nonebot-plugin-guestool/blob/main/nonebot_plugin_guestool/info.py
41 | def get_linux_name_version() -> Optional[tuple[str, str]]:
42 | env = parse_env_file("/etc/os-release")
43 | if env and (name := env.get("NAME")) and (version_id := env.get("VERSION_ID")):
44 | return name, version_id
45 |
46 | env = parse_env_file("/etc/lsb-release")
47 | if (
48 | env
49 | and (name := env.get("DISTRIB_ID"))
50 | and (version_id := env.get("DISTRIB_RELEASE"))
51 | ):
52 | return name, version_id
53 |
54 | return None
55 |
56 |
57 | @normal_collector("nonebot_run_time")
58 | async def nonebot_run_time_str() -> str:
59 | now_time = datetime.now().astimezone()
60 | return (
61 | format_time_delta_ps(now_time - nonebot_run_time)
62 | if nonebot_run_time
63 | else "未知"
64 | )
65 |
66 |
67 | @normal_collector()
68 | async def system_run_time() -> str:
69 | now_time = datetime.now().astimezone()
70 | return format_time_delta_ps(
71 | now_time - datetime.fromtimestamp(psutil.boot_time()).astimezone(),
72 | )
73 |
74 |
75 | @first_time_collector()
76 | async def nonebot_version() -> str:
77 | return nonebot.__version__
78 |
79 |
80 | @first_time_collector()
81 | async def ps_version() -> str:
82 | from .. import __version__
83 |
84 | return __version__
85 |
86 |
87 | @periodic_collector("time")
88 | async def time_str() -> str:
89 | return time.strftime("%Y-%m-%d %H:%M:%S")
90 |
91 |
92 | @first_time_collector()
93 | async def python_version() -> str:
94 | return f"{platform.python_implementation()} {platform.python_version()}"
95 |
96 |
97 | @first_time_collector()
98 | async def system_name():
99 | system, _, release, version, machine, _ = platform.uname()
100 | system, release, version = platform.system_alias(system, release, version)
101 |
102 | if system == "Java":
103 | _, _, _, (system, release, machine) = platform.java_ver()
104 |
105 | if system == "Darwin":
106 | return f"MacOS {platform.mac_ver()[0]} {machine}"
107 |
108 | if system == "Windows":
109 | return f"Windows {release} {platform.win32_edition()} {machine}"
110 |
111 | if system == "Linux":
112 | if (pfx := os.getenv("PREFIX")) and "termux" in pfx:
113 | system = f"Termux (Android) {release}" # a strange platform
114 |
115 | elif os.getenv("ANDROID_ROOT") == "/system":
116 | system = f"Linux (Android) {release}"
117 |
118 | elif ver := get_linux_name_version():
119 | name, version_id = ver
120 | version = release if version_id.lower() == "rolling" else version_id
121 | system = f"{name} {version}"
122 |
123 | else:
124 | system = f"未知 Linux {release}"
125 |
126 | return f"{system} {machine}"
127 |
128 | return f"{system} {release}"
129 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/collectors/network.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import time
3 | from dataclasses import dataclass
4 | from typing import Optional, Union
5 |
6 | import psutil
7 | from httpx import AsyncClient, ReadTimeout
8 | from psutil._common import snetio
9 |
10 | from ..config import TestSiteCfg, config
11 | from ..util import match_list_regexp
12 | from . import TimeBasedCounterCollector, collector, normal_collector
13 |
14 |
15 | @dataclass
16 | class NetworkIO:
17 | name: str
18 | sent: float
19 | recv: float
20 |
21 |
22 | @dataclass
23 | class NetworkConnectionOK:
24 | name: str
25 | status: int
26 | reason: str
27 | delay: float
28 |
29 |
30 | @dataclass
31 | class NetworkConnectionError:
32 | name: str
33 | error: str
34 |
35 |
36 | NetworkConnectionType = Union[NetworkConnectionOK, NetworkConnectionError]
37 |
38 |
39 | @collector("network_io")
40 | class NetworkIOCollector(TimeBasedCounterCollector[dict[str, snetio], list[NetworkIO]]):
41 | async def _calc(
42 | self,
43 | past: dict[str, snetio],
44 | now: dict[str, snetio],
45 | time_passed: float,
46 | ) -> list[NetworkIO]:
47 | def calc_one(name: str, past_it: snetio, now_it: snetio) -> Optional[NetworkIO]:
48 | if match_list_regexp(config.ps_ignore_nets, name):
49 | # logger.info(f"网卡IO统计 {name} 匹配 {regex.re.pattern},忽略")
50 | return None
51 |
52 | sent = (now_it.bytes_sent - past_it.bytes_sent) / time_passed
53 | recv = (now_it.bytes_recv - past_it.bytes_recv) / time_passed
54 |
55 | if sent == 0 and recv == 0 and config.ps_ignore_0b_net:
56 | # logger.info(f"网卡IO统计 忽略无IO网卡 {name}")
57 | return None
58 |
59 | return NetworkIO(name=name, sent=sent, recv=recv)
60 |
61 | res = [calc_one(name, past[name], now[name]) for name in past if name in now]
62 | res = [x for x in res if x]
63 | if config.ps_sort_nets:
64 | res.sort(key=lambda x: x.sent + x.recv, reverse=True)
65 | return res
66 |
67 | async def _get_obj(self) -> dict[str, snetio]:
68 | return psutil.net_io_counters(pernic=True)
69 |
70 |
71 | @normal_collector()
72 | async def network_connection() -> list[NetworkConnectionType]:
73 | def format_conn_error(error: Exception) -> str:
74 | if isinstance(error, ReadTimeout):
75 | return "超时"
76 | return error.__class__.__name__
77 |
78 | async def test_one(site: TestSiteCfg) -> NetworkConnectionType:
79 | try:
80 | async with AsyncClient(
81 | timeout=config.ps_test_timeout,
82 | proxy=config.proxy if site.use_proxy else None,
83 | follow_redirects=True,
84 | ) as client:
85 | start = time.time()
86 | resp = await client.get(str(site.url))
87 | delay = (time.time() - start) * 1000
88 |
89 | except Exception as e:
90 | return NetworkConnectionError(name=site.name, error=format_conn_error(e))
91 |
92 | return NetworkConnectionOK(
93 | name=site.name,
94 | status=resp.status_code,
95 | reason=resp.reason_phrase,
96 | delay=delay,
97 | )
98 |
99 | res = await asyncio.gather(*map(test_one, config.ps_test_sites))
100 | if config.ps_sort_sites:
101 | res.sort(key=lambda x: x.delay if isinstance(x, NetworkConnectionOK) else -1)
102 |
103 | return res
104 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/collectors/process.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from dataclasses import dataclass
3 | from typing import Optional, Union, cast
4 |
5 | import psutil
6 |
7 | from ..config import config
8 | from ..util import match_list_regexp
9 | from . import periodic_collector
10 |
11 |
12 | @dataclass
13 | class ProcessStatus:
14 | name: str
15 | cpu: float
16 | mem: int
17 |
18 |
19 | @periodic_collector()
20 | async def process_status() -> list[ProcessStatus]:
21 | if not config.ps_proc_len:
22 | return []
23 |
24 | async def parse_one(proc: psutil.Process) -> Optional[ProcessStatus]:
25 | name = proc.name()
26 | if match_list_regexp(config.ps_ignore_procs, name):
27 | # logger.info(f"进程 {name} 匹配 {regex.re.pattern},忽略")
28 | return None
29 |
30 | # proc.cpu_percent()
31 | # await asyncio.sleep(1)
32 | with proc.oneshot():
33 | cpu = proc.cpu_percent()
34 | cpu = cpu / psutil.cpu_count() if config.ps_proc_cpu_max_100p else cpu
35 | mem: int = proc.memory_info().rss
36 |
37 | return ProcessStatus(name=name, cpu=cpu, mem=mem)
38 |
39 | def sorter(x: ProcessStatus):
40 | sort_by = config.ps_proc_sort_by
41 | if sort_by == "mem":
42 | return x.mem
43 | # if sort_by == "cpu":
44 | return x.cpu
45 |
46 | proc_list = cast(
47 | "list[Union[Optional[ProcessStatus], Exception]]",
48 | await asyncio.gather(
49 | *(parse_one(proc) for proc in psutil.process_iter()),
50 | return_exceptions=True,
51 | ),
52 | )
53 | proc_list = [x for x in proc_list if x and (not isinstance(x, Exception))]
54 | proc_list.sort(key=sorter, reverse=True)
55 | return proc_list[: config.ps_proc_len]
56 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/config.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 | from typing import Literal, Optional, Union
3 |
4 | from nonebot import get_plugin_config
5 | from nonebot.compat import type_validate_python
6 | from pydantic import AnyHttpUrl, BaseModel, Field
7 |
8 | RES_PATH = Path(__file__).parent / "res"
9 | ASSETS_PATH = RES_PATH / "assets"
10 | TEMPLATE_PATH = RES_PATH / "templates"
11 | DEFAULT_BG_PATH = ASSETS_PATH / "default_bg.webp"
12 | DEFAULT_AVATAR_PATH = ASSETS_PATH / "default_avatar.webp"
13 |
14 | ProcSortByType = Literal["cpu", "mem"]
15 |
16 |
17 | class TestSiteCfg(BaseModel):
18 | name: str
19 | url: AnyHttpUrl
20 | use_proxy: bool = False
21 |
22 |
23 | class ConfigModel(BaseModel):
24 | # region builtin
25 | superusers: set[str]
26 | nickname: set[str]
27 | # endregion
28 |
29 | # region global
30 | proxy: Optional[str] = None
31 | # endregion
32 |
33 | # region behavior
34 | ps_template: str = "default"
35 | ps_command: list[str] = ["运行状态", "状态", "zt", "yxzt", "status"]
36 | ps_only_su: bool = False
37 | ps_need_at: bool = False
38 | ps_reply_target: bool = True
39 | ps_req_timeout: Optional[int] = 10
40 | # endregion
41 |
42 | # region style
43 | ps_bg_provider: str = "loli"
44 | ps_bg_preload_count: int = 1
45 | ps_bg_lolicon_r18_type: Literal[0, 1, 2] = 0
46 | ps_bg_local_path: Path = DEFAULT_BG_PATH
47 | ps_default_avatar: Path = DEFAULT_AVATAR_PATH
48 | # endregion
49 |
50 | # region collectors
51 | # region base
52 | ps_collect_interval: int = 2
53 | ps_default_collect_cache_size: int = 1
54 | ps_collect_cache_size: dict[str, int] = Field(default_factory=dict)
55 | # endregion
56 |
57 | # region header
58 | ps_use_env_nick: bool = False
59 | ps_show_current_bot_only: bool = False
60 | ps_ob_v11_use_get_status: bool = True
61 | ps_count_message_sent_event: Union[bool, set[str]] = False
62 | ps_disconnect_reset_counter: bool = True
63 | # endregion
64 |
65 | # region disk
66 | # usage
67 | ps_ignore_parts: list[str] = []
68 | ps_ignore_bad_parts: bool = False
69 | ps_sort_parts: bool = True
70 | ps_sort_parts_reverse: bool = False
71 | # io
72 | ps_ignore_disk_ios: list[str] = []
73 | ps_ignore_no_io_disk: bool = False
74 | ps_sort_disk_ios: bool = True
75 | # endregion
76 |
77 | # region network
78 | # io
79 | ps_ignore_nets: list[str] = [r"^lo(op)?\d*$", "^Loopback"]
80 | ps_ignore_0b_net: bool = False
81 | ps_sort_nets: bool = True
82 | # connection_test
83 | ps_test_sites: list[TestSiteCfg] = [
84 | type_validate_python(
85 | TestSiteCfg,
86 | {"name": "百度", "url": "https://www.baidu.com/"},
87 | ),
88 | type_validate_python(
89 | TestSiteCfg,
90 | {"name": "Google", "url": "https://www.google.com/", "use_proxy": True},
91 | ),
92 | ]
93 | ps_sort_sites: bool = True
94 | ps_test_timeout: int = 5
95 | # endregion
96 |
97 | # region process
98 | ps_proc_len: int = 5
99 | ps_ignore_procs: list[str] = ["^System Idle Process$"]
100 | ps_proc_sort_by: ProcSortByType = "cpu"
101 | ps_proc_cpu_max_100p: bool = False
102 | # endregion
103 | # endregion components
104 |
105 |
106 | config: ConfigModel = get_plugin_config(ConfigModel)
107 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/debug.py:
--------------------------------------------------------------------------------
1 | import json
2 | import time
3 | from pathlib import Path
4 | from typing import Any
5 |
6 | ROOT_DEBUG_DIR = Path.cwd() / "debug"
7 | DEBUG_DIR = ROOT_DEBUG_DIR / "picstatus"
8 |
9 |
10 | def is_debug_mode():
11 | return ROOT_DEBUG_DIR.exists()
12 |
13 |
14 | def write_debug_file(filename: str, content: Any):
15 | if not DEBUG_DIR.exists():
16 | DEBUG_DIR.mkdir(parents=True)
17 | filename = filename.format(time=round(time.time() * 1000))
18 | path = DEBUG_DIR / filename
19 | if isinstance(content, (bytes, bytearray)):
20 | path.write_bytes(content)
21 | return
22 | path.write_text(
23 | (
24 | content
25 | if isinstance(content, str)
26 | else json.dumps(content, ensure_ascii=False)
27 | ),
28 | "u8",
29 | )
30 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/misc_statistics.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | from typing import Any, Callable, Optional, Union
3 |
4 | from nonebot import get_driver, logger
5 | from nonebot.adapters import Bot as BaseBot, Event as BaseEvent
6 | from nonebot.message import event_preprocessor
7 | from nonebot_plugin_userinfo import UserInfo, get_user_info
8 |
9 | from .config import config
10 |
11 | nonebot_run_time: datetime = datetime.now().astimezone()
12 | bot_connect_time: dict[str, datetime] = {}
13 | recv_num: dict[str, int] = {}
14 | send_num: dict[str, int] = {}
15 |
16 | bot_info_cache: dict[str, UserInfo] = {}
17 | bot_avatar_cache: dict[str, bytes] = {}
18 |
19 | driver = get_driver()
20 |
21 | SEND_APIS: dict[str, Union[list[str], Callable[[str], bool]]] = {
22 | # "BilibiliLive": [], # 狗东西发消息不走 call_api
23 | "Console": ["send_msg"],
24 | "Ding": ["send"],
25 | "Discord": ["create_message"],
26 | "Feishu": ["im/v1/messages"],
27 | "Kaiheila": ["message_create", "directMessage_create"],
28 | "Minecraft": ["send_msg"],
29 | "mirai2": ["send_friend_message", "send_group_message", "send_temp_message"],
30 | "ntchat": lambda x: x.startswith("send_"),
31 | "OneBot V11": ["send_private_msg", "send_group_msg", "send_msg"],
32 | "OneBot V12": ["send_message"],
33 | "QQ": [
34 | "post_dms_messages",
35 | "post_messages",
36 | "post_c2c_messages",
37 | "post_c2c_files",
38 | "post_group_messages",
39 | "post_group_files",
40 | ],
41 | "RedProtocol": ["send_message", "send_fake_forward"],
42 | "Satori": ["message_create"],
43 | "Telegram": lambda x: x.startswith("send_"),
44 | "大别野": ["send_message"],
45 | }
46 |
47 |
48 | def method_is_send_msg(platform: str, name: str) -> bool:
49 | return (platform in SEND_APIS) and (
50 | (name in it) if isinstance((it := SEND_APIS[platform]), list) else it(name)
51 | )
52 |
53 |
54 | if config.ps_count_message_sent_event:
55 |
56 | @event_preprocessor
57 | async def _(bot: BaseBot, event: BaseEvent):
58 | if (
59 | config.ps_count_message_sent_event
60 | and (
61 | (config.ps_count_message_sent_event is True)
62 | or bot.adapter.get_name() in config.ps_count_message_sent_event
63 | )
64 | and (
65 | (event.get_type() == "message_sent")
66 | or (
67 | event.get_type() == "message" and event.get_user_id() == bot.self_id
68 | )
69 | )
70 | ):
71 | # logger.debug(f"Bot {bot.self_id} sent counter +1")
72 | send_num[bot.self_id] += 1
73 |
74 |
75 | if config.ps_count_message_sent_event is not True:
76 |
77 | @BaseBot.on_called_api
78 | async def called_api(
79 | bot: BaseBot,
80 | exc: Optional[Exception],
81 | api: str,
82 | _: dict[str, Any],
83 | __: Any,
84 | ):
85 | if (
86 | (not exc)
87 | and (config.ps_count_message_sent_event is not True)
88 | and (
89 | (config.ps_count_message_sent_event is False)
90 | or (bot.adapter.get_name() not in config.ps_count_message_sent_event)
91 | )
92 | and method_is_send_msg(bot.adapter.get_name(), api)
93 | ):
94 | # logger.debug(f"Bot {bot.self_id} sent counter +1")
95 | send_num[bot.self_id] += 1
96 |
97 |
98 | @driver.on_bot_connect
99 | async def _(bot: BaseBot):
100 | bot_connect_time[bot.self_id] = datetime.now().astimezone()
101 | if bot.self_id not in recv_num:
102 | recv_num[bot.self_id] = 0
103 | if (bot.self_id not in send_num) and (bot.adapter.get_name() in SEND_APIS):
104 | send_num[bot.self_id] = 0
105 |
106 |
107 | @driver.on_bot_disconnect
108 | async def _(bot: BaseBot):
109 | bot_connect_time.pop(bot.self_id, None)
110 | if config.ps_disconnect_reset_counter:
111 | recv_num.pop(bot.self_id, None)
112 | send_num.pop(bot.self_id, None)
113 |
114 |
115 | @event_preprocessor
116 | async def _(bot: BaseBot, event: BaseEvent):
117 | if event.get_type() == "message":
118 | recv_num[bot.self_id] += 1
119 |
120 |
121 | async def cache_bot_info(bot: BaseBot, event: BaseEvent):
122 | try:
123 | info = await get_user_info(bot, event, bot.self_id)
124 | except ValueError as e:
125 | logger.debug(e)
126 | except Exception as e:
127 | logger.warning(f"Error when getting bot info: {e.__class__.__name__}: {e}")
128 | else:
129 | if info:
130 | bot_info_cache[bot.self_id] = info
131 |
132 |
133 | @event_preprocessor
134 | async def _(bot: BaseBot, event: BaseEvent):
135 | if bot.self_id in bot_info_cache:
136 | return
137 | await cache_bot_info(bot, event)
138 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/res/assets/default_avatar.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lgc-NB2Dev/nonebot-plugin-picstatus/e1706f6c29bf8980e7ea1b9bfa763b8087fcb2f3/nonebot_plugin_picstatus/res/assets/default_avatar.webp
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/res/assets/default_bg.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lgc-NB2Dev/nonebot-plugin-picstatus/e1706f6c29bf8980e7ea1b9bfa763b8087fcb2f3/nonebot_plugin_picstatus/res/assets/default_bg.webp
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/res/js/globalThis.d.ts:
--------------------------------------------------------------------------------
1 | declare module globalThis {
2 | var plugins: (() => Promise)[];
3 | }
4 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/res/js/init-global.js:
--------------------------------------------------------------------------------
1 | globalThis.plugins = [];
2 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/res/js/lazy-load.js:
--------------------------------------------------------------------------------
1 | ///
2 | (() => {
3 | /**
4 | * @template {any[]} A
5 | * @template R
6 | * @param {(...args: A) => Promise} func
7 | * @returns {(...args: A) => Promise}
8 | */
9 | function wrapErr(func) {
10 | return async (...args) => {
11 | try {
12 | return await func(...args);
13 | } catch (e) {
14 | console.error(e);
15 | }
16 | };
17 | }
18 |
19 | /**
20 | * @param {string} url
21 | */
22 | async function makeObjUrlFromUrl(url) {
23 | const res = await fetch(url);
24 | const blob = await res.blob();
25 | return URL.createObjectURL(blob);
26 | }
27 |
28 | /** @typedef {(elem: HTMLElement, objUrl: string) => Promise} PropSetterType */
29 |
30 | /** @type {Record} */
31 | const propSetterMap = {
32 | 'data-background-image': async (elem, objUrl) => {
33 | elem.style.backgroundImage = `url(${objUrl})`;
34 | },
35 | 'data-src': async (elem, objUrl) => {
36 | if (elem instanceof HTMLImageElement) elem.src = objUrl;
37 | },
38 | };
39 |
40 | /**
41 | * @param {HTMLElement} elem
42 | * @param {string} attr
43 | * @param {PropSetterType} setter
44 | */
45 | async function lazyLoadOne(elem, attr, setter) {
46 | const url = elem.getAttribute(attr);
47 | if (!url) return;
48 | const objUrl = await makeObjUrlFromUrl(url);
49 | await setter(elem, objUrl);
50 | elem.removeAttribute(attr);
51 | }
52 |
53 | /**
54 | * @param {string} attr
55 | */
56 | async function lazyLoad(attr) {
57 | /** @type {HTMLElement[]} */
58 | // @ts-ignore
59 | const elements = [...document.body.querySelectorAll(`[${attr}]`)].filter(
60 | (v) => v instanceof HTMLElement
61 | );
62 | const tasks = elements.map((v) =>
63 | wrapErr(lazyLoadOne)(v, attr, propSetterMap[attr])
64 | );
65 | await Promise.all(tasks);
66 | }
67 |
68 | async function lazyLoadAll() {
69 | await Promise.all(Object.keys(propSetterMap).map(lazyLoad));
70 | }
71 |
72 | // 使用 globalThis.plugins.push 注册插件
73 | // 只有这样才能保证你的插件运行完成之后才会网页截图
74 | globalThis.plugins.push(async () => {
75 | await lazyLoadAll();
76 | });
77 | })();
78 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/res/js/load-plugin.js:
--------------------------------------------------------------------------------
1 | (async () => {
2 | for (const plugin of globalThis.plugins) {
3 | try {
4 | await plugin();
5 | } catch (e) {
6 | console.error(e);
7 | }
8 | }
9 | document.body.classList.add('done');
10 | })();
11 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/__init__.py:
--------------------------------------------------------------------------------
1 | import importlib
2 | from collections.abc import Awaitable
3 | from dataclasses import dataclass
4 | from pathlib import Path
5 | from typing import TYPE_CHECKING, Any, Optional, TypedDict
6 | from typing_extensions import Protocol, Unpack
7 |
8 | from nonebot import logger
9 |
10 | from ..config import config
11 |
12 | if TYPE_CHECKING:
13 | from ..bg_provider import BgData
14 |
15 |
16 | class TemplateRendererKwargs(TypedDict):
17 | collected: dict[str, Any]
18 | bg: "BgData"
19 |
20 |
21 | class TemplateRenderer(Protocol):
22 | __name__: str
23 |
24 | def __call__(
25 | self,
26 | **kwargs: Unpack[TemplateRendererKwargs],
27 | ) -> Awaitable[bytes]: ...
28 |
29 |
30 | @dataclass()
31 | class TemplateInfo:
32 | renderer: TemplateRenderer
33 | collectors: Optional[set[str]] = None
34 |
35 |
36 | loaded_templates: dict[str, TemplateInfo] = {}
37 |
38 |
39 | def pic_template(
40 | name: Optional[str] = None,
41 | collecting: Optional[set[str]] = None,
42 | ):
43 | def deco(func: TemplateRenderer):
44 | template_name = name or func.__name__
45 | if template_name in loaded_templates:
46 | raise ValueError(f"Template {template_name} already exists")
47 | loaded_templates[template_name] = TemplateInfo(
48 | renderer=func,
49 | collectors=collecting,
50 | )
51 | logger.debug(f"Registered template {template_name}")
52 |
53 | return deco
54 |
55 |
56 | def load_builtin_templates():
57 | for module in Path(__file__).parent.iterdir():
58 | name = module.name
59 | if (not module.is_dir()) or name.startswith("_"):
60 | continue
61 | assert importlib.import_module(f".{name}", __package__)
62 |
63 |
64 | async def render_current_template(**kwargs: Unpack[TemplateRendererKwargs]):
65 | return await loaded_templates[config.ps_template].renderer(**kwargs)
66 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/default/__init__.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 | from pathlib import Path
3 | from typing import TYPE_CHECKING, Any, Literal
4 |
5 | import jinja2
6 | from cookit import flatten
7 | from cookit.pyd import field_validator
8 | from nonebot import get_plugin_config, require
9 | from pydantic import BaseModel
10 |
11 | from ...debug import is_debug_mode, write_debug_file
12 | from .. import pic_template
13 | from ..pw_render import (
14 | ROUTE_URL,
15 | add_background_router,
16 | add_root_router,
17 | base_router_group,
18 | make_file_router,
19 | register_global_filter_to,
20 | resolve_file_url,
21 | )
22 |
23 | require("nonebot_plugin_htmlrender")
24 |
25 | from nonebot_plugin_htmlrender import get_new_page # noqa: E402
26 |
27 | if TYPE_CHECKING:
28 | from ...bg_provider import BgData
29 |
30 | RES_PATH = Path(__file__).parent / "res"
31 | TEMPLATE_PATH = RES_PATH / "templates"
32 | CSS_PATH = RES_PATH / "css"
33 | ENVIRONMENT = jinja2.Environment(
34 | loader=jinja2.FileSystemLoader(str(TEMPLATE_PATH)),
35 | autoescape=jinja2.select_autoescape(["html", "xml"]),
36 | enable_async=True,
37 | )
38 | register_global_filter_to(ENVIRONMENT)
39 |
40 | template_router_group = base_router_group.copy()
41 | template_router_group.router(f"{ROUTE_URL}/default/res/**/*", priority=99)(
42 | make_file_router(query_name=None, base_path=RES_PATH, prefix_omit="default/res/"),
43 | )
44 |
45 | COMPONENT_COLLECTORS = {
46 | "header": {"bots", "nonebot_run_time", "system_run_time"},
47 | "cpu_mem": {
48 | "cpu_percent",
49 | "cpu_count",
50 | "cpu_count_logical",
51 | "cpu_freq",
52 | "cpu_brand",
53 | "memory_stat",
54 | "swap_stat",
55 | },
56 | "disk": {"disk_usage", "disk_io"},
57 | "network": {"network_io", "network_connection"},
58 | "process": {"process_status"},
59 | "footer": {
60 | "nonebot_version",
61 | "ps_version",
62 | "time",
63 | "python_version",
64 | "system_name",
65 | },
66 | }
67 |
68 |
69 | class TemplateConfig(BaseModel):
70 | ps_default_components: list[str] = [
71 | "header",
72 | "cpu_mem",
73 | "disk",
74 | "network",
75 | "process",
76 | "footer",
77 | ]
78 | ps_default_additional_css: list[str] = []
79 | ps_default_additional_script: list[str] = []
80 | ps_default_pic_format: Literal["jpeg", "png"] = "jpeg"
81 |
82 | @field_validator("ps_default_additional_css")
83 | def resolve_css_url(cls, v: list[str]): # noqa: N805
84 | return [resolve_file_url(x, {"default/res/css": CSS_PATH}) for x in v]
85 |
86 | @field_validator("ps_default_additional_script")
87 | def resolve_script_url(cls, v: list[str]): # noqa: N805
88 | return [resolve_file_url(x) for x in v]
89 |
90 |
91 | template_config = get_plugin_config(TemplateConfig)
92 | collecting = set(
93 | flatten(COMPONENT_COLLECTORS[k] for k in template_config.ps_default_components),
94 | )
95 |
96 |
97 | @pic_template(collecting=collecting)
98 | async def default(collected: dict[str, Any], bg: "BgData", **_) -> bytes:
99 | collected = {k: v[0] if isinstance(v, deque) else v for k, v in collected.items()}
100 | template = ENVIRONMENT.get_template("index.html.jinja")
101 | html = await template.render_async(d=collected, config=template_config)
102 |
103 | if is_debug_mode():
104 | write_debug_file("default_{time}.html", html)
105 |
106 | router_group = template_router_group.copy()
107 | add_root_router(router_group, html)
108 | add_background_router(router_group, bg)
109 |
110 | async with get_new_page() as page:
111 | await router_group.apply(page)
112 | await page.goto(f"{ROUTE_URL}/")
113 | await page.wait_for_selector("body.done")
114 | elem = await page.query_selector(".main-background")
115 | assert elem
116 | return await elem.screenshot(type="jpeg")
117 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/default/res/css/index.css:
--------------------------------------------------------------------------------
1 | /* Base */
2 |
3 | * {
4 | --font-family: 'HarmonyOS Sans SC', 'Source Han Sans SC', 'Source Han Sans',
5 | sans-serif;
6 | --monospace-font-family: 'JetBrains Mono', 'Cascadia Code', 'Consolas',
7 | monospace;
8 |
9 | --primary-text-color: #3a3a3a;
10 | --secondary-text-color: #6a6a6a;
11 |
12 | --default-background: #3a3a3aaa;
13 | --background-mask-color: #fafafa66;
14 | --card-background-color: #fafafaaa;
15 | --default-box-shadow: 2px 2px 6px #6a6a6a66;
16 |
17 | --label-red-text-color: var(--secondary-text-color);
18 | --label-orange-text-color: var(--secondary-text-color);
19 | --label-yellow-text-color: var(--secondary-text-color);
20 | --label-green-text-color: var(--secondary-text-color);
21 | --label-cyan-text-color: var(--secondary-text-color);
22 | --label-blue-text-color: var(--secondary-text-color);
23 | --label-purple-text-color: var(--secondary-text-color);
24 | --label-gray-text-color: var(--secondary-text-color);
25 | --label-black-text-color: #fafafa;
26 |
27 | --background-color: var(--card-background-color);
28 | --label-red-bg-color: #e05661aa;
29 | --label-orange-bg-color: #ee9025aa;
30 | --label-yellow-bg-color: #eea825aa;
31 | --label-green-bg-color: #1da912aa;
32 | --label-cyan-bg-color: #56b6c2aa;
33 | --label-blue-bg-color: #118dc3aa;
34 | --label-purple-bg-color: #9a77cfaa;
35 | --label-gray-bg-color: #bebebeaa;
36 | --label-black-bg-color: #3a3a3aaa;
37 |
38 | --prog-low-text-color: var(--secondary-text-color);
39 | --prog-medium-text-color: var(--secondary-text-color);
40 | --prog-high-text-color: var(--secondary-text-color);
41 | --prog-low-bg-color: var(--label-green-bg-color);
42 | --prog-medium-bg-color: var(--label-orange-bg-color);
43 | --prog-high-bg-color: var(--label-red-bg-color);
44 |
45 | --segment-color: #bebebe;
46 | }
47 |
48 | .red {
49 | --background-color: var(--label-red-bg-color);
50 | --secondary-text-color: var(--label-red-text-color);
51 | }
52 |
53 | .orange {
54 | --background-color: var(--label-orange-bg-color);
55 | --secondary-text-color: var(--label-orange-text-color);
56 | }
57 |
58 | .yellow {
59 | --background-color: var(--label-yellow-bg-color);
60 | --secondary-text-color: var(--label-yellow-text-color);
61 | }
62 |
63 | .green {
64 | --background-color: var(--label-green-bg-color);
65 | --secondary-text-color: var(--label-green-text-color);
66 | }
67 |
68 | .cyan {
69 | --background-color: var(--label-cyan-bg-color);
70 | --secondary-text-color: var(--label-cyan-text-color);
71 | }
72 |
73 | .blue {
74 | --background-color: var(--label-blue-bg-color);
75 | --secondary-text-color: var(--label-blue-text-color);
76 | }
77 |
78 | .purple {
79 | --background-color: var(--label-purple-bg-color);
80 | --secondary-text-color: var(--label-purple-text-color);
81 | }
82 |
83 | .gray {
84 | --background-color: var(--label-gray-bg-color);
85 | --secondary-text-color: var(--label-gray-text-color);
86 | }
87 |
88 | .black {
89 | --background-color: var(--label-black-bg-color);
90 | --secondary-text-color: var(--label-black-text-color);
91 | }
92 |
93 | .prog-low {
94 | --background-color: var(--prog-low-bg-color);
95 | --secondary-text-color: var(--prog-low-text-color);
96 | }
97 |
98 | .prog-medium {
99 | --background-color: var(--prog-medium-bg-color);
100 | --secondary-text-color: var(--prog-medium-text-color);
101 | }
102 |
103 | .prog-high {
104 | --background-color: var(--prog-high-bg-color);
105 | --secondary-text-color: var(--prog-high-text-color);
106 | }
107 |
108 | .monospace {
109 | font-family: var(--monospace-font-family);
110 | }
111 |
112 | body {
113 | font-family: var(--font-family);
114 | color: var(--primary-text-color);
115 | font-size: 20px;
116 | }
117 |
118 | .main-background {
119 | width: 650px;
120 | background: var(--default-background);
121 | background-repeat: no-repeat;
122 | background-position: center;
123 | background-size: cover;
124 | }
125 |
126 | .main-background-mask {
127 | padding: 16px;
128 | background-color: var(--background-mask-color);
129 | }
130 |
131 | .main {
132 | display: grid;
133 | grid-template-columns: 1fr;
134 | gap: 16px;
135 | }
136 |
137 | .card {
138 | border-radius: 8px;
139 | padding: 16px;
140 | background: var(--card-background-color);
141 | box-shadow: var(--default-box-shadow);
142 | backdrop-filter: blur(2px);
143 | overflow: hidden;
144 | }
145 |
146 | .splitter > *:not(:first-child) {
147 | margin-top: 8px;
148 | padding-top: 8px;
149 | border-top: 2px solid var(--segment-color);
150 | }
151 |
152 | .align-right {
153 | text-align: right;
154 | }
155 |
156 | /* Span Label */
157 |
158 | span.label {
159 | padding: 2px 4px;
160 | border-radius: 4px;
161 | box-shadow: var(--default-box-shadow);
162 | background-color: var(--background-color);
163 | color: var(--secondary-text-color);
164 | }
165 |
166 | .label-container {
167 | display: flex;
168 | flex-direction: row;
169 | flex-wrap: wrap;
170 | align-items: center;
171 | }
172 |
173 | .label-container > * {
174 | margin-right: 2px;
175 | margin-bottom: 2px;
176 | }
177 |
178 | /* Account */
179 |
180 | .account {
181 | display: flex;
182 | flex-direction: row;
183 | }
184 |
185 | .account .avatar {
186 | width: 125px;
187 | height: 125px;
188 | border-radius: 50%;
189 | box-shadow: var(--default-box-shadow);
190 | background-color: var(--card-background-color);
191 | }
192 |
193 | .account .description {
194 | margin-left: 16px;
195 | display: flex;
196 | flex-direction: column;
197 | justify-content: center;
198 | }
199 |
200 | .account .description .nickname {
201 | font-size: 36px;
202 | font-weight: bold;
203 | margin-bottom: 8px;
204 | word-break: break-word;
205 | line-height: 1.1;
206 | }
207 |
208 | /* Donut Chart */
209 |
210 | .donut-chart {
211 | display: flex;
212 | flex-direction: column;
213 | justify-content: center;
214 | align-items: center;
215 | text-align: center;
216 | }
217 |
218 | .donut-chart .chart-wrapper,
219 | .donut-chart .chart,
220 | .donut-chart .shadow {
221 | width: 150px;
222 | height: 150px;
223 | }
224 |
225 | .donut-chart .chart-wrapper {
226 | position: relative;
227 | }
228 |
229 | .donut-chart .chart {
230 | transform: rotate(-90deg);
231 | }
232 |
233 | .donut-chart .chart .empty,
234 | .donut-chart .chart .slice {
235 | fill: transparent;
236 | stroke-width: 15px;
237 | }
238 |
239 | .donut-chart .chart .empty {
240 | stroke: var(--label-gray-bg-color);
241 | }
242 |
243 | .donut-chart .chart .slice {
244 | stroke: var(--background-color);
245 | stroke-dasharray: calc((67.5px * 2) * 3.1415926);
246 | stroke-dashoffset: calc(
247 | (67.5px * 2) * 3.1415926 / 360 * (360 - (360 * var(--percent)))
248 | );
249 | }
250 |
251 | .donut-chart .shadow {
252 | position: absolute;
253 | top: 0;
254 | border-radius: 50%;
255 | box-shadow: var(--default-box-shadow);
256 | }
257 |
258 | .donut-chart .label {
259 | position: absolute;
260 | left: 50%;
261 | top: 50%;
262 | transform: translate(-50%, -50%);
263 | }
264 |
265 | .donut-chart .label,
266 | .donut-chart .title {
267 | font-size: 32px;
268 | font-weight: bold;
269 | text-wrap: nowrap;
270 | white-space: nowrap;
271 | }
272 |
273 | .donut-chart .desc {
274 | font-size: 12px;
275 | word-break: break-word;
276 | color: var(--secondary-text-color);
277 | }
278 |
279 | /* Progress Bar */
280 |
281 | .progress-bar {
282 | position: relative;
283 | border-radius: 4px;
284 | overflow: hidden;
285 | box-shadow: var(--default-box-shadow);
286 | }
287 |
288 | .progress-bar .background {
289 | position: absolute;
290 | width: 100%;
291 | height: 100%;
292 | background-color: var(--label-gray-bg-color);
293 | }
294 |
295 | .progress-bar .progress {
296 | position: absolute;
297 | height: 100%;
298 | background-color: var(--background-color);
299 | }
300 |
301 | .progress-bar .label {
302 | position: relative;
303 | z-index: 1;
304 | text-align: center;
305 | }
306 |
307 | /* #### Split Line #### */
308 |
309 | /* Card Header */
310 |
311 | .card.header {
312 | display: flex;
313 | flex-direction: column;
314 | }
315 |
316 | .card.header .label-container {
317 | font-size: 16px;
318 | }
319 |
320 | .card.header .extra > * {
321 | flex-grow: 1;
322 | text-align: center;
323 | }
324 |
325 | /* Donut Chart Line */
326 |
327 | .donut-chart-line {
328 | display: grid;
329 | gap: 8px;
330 | grid-template-columns: repeat(3, 1fr);
331 | align-items: start;
332 | }
333 |
334 | /* List Grid */
335 |
336 | .list-grid {
337 | display: grid;
338 | gap: 4px;
339 | align-items: center;
340 | }
341 |
342 | .list-grid.disk-usage {
343 | grid-template-columns: auto minmax(180px, 100%) auto;
344 | }
345 |
346 | .list-grid.disk-io,
347 | .list-grid.network-io,
348 | .list-grid.network-connection-test,
349 | .list-grid.process-usage {
350 | grid-template-columns: minmax(0, 100%) auto auto auto auto auto;
351 | }
352 |
353 | .list-grid.network-connection-test {
354 | grid-template-columns: minmax(0, 100%) auto auto auto;
355 | }
356 |
357 | .list-grid.network-connection-test .error {
358 | grid-column-end: span 3;
359 | text-align: right;
360 | }
361 |
362 | /* Footer */
363 |
364 | .footer {
365 | font-size: 14px;
366 | text-align: center;
367 | color: var(--primary-text-color);
368 | text-shadow: var(--default-box-shadow);
369 | }
370 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/default/res/css/no-blur.css:
--------------------------------------------------------------------------------
1 | .card {
2 | backdrop-filter: none;
3 | }
4 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/default/res/css/no-radius.css:
--------------------------------------------------------------------------------
1 | .card,
2 | span.label,
3 | .progress-bar {
4 | border-radius: 0;
5 | }
6 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/default/res/css/no-shadow.css:
--------------------------------------------------------------------------------
1 | * {
2 | --default-box-shadow: none;
3 | }
4 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/default/res/css/theme-dark.css:
--------------------------------------------------------------------------------
1 | * {
2 | --primary-text-color: #d0d6e2;
3 | --secondary-text-color: #abb2bf;
4 |
5 | --default-background: #d0d6e2aa;
6 | --background-mask-color: #282c3455;
7 | --card-background-color: #282c3488;
8 | --default-box-shadow: 2px 2px 6px #abb2bf66;
9 |
10 | --label-default-bg-color: #282c34aa;
11 | --label-red-bg-color: #e06c75aa;
12 | --label-orange-bg-color: #d19a66aa;
13 | --label-yellow-bg-color: #e5c07baa;
14 | --label-green-bg-color: #98c379aa;
15 | --label-cyan-bg-color: #56b6c2aa;
16 | --label-blue-bg-color: #61afefaa;
17 | --label-purple-bg-color: #c678ddaa;
18 | --label-gray-bg-color: #737c8caa;
19 | --label-black-bg-color: #d0d6e2aa;
20 | --label-black-text-color: #282c34;
21 |
22 | --segment-color: #5c6370;
23 | }
24 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/default/res/templates/index.html.jinja:
--------------------------------------------------------------------------------
1 | {% from 'macros.html.jinja' import header, cpu_mem, disk, network, process, footer %}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | {% for css in config.ps_default_additional_css -%}
11 | {% endfor %}
12 |
13 |
14 |
15 |
16 |
17 |
18 | {% for name in config.ps_default_components %}
19 | {% if name == "header" %}
20 | {{ header(d) }}
21 | {% elif name == "cpu_mem" %}
22 | {{ cpu_mem(d) }}
23 | {% elif name == "disk" %}
24 | {{ disk(d) }}
25 | {% elif name == "network" %}
26 | {{ network(d) }}
27 | {% elif name == "process" %}
28 | {{ process(d) }}
29 | {% elif name == "footer" %}
30 | {{ footer(d) }}
31 | {% endif %}
32 | {% endfor %}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | {% for script in config.ps_default_additional_script -%}
41 | {% endfor %}
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/default/res/templates/macros.html.jinja:
--------------------------------------------------------------------------------
1 | {% macro donut_chart(percent, title, caption) %}
2 |
3 |
4 |
10 |
11 |
12 | {%- if percent == None %}未部署
13 | {%- else %}{{ '{0:.0f}%'.format(percent) }}{% endif -%}
14 |
15 |
16 |
{{ title }}
17 |
{{ caption | br }}
18 |
19 | {% endmacro %}
20 |
21 | {% macro header(d) %}
22 |
42 | {% endmacro %}
43 |
44 | {% macro cpu_mem(d) %}
45 | {% set freq = d.cpu_freq | format_cpu_freq %}
46 | {% set ram_used = d.memory_stat.used | auto_convert_unit %}
47 | {% set ram_total = d.memory_stat.total | auto_convert_unit %}
48 | {% set swap_used = d.swap_stat.used | auto_convert_unit %}
49 | {% set swap_total = d.swap_stat.total | auto_convert_unit %}
50 |
51 | {{ donut_chart(d.cpu_percent, "CPU", "{}核 {}线程 {}\n{}".format(d.cpu_count, d.cpu_count_logical, freq, d.cpu_brand)) }}
52 | {{ donut_chart(d.memory_stat.percent, "RAM", "{} / {}").format(ram_used, ram_total) }}
53 | {{ donut_chart(d.swap_stat.percent, "SWAP", "{} / {}").format(swap_used, swap_total) }}
54 |
55 | {% endmacro %}
56 |
57 | {% macro disk(d) %}
58 |
59 |
60 | {% for it in d.disk_usage %}
61 |
{{ it.name }}
62 |
63 |
64 | {% if it.exception %}
65 |
{{ it.exception }}
66 | {% else %}
67 |
68 |
{{ it.used | auto_convert_unit }} / {{ it.total | auto_convert_unit }}
69 | {% endif %}
70 |
71 |
72 | {%- if it.percent %}{{ '{0:.1f}%'.format(it.percent) }}
73 | {%- else %}??.?%{% endif -%}
74 |
75 | {% endfor %}
76 |
77 |
78 | {% if d.disk_io -%}
79 |
80 | {% for it in d.disk_io %}
81 |
{{ it.name }}
82 |
读
83 |
{{ it.read | auto_convert_unit(suffix='/s') }}
84 |
|
85 |
写
86 |
{{ it.write | auto_convert_unit(suffix='/s') }}
87 | {% endfor %}
88 |
89 | {%- endif %}
90 |
91 | {% endmacro %}
92 |
93 | {% macro network(d) %}
94 |
95 |
96 | {% for it in d.network_io %}
97 |
{{ it.name }}
98 |
↑
99 |
{{ it.sent | auto_convert_unit(suffix='/s') }}
100 |
|
101 |
↓
102 |
{{ it.recv | auto_convert_unit(suffix='/s') }}
103 | {% endfor %}
104 |
105 |
106 | {% for it in d.network_connection %}
107 |
{{ it.name }}
108 | {% if it.error %}
109 |
{{ it.error }}
110 | {% else %}
111 |
{{ it.status }} {{ it.reason }}
112 |
|
113 |
{{ '{0:.2f}ms'.format(it.delay) }}
114 | {% endif %}
115 | {% endfor %}
116 |
117 |
118 | {% endmacro %}
119 |
120 | {% macro process(d) %}
121 |
122 |
123 | {% for it in d.process_status %}
124 |
{{ it.name }}
125 |
CPU
126 |
{{ '{0:.1f}%'.format(it.cpu) }}
127 |
|
128 |
MEM
129 |
{{ it.mem | auto_convert_unit }}
130 | {% endfor %}
131 |
132 |
133 | {% endmacro %}
134 |
135 | {% macro footer(d) %}
136 |
140 | {% endmacro %}
141 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/templates/pw_render.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 | from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar
3 | from urllib.parse import urlencode
4 |
5 | from cookit import auto_convert_byte, make_append_obj_to_dict_deco
6 | from cookit.jinja import all_filters
7 | from cookit.pw import CKRouterFunc, RouterGroup, make_real_path_router
8 | from cookit.pw.loguru import log_router_err
9 | from nonebot import logger
10 | from yarl import URL
11 |
12 | from ..config import DEFAULT_AVATAR_PATH, config
13 | from ..misc_statistics import bot_avatar_cache, bot_info_cache
14 | from ..util import format_cpu_freq
15 |
16 | if TYPE_CHECKING:
17 | import jinja2
18 | from playwright.async_api import Request, Route
19 |
20 | from ..bg_provider import BgData
21 |
22 | TC = TypeVar("TC", bound=Callable[..., Any])
23 |
24 | ROOT_PATH = Path(__file__).parent.parent
25 | RES_PATH = ROOT_PATH / "res"
26 | ROUTE_URL = "http://picstatus.nonebot"
27 | RES_LOCATION_MAP = {
28 | "": RES_PATH,
29 | }
30 |
31 | # region pw
32 |
33 | base_router_group = RouterGroup()
34 |
35 |
36 | def resolve_file_url(
37 | path: str,
38 | additional_locations: Optional[dict[str, Path]] = None,
39 | ) -> str:
40 | if path.startswith("res:"):
41 | path = path[4:].lstrip("/")
42 | locations = {**RES_LOCATION_MAP, **(additional_locations or {})}
43 | for pfx, loc in locations.items():
44 | if (loc / path).exists():
45 | return f"/{pfx}/{path}"
46 | raise ValueError(f"Cannot resolve builtin resource `{path}`")
47 | params = urlencode({"path": path})
48 | return f"/api/local_file?{params}"
49 |
50 |
51 | def make_file_router(
52 | query_name: Optional[str] = None,
53 | base_path: Optional[Path] = None,
54 | prefix_omit: str = "",
55 | ) -> CKRouterFunc:
56 | @log_router_err()
57 | @make_real_path_router
58 | async def router(request: "Request", **_):
59 | url = URL(request.url)
60 | query_path = url.query.get(query_name, "") if query_name else url.path[1:]
61 | if prefix_omit and query_path.startswith(prefix_omit):
62 | query_path = query_path[len(prefix_omit) :]
63 | path = Path((base_path / query_path) if base_path else query_path)
64 | logger.debug(f"Associated file `{path}`")
65 | return path
66 |
67 | return router
68 |
69 |
70 | @base_router_group.router(f"{ROUTE_URL}/api/bot_avatar/*")
71 | @log_router_err()
72 | async def _(route: "Route", request: "Request", **_):
73 | url = URL(request.url)
74 | self_id = url.parts[-1]
75 |
76 | if self_id in bot_avatar_cache:
77 | await route.fulfill(body=bot_avatar_cache[self_id])
78 | return
79 |
80 | if (self_id in bot_info_cache) and (avatar := bot_info_cache[self_id].user_avatar):
81 | try:
82 | img = await avatar.get_image()
83 | except Exception as e:
84 | logger.warning(
85 | f"Error when getting bot avatar, fallback to default: "
86 | f"{e.__class__.__name__}: {e}",
87 | )
88 | else:
89 | bot_avatar_cache[self_id] = img
90 | await route.fulfill(body=img)
91 | return
92 |
93 | data = (
94 | config.ps_default_avatar
95 | if config.ps_default_avatar.is_file()
96 | else DEFAULT_AVATAR_PATH
97 | ).read_bytes()
98 | await route.fulfill(body=data)
99 |
100 |
101 | base_router_group.router(f"{ROUTE_URL}/api/local_file*")(
102 | make_file_router(query_name="path", base_path=None),
103 | )
104 |
105 | base_router_group.router(f"{ROUTE_URL}/**/*", priority=100)(
106 | make_file_router(query_name=None, base_path=RES_PATH),
107 | )
108 |
109 |
110 | def add_root_router(router_group: RouterGroup, html: str):
111 | @router_group.router(f"{ROUTE_URL}/")
112 | @log_router_err()
113 | async def _(route: "Route", **_):
114 | await route.fulfill(content_type="text/html", body=html)
115 |
116 |
117 | def add_background_router(router_group: RouterGroup, bg: "BgData"):
118 | @router_group.router(f"{ROUTE_URL}/api/background")
119 | @log_router_err()
120 | async def _(route: "Route", **_):
121 | await route.fulfill(content_type=bg.mime, body=bg.data)
122 |
123 |
124 | # endregion
125 |
126 | # region jinja
127 |
128 | global_jinja_filters: dict[str, Callable] = all_filters.copy()
129 |
130 |
131 | jinja_filter = make_append_obj_to_dict_deco(global_jinja_filters)
132 |
133 |
134 | def register_global_filter_to(env: "jinja2.Environment"):
135 | env.filters.update(global_jinja_filters)
136 |
137 |
138 | jinja_filter(format_cpu_freq)
139 |
140 |
141 | @jinja_filter
142 | def percent_to_color(percent: float) -> str:
143 | if percent < 70:
144 | return "prog-low"
145 | if percent < 90:
146 | return "prog-medium"
147 | return "prog-high"
148 |
149 |
150 | @jinja_filter
151 | def auto_convert_unit(value: float, **kw) -> str:
152 | return auto_convert_byte(value=value, with_space=False, **kw)
153 |
154 |
155 | # endregion
156 |
--------------------------------------------------------------------------------
/nonebot_plugin_picstatus/util.py:
--------------------------------------------------------------------------------
1 | import re
2 | from functools import partial
3 | from typing import TYPE_CHECKING, Optional
4 |
5 | from cookit import auto_convert_byte, format_timedelta
6 |
7 | if TYPE_CHECKING:
8 | from .collectors.cpu import CpuFreq
9 |
10 | format_time_delta_ps = partial(format_timedelta, day_divider=" ", day_suffix="天")
11 |
12 |
13 | def match_list_regexp(reg_list: list[str], txt: str) -> Optional[re.Match]:
14 | return next((match for r in reg_list if (match := re.search(r, txt))), None)
15 |
16 |
17 | def format_cpu_freq(freq: "CpuFreq") -> str:
18 | cu = partial(auto_convert_byte, suffix="Hz", unit_index=2, with_space=False)
19 | if not freq.current:
20 | return "主频未知"
21 | if not freq.max:
22 | return cu(value=freq.current)
23 | if freq.max == freq.current:
24 | return cu(value=freq.max)
25 | return f"{cu(value=freq.current)} / {cu(value=freq.max)}"
26 |
--------------------------------------------------------------------------------
/pdm.lock:
--------------------------------------------------------------------------------
1 | # This file is @generated by PDM.
2 | # It is not intended for manual editing.
3 |
4 | [metadata]
5 | groups = ["default"]
6 | strategy = ["inherit_metadata"]
7 | lock_version = "4.5.0"
8 | content_hash = "sha256:891c0bb94eb7c754c70bedc507acd8483e545fd929369c0963562e46ddca7891"
9 |
10 | [[metadata.targets]]
11 | requires_python = "~=3.9"
12 |
13 | [[package]]
14 | name = "aiofiles"
15 | version = "24.1.0"
16 | requires_python = ">=3.8"
17 | summary = "File support for asyncio."
18 | groups = ["default"]
19 | files = [
20 | {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"},
21 | {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"},
22 | ]
23 |
24 | [[package]]
25 | name = "annotated-types"
26 | version = "0.7.0"
27 | requires_python = ">=3.8"
28 | summary = "Reusable constraint types to use with typing.Annotated"
29 | groups = ["default"]
30 | dependencies = [
31 | "typing-extensions>=4.0.0; python_version < \"3.9\"",
32 | ]
33 | files = [
34 | {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
35 | {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
36 | ]
37 |
38 | [[package]]
39 | name = "anyio"
40 | version = "4.8.0"
41 | requires_python = ">=3.9"
42 | summary = "High level compatibility layer for multiple asynchronous event loop implementations"
43 | groups = ["default"]
44 | dependencies = [
45 | "exceptiongroup>=1.0.2; python_version < \"3.11\"",
46 | "idna>=2.8",
47 | "sniffio>=1.1",
48 | "typing-extensions>=4.5; python_version < \"3.13\"",
49 | ]
50 | files = [
51 | {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"},
52 | {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"},
53 | ]
54 |
55 | [[package]]
56 | name = "apscheduler"
57 | version = "3.11.0"
58 | requires_python = ">=3.8"
59 | summary = "In-process task scheduler with Cron-like capabilities"
60 | groups = ["default"]
61 | dependencies = [
62 | "backports-zoneinfo; python_version < \"3.9\"",
63 | "tzlocal>=3.0",
64 | ]
65 | files = [
66 | {file = "APScheduler-3.11.0-py3-none-any.whl", hash = "sha256:fc134ca32e50f5eadcc4938e3a4545ab19131435e851abb40b34d63d5141c6da"},
67 | {file = "apscheduler-3.11.0.tar.gz", hash = "sha256:4c622d250b0955a65d5d0eb91c33e6d43fd879834bf541e0a18661ae60460133"},
68 | ]
69 |
70 | [[package]]
71 | name = "arclet-alconna"
72 | version = "1.8.35"
73 | requires_python = ">=3.9"
74 | summary = "A High-performance, Generality, Humane Command Line Arguments Parser Library."
75 | groups = ["default"]
76 | dependencies = [
77 | "nepattern<1.0.0,>=0.7.7",
78 | "tarina<0.7.0,>=0.6.1",
79 | "typing-extensions>=4.5.0",
80 | ]
81 | files = [
82 | {file = "arclet_alconna-1.8.35-py3-none-any.whl", hash = "sha256:95d8aaf079167b24e158a0c5125dc17c671da129969dcc5f8b79a9cc72b6389c"},
83 | {file = "arclet_alconna-1.8.35.tar.gz", hash = "sha256:0cdb7fbdd154110ed7fb79e2b281df6c5fc87861770301f1c0cf8af594ee95f3"},
84 | ]
85 |
86 | [[package]]
87 | name = "arclet-alconna-tools"
88 | version = "0.7.10"
89 | requires_python = ">=3.9"
90 | summary = "Builtin Tools for Alconna"
91 | groups = ["default"]
92 | dependencies = [
93 | "arclet-alconna>=1.8.31",
94 | "nepattern<1.0.0,>=0.7.3",
95 | ]
96 | files = [
97 | {file = "arclet_alconna_tools-0.7.10-py3-none-any.whl", hash = "sha256:50e8b2f433fbc612dc8b99f4f5410006dcb1ef406c971c795071117a4eab8e20"},
98 | {file = "arclet_alconna_tools-0.7.10.tar.gz", hash = "sha256:446a63a9c56886c23fb44548bb9a18655e0ba5b5dd80cc87915b858dfb02554c"},
99 | ]
100 |
101 | [[package]]
102 | name = "cachetools"
103 | version = "5.5.1"
104 | requires_python = ">=3.7"
105 | summary = "Extensible memoizing collections and decorators"
106 | groups = ["default"]
107 | files = [
108 | {file = "cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb"},
109 | {file = "cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95"},
110 | ]
111 |
112 | [[package]]
113 | name = "certifi"
114 | version = "2025.1.31"
115 | requires_python = ">=3.6"
116 | summary = "Python package for providing Mozilla's CA Bundle."
117 | groups = ["default"]
118 | files = [
119 | {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"},
120 | {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"},
121 | ]
122 |
123 | [[package]]
124 | name = "colorama"
125 | version = "0.4.6"
126 | requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
127 | summary = "Cross-platform colored terminal text."
128 | groups = ["default"]
129 | marker = "sys_platform == \"win32\""
130 | files = [
131 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
132 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
133 | ]
134 |
135 | [[package]]
136 | name = "cookit"
137 | version = "0.9.3"
138 | requires_python = "<4.0,>=3.9"
139 | summary = "A toolkit for self use."
140 | groups = ["default"]
141 | dependencies = [
142 | "typing-extensions>=4.12.2",
143 | ]
144 | files = [
145 | {file = "cookit-0.9.3-py3-none-any.whl", hash = "sha256:bcda202f9b6bbc7739ee613a5742b2189cb134d73e54dd61178881676b431dbf"},
146 | {file = "cookit-0.9.3.tar.gz", hash = "sha256:68e6fce24bc7c0481b0aefb41e517b5c8744e371d87fe2a89c627c006a7b1ea8"},
147 | ]
148 |
149 | [[package]]
150 | name = "cookit"
151 | version = "0.9.3"
152 | extras = ["jinja", "loguru", "playwright", "pydantic"]
153 | requires_python = "<4.0,>=3.9"
154 | summary = "A toolkit for self use."
155 | groups = ["default"]
156 | dependencies = [
157 | "anyio>=4.6.2.post1",
158 | "cookit==0.9.3",
159 | "jinja2>=3.1.4",
160 | "loguru>=0.7.2",
161 | "playwright>=1.49.0",
162 | "pydantic!=2.5.0,!=2.5.1,<3.0.0,>=1.10.0",
163 | "yarl>=1.18.3",
164 | ]
165 | files = [
166 | {file = "cookit-0.9.3-py3-none-any.whl", hash = "sha256:bcda202f9b6bbc7739ee613a5742b2189cb134d73e54dd61178881676b431dbf"},
167 | {file = "cookit-0.9.3.tar.gz", hash = "sha256:68e6fce24bc7c0481b0aefb41e517b5c8744e371d87fe2a89c627c006a7b1ea8"},
168 | ]
169 |
170 | [[package]]
171 | name = "emoji"
172 | version = "2.14.1"
173 | requires_python = ">=3.7"
174 | summary = "Emoji for Python"
175 | groups = ["default"]
176 | dependencies = [
177 | "typing-extensions>=4.7.0; python_version < \"3.9\"",
178 | ]
179 | files = [
180 | {file = "emoji-2.14.1-py3-none-any.whl", hash = "sha256:35a8a486c1460addb1499e3bf7929d3889b2e2841a57401903699fef595e942b"},
181 | {file = "emoji-2.14.1.tar.gz", hash = "sha256:f8c50043d79a2c1410ebfae833ae1868d5941a67a6cd4d18377e2eb0bd79346b"},
182 | ]
183 |
184 | [[package]]
185 | name = "exceptiongroup"
186 | version = "1.2.2"
187 | requires_python = ">=3.7"
188 | summary = "Backport of PEP 654 (exception groups)"
189 | groups = ["default"]
190 | files = [
191 | {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
192 | {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
193 | ]
194 |
195 | [[package]]
196 | name = "greenlet"
197 | version = "3.1.1"
198 | requires_python = ">=3.7"
199 | summary = "Lightweight in-process concurrent programming"
200 | groups = ["default"]
201 | files = [
202 | {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"},
203 | {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"},
204 | {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"},
205 | {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"},
206 | {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"},
207 | {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"},
208 | {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"},
209 | {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"},
210 | {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"},
211 | {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"},
212 | {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"},
213 | {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"},
214 | {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"},
215 | {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"},
216 | {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"},
217 | {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"},
218 | {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"},
219 | {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"},
220 | {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"},
221 | {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"},
222 | {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"},
223 | {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"},
224 | {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"},
225 | {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"},
226 | {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"},
227 | {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"},
228 | {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"},
229 | {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"},
230 | {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"},
231 | {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"},
232 | {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"},
233 | {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"},
234 | {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"},
235 | {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"},
236 | {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"},
237 | {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"},
238 | {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"},
239 | {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"},
240 | {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"},
241 | {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"},
242 | {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"},
243 | {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"},
244 | {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"},
245 | {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"},
246 | {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"},
247 | {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"},
248 | {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"},
249 | {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"},
250 | {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"},
251 | {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"},
252 | {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"},
253 | {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"},
254 | {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"},
255 | {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"},
256 | ]
257 |
258 | [[package]]
259 | name = "h11"
260 | version = "0.14.0"
261 | requires_python = ">=3.7"
262 | summary = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
263 | groups = ["default"]
264 | dependencies = [
265 | "typing-extensions; python_version < \"3.8\"",
266 | ]
267 | files = [
268 | {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
269 | {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
270 | ]
271 |
272 | [[package]]
273 | name = "httpcore"
274 | version = "1.0.7"
275 | requires_python = ">=3.8"
276 | summary = "A minimal low-level HTTP client."
277 | groups = ["default"]
278 | dependencies = [
279 | "certifi",
280 | "h11<0.15,>=0.13",
281 | ]
282 | files = [
283 | {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"},
284 | {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"},
285 | ]
286 |
287 | [[package]]
288 | name = "httpx"
289 | version = "0.28.1"
290 | requires_python = ">=3.8"
291 | summary = "The next generation HTTP client."
292 | groups = ["default"]
293 | dependencies = [
294 | "anyio",
295 | "certifi",
296 | "httpcore==1.*",
297 | "idna",
298 | ]
299 | files = [
300 | {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
301 | {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
302 | ]
303 |
304 | [[package]]
305 | name = "idna"
306 | version = "3.10"
307 | requires_python = ">=3.6"
308 | summary = "Internationalized Domain Names in Applications (IDNA)"
309 | groups = ["default"]
310 | files = [
311 | {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
312 | {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
313 | ]
314 |
315 | [[package]]
316 | name = "importlib-metadata"
317 | version = "8.6.1"
318 | requires_python = ">=3.9"
319 | summary = "Read metadata from Python packages"
320 | groups = ["default"]
321 | dependencies = [
322 | "typing-extensions>=3.6.4; python_version < \"3.8\"",
323 | "zipp>=3.20",
324 | ]
325 | files = [
326 | {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"},
327 | {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"},
328 | ]
329 |
330 | [[package]]
331 | name = "jinja2"
332 | version = "3.1.5"
333 | requires_python = ">=3.7"
334 | summary = "A very fast and expressive template engine."
335 | groups = ["default"]
336 | dependencies = [
337 | "MarkupSafe>=2.0",
338 | ]
339 | files = [
340 | {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"},
341 | {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"},
342 | ]
343 |
344 | [[package]]
345 | name = "loguru"
346 | version = "0.7.3"
347 | requires_python = "<4.0,>=3.5"
348 | summary = "Python logging made (stupidly) simple"
349 | groups = ["default"]
350 | dependencies = [
351 | "aiocontextvars>=0.2.0; python_version < \"3.7\"",
352 | "colorama>=0.3.4; sys_platform == \"win32\"",
353 | "win32-setctime>=1.0.0; sys_platform == \"win32\"",
354 | ]
355 | files = [
356 | {file = "loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c"},
357 | {file = "loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6"},
358 | ]
359 |
360 | [[package]]
361 | name = "markdown"
362 | version = "3.7"
363 | requires_python = ">=3.8"
364 | summary = "Python implementation of John Gruber's Markdown."
365 | groups = ["default"]
366 | dependencies = [
367 | "importlib-metadata>=4.4; python_version < \"3.10\"",
368 | ]
369 | files = [
370 | {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"},
371 | {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"},
372 | ]
373 |
374 | [[package]]
375 | name = "markupsafe"
376 | version = "3.0.2"
377 | requires_python = ">=3.9"
378 | summary = "Safely add untrusted strings to HTML/XML markup."
379 | groups = ["default"]
380 | files = [
381 | {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
382 | {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
383 | {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"},
384 | {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"},
385 | {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"},
386 | {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"},
387 | {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"},
388 | {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"},
389 | {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"},
390 | {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"},
391 | {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"},
392 | {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"},
393 | {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"},
394 | {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"},
395 | {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"},
396 | {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"},
397 | {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"},
398 | {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"},
399 | {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"},
400 | {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"},
401 | {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"},
402 | {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"},
403 | {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"},
404 | {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"},
405 | {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"},
406 | {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"},
407 | {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"},
408 | {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"},
409 | {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"},
410 | {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"},
411 | {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"},
412 | {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"},
413 | {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"},
414 | {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"},
415 | {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"},
416 | {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"},
417 | {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"},
418 | {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"},
419 | {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"},
420 | {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"},
421 | {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"},
422 | {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"},
423 | {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"},
424 | {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"},
425 | {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"},
426 | {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"},
427 | {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"},
428 | {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"},
429 | {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"},
430 | {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"},
431 | {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"},
432 | {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"},
433 | {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"},
434 | {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"},
435 | {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"},
436 | {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"},
437 | {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"},
438 | {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"},
439 | {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"},
440 | {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"},
441 | {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
442 | ]
443 |
444 | [[package]]
445 | name = "multidict"
446 | version = "6.1.0"
447 | requires_python = ">=3.8"
448 | summary = "multidict implementation"
449 | groups = ["default"]
450 | dependencies = [
451 | "typing-extensions>=4.1.0; python_version < \"3.11\"",
452 | ]
453 | files = [
454 | {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"},
455 | {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"},
456 | {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"},
457 | {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"},
458 | {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"},
459 | {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"},
460 | {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"},
461 | {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"},
462 | {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"},
463 | {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"},
464 | {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"},
465 | {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"},
466 | {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"},
467 | {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"},
468 | {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"},
469 | {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"},
470 | {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"},
471 | {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"},
472 | {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"},
473 | {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"},
474 | {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"},
475 | {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"},
476 | {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"},
477 | {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"},
478 | {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"},
479 | {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"},
480 | {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"},
481 | {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"},
482 | {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"},
483 | {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"},
484 | {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"},
485 | {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"},
486 | {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"},
487 | {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"},
488 | {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"},
489 | {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"},
490 | {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"},
491 | {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"},
492 | {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"},
493 | {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"},
494 | {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"},
495 | {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"},
496 | {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"},
497 | {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"},
498 | {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"},
499 | {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"},
500 | {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"},
501 | {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"},
502 | {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"},
503 | {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"},
504 | {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"},
505 | {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"},
506 | {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"},
507 | {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"},
508 | {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"},
509 | {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"},
510 | {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"},
511 | {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"},
512 | {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"},
513 | {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"},
514 | {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"},
515 | {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"},
516 | {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"},
517 | {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"},
518 | {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"},
519 | {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"},
520 | {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"},
521 | {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"},
522 | {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"},
523 | {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"},
524 | {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"},
525 | {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"},
526 | {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"},
527 | {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"},
528 | {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"},
529 | {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"},
530 | {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"},
531 | ]
532 |
533 | [[package]]
534 | name = "nepattern"
535 | version = "0.7.7"
536 | requires_python = ">=3.8"
537 | summary = "a complex pattern, support typing"
538 | groups = ["default"]
539 | dependencies = [
540 | "tarina>=0.5.1",
541 | "typing-extensions>=4.5.0",
542 | ]
543 | files = [
544 | {file = "nepattern-0.7.7-py3-none-any.whl", hash = "sha256:2d66f964333f42df7971390da4fb98dfed1e8b769236f305c28a83c0bcda849a"},
545 | {file = "nepattern-0.7.7.tar.gz", hash = "sha256:6667f888457e78937998f9412eb70ad16d220464d2d77850dd2b05e9ecfb3207"},
546 | ]
547 |
548 | [[package]]
549 | name = "nonebot-plugin-alconna"
550 | version = "0.54.2"
551 | requires_python = ">=3.9"
552 | summary = "Alconna Adapter for Nonebot"
553 | groups = ["default"]
554 | dependencies = [
555 | "arclet-alconna-tools>=0.7.10",
556 | "arclet-alconna<2.0,>=1.8.35",
557 | "importlib-metadata>=4.13.0",
558 | "nepattern<1.0,>=0.7.7",
559 | "nonebot-plugin-waiter>=0.6.0",
560 | "nonebot2>=2.3.0",
561 | "tarina<0.7,>=0.6.8",
562 | ]
563 | files = [
564 | {file = "nonebot_plugin_alconna-0.54.2-py3-none-any.whl", hash = "sha256:ab9a1a5f0f8c9a30ba57a49bed5d3e9c3f761ea5954cbafb15bcd2aa9c7d5507"},
565 | {file = "nonebot_plugin_alconna-0.54.2.tar.gz", hash = "sha256:0216da3bc2e5f8b4c4c44c2701f8f0a536d35ea0db79e708cc2ecd002b57ace6"},
566 | ]
567 |
568 | [[package]]
569 | name = "nonebot-plugin-apscheduler"
570 | version = "0.5.0"
571 | requires_python = "<4.0,>=3.9"
572 | summary = "APScheduler Support for NoneBot2"
573 | groups = ["default"]
574 | dependencies = [
575 | "apscheduler<4.0.0,>=3.7.0",
576 | "nonebot2<3.0.0,>=2.2.0",
577 | "pydantic!=2.5.0,!=2.5.1,<3.0.0,>=1.10.0",
578 | ]
579 | files = [
580 | {file = "nonebot_plugin_apscheduler-0.5.0-py3-none-any.whl", hash = "sha256:8b99b5ee60c4bc195d4df2fd27dab3d6963691e3332f6cee31a06eb4277c307f"},
581 | {file = "nonebot_plugin_apscheduler-0.5.0.tar.gz", hash = "sha256:6c0230e99765f275dc83d6639ff33bd6f71203fa10cd1b8a204b0f95530cda86"},
582 | ]
583 |
584 | [[package]]
585 | name = "nonebot-plugin-htmlrender"
586 | version = "0.5.1"
587 | requires_python = "<4.0,>=3.9"
588 | summary = "通过浏览器渲染图片"
589 | groups = ["default"]
590 | dependencies = [
591 | "aiofiles>=0.8.0",
592 | "jinja2>=3.0.3",
593 | "markdown>=3.3.6",
594 | "nonebot2>=2.2.0",
595 | "playwright>=1.48.0",
596 | "pygments>=2.10.0",
597 | "pymdown-extensions>=9.1",
598 | "python-markdown-math>=0.8",
599 | ]
600 | files = [
601 | {file = "nonebot_plugin_htmlrender-0.5.1-py3-none-any.whl", hash = "sha256:5c6395202bf437bb111edc0c761a201fdeaeb12114275d723ca9f33fd8b7dca7"},
602 | {file = "nonebot_plugin_htmlrender-0.5.1.tar.gz", hash = "sha256:8dc3fedf12ae7a2b9d0f41af81cfa31b07373b50c362ddfb5f1ff1b436a56889"},
603 | ]
604 |
605 | [[package]]
606 | name = "nonebot-plugin-userinfo"
607 | version = "0.2.6"
608 | requires_python = "<4.0,>=3.9"
609 | summary = "Nonebot2 用户信息获取插件"
610 | groups = ["default"]
611 | dependencies = [
612 | "cachetools<6.0.0,>=5.0.0",
613 | "emoji<3.0.0,>=2.0.0",
614 | "httpx<1.0.0,>=0.20.0",
615 | "nonebot2<3.0.0,>=2.3.0",
616 | "strenum<0.5.0,>=0.4.15",
617 | ]
618 | files = [
619 | {file = "nonebot_plugin_userinfo-0.2.6-py3-none-any.whl", hash = "sha256:79d2481af08a5ec77cf171c685eecd14eaf1ce4d5a1ec1fd22fbb0b85e06c260"},
620 | {file = "nonebot_plugin_userinfo-0.2.6.tar.gz", hash = "sha256:0d1ce897e94a9d4c0b5300bc8f239a4676f9bb62c78a14e0f0527e5398ffc840"},
621 | ]
622 |
623 | [[package]]
624 | name = "nonebot-plugin-waiter"
625 | version = "0.8.1"
626 | requires_python = ">=3.9"
627 | summary = "An alternative for got-and-reject in Nonebot"
628 | groups = ["default"]
629 | dependencies = [
630 | "nonebot2>=2.3.0",
631 | ]
632 | files = [
633 | {file = "nonebot_plugin_waiter-0.8.1-py3-none-any.whl", hash = "sha256:3e1afc8f134496d3a4ecefd9c3a2a98d6ef28a5318268cb22b99a0ef61a44080"},
634 | {file = "nonebot_plugin_waiter-0.8.1.tar.gz", hash = "sha256:5e54213dfea1fd8a1e20dbe6d93b7881f35cbeedf80005148cdc39c1fd2ccc0f"},
635 | ]
636 |
637 | [[package]]
638 | name = "nonebot2"
639 | version = "2.4.1"
640 | requires_python = "<4.0,>=3.9"
641 | summary = "An asynchronous python bot framework."
642 | groups = ["default"]
643 | dependencies = [
644 | "anyio<5.0.0,>=4.4.0",
645 | "exceptiongroup<2.0.0,>=1.2.2",
646 | "loguru<1.0.0,>=0.6.0",
647 | "pydantic!=2.10.0,!=2.10.1,!=2.5.0,!=2.5.1,<3.0.0,>=1.10.0",
648 | "pygtrie<3.0.0,>=2.4.1",
649 | "python-dotenv<2.0.0,>=0.21.0",
650 | "tomli<3.0.0,>=2.0.1; python_version < \"3.11\"",
651 | "typing-extensions<5.0.0,>=4.4.0",
652 | "yarl<2.0.0,>=1.7.2",
653 | ]
654 | files = [
655 | {file = "nonebot2-2.4.1-py3-none-any.whl", hash = "sha256:fec95f075efc89dbe9ce148618b413b02f46ba284200367749b035e794695111"},
656 | {file = "nonebot2-2.4.1.tar.gz", hash = "sha256:8fea364318501ed79721403a8ecd76587bc884d58c356260f691a8bbda9b05e6"},
657 | ]
658 |
659 | [[package]]
660 | name = "playwright"
661 | version = "1.50.0"
662 | requires_python = ">=3.9"
663 | summary = "A high-level API to automate web browsers"
664 | groups = ["default"]
665 | dependencies = [
666 | "greenlet<4.0.0,>=3.1.1",
667 | "pyee<13,>=12",
668 | ]
669 | files = [
670 | {file = "playwright-1.50.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:f36d754a6c5bd9bf7f14e8f57a2aea6fd08f39ca4c8476481b9c83e299531148"},
671 | {file = "playwright-1.50.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:40f274384591dfd27f2b014596250b2250c843ed1f7f4ef5d2960ecb91b4961e"},
672 | {file = "playwright-1.50.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:9922ef9bcd316995f01e220acffd2d37a463b4ad10fd73e388add03841dfa230"},
673 | {file = "playwright-1.50.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:8fc628c492d12b13d1f347137b2ac6c04f98197ff0985ef0403a9a9ee0d39131"},
674 | {file = "playwright-1.50.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcff35f72db2689a79007aee78f1b0621a22e6e3d6c1f58aaa9ac805bf4497c"},
675 | {file = "playwright-1.50.0-py3-none-win32.whl", hash = "sha256:3b906f4d351260016a8c5cc1e003bb341651ae682f62213b50168ed581c7558a"},
676 | {file = "playwright-1.50.0-py3-none-win_amd64.whl", hash = "sha256:1859423da82de631704d5e3d88602d755462b0906824c1debe140979397d2e8d"},
677 | ]
678 |
679 | [[package]]
680 | name = "propcache"
681 | version = "0.2.1"
682 | requires_python = ">=3.9"
683 | summary = "Accelerated property cache"
684 | groups = ["default"]
685 | files = [
686 | {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"},
687 | {file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"},
688 | {file = "propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea"},
689 | {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212"},
690 | {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3"},
691 | {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d"},
692 | {file = "propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634"},
693 | {file = "propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2"},
694 | {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958"},
695 | {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c"},
696 | {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583"},
697 | {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf"},
698 | {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034"},
699 | {file = "propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b"},
700 | {file = "propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4"},
701 | {file = "propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba"},
702 | {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16"},
703 | {file = "propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717"},
704 | {file = "propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3"},
705 | {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9"},
706 | {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787"},
707 | {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465"},
708 | {file = "propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af"},
709 | {file = "propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7"},
710 | {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f"},
711 | {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54"},
712 | {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505"},
713 | {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82"},
714 | {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca"},
715 | {file = "propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e"},
716 | {file = "propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034"},
717 | {file = "propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3"},
718 | {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a"},
719 | {file = "propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0"},
720 | {file = "propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d"},
721 | {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4"},
722 | {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d"},
723 | {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5"},
724 | {file = "propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24"},
725 | {file = "propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff"},
726 | {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f"},
727 | {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec"},
728 | {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348"},
729 | {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6"},
730 | {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6"},
731 | {file = "propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518"},
732 | {file = "propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246"},
733 | {file = "propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1"},
734 | {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc"},
735 | {file = "propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9"},
736 | {file = "propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439"},
737 | {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536"},
738 | {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629"},
739 | {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b"},
740 | {file = "propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052"},
741 | {file = "propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce"},
742 | {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d"},
743 | {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce"},
744 | {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95"},
745 | {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf"},
746 | {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f"},
747 | {file = "propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30"},
748 | {file = "propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6"},
749 | {file = "propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1"},
750 | {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541"},
751 | {file = "propcache-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e"},
752 | {file = "propcache-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4"},
753 | {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097"},
754 | {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd"},
755 | {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681"},
756 | {file = "propcache-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16"},
757 | {file = "propcache-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d"},
758 | {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae"},
759 | {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b"},
760 | {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347"},
761 | {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf"},
762 | {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04"},
763 | {file = "propcache-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587"},
764 | {file = "propcache-0.2.1-cp39-cp39-win32.whl", hash = "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb"},
765 | {file = "propcache-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1"},
766 | {file = "propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54"},
767 | {file = "propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64"},
768 | ]
769 |
770 | [[package]]
771 | name = "psutil"
772 | version = "6.1.1"
773 | requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
774 | summary = "Cross-platform lib for process and system monitoring in Python."
775 | groups = ["default"]
776 | files = [
777 | {file = "psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8"},
778 | {file = "psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377"},
779 | {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003"},
780 | {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160"},
781 | {file = "psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3"},
782 | {file = "psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53"},
783 | {file = "psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649"},
784 | {file = "psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5"},
785 | ]
786 |
787 | [[package]]
788 | name = "py-cpuinfo"
789 | version = "9.0.0"
790 | summary = "Get CPU info with pure Python"
791 | groups = ["default"]
792 | files = [
793 | {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"},
794 | {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"},
795 | ]
796 |
797 | [[package]]
798 | name = "pydantic"
799 | version = "2.10.6"
800 | requires_python = ">=3.8"
801 | summary = "Data validation using Python type hints"
802 | groups = ["default"]
803 | dependencies = [
804 | "annotated-types>=0.6.0",
805 | "pydantic-core==2.27.2",
806 | "typing-extensions>=4.12.2",
807 | ]
808 | files = [
809 | {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"},
810 | {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"},
811 | ]
812 |
813 | [[package]]
814 | name = "pydantic-core"
815 | version = "2.27.2"
816 | requires_python = ">=3.8"
817 | summary = "Core functionality for Pydantic validation and serialization"
818 | groups = ["default"]
819 | dependencies = [
820 | "typing-extensions!=4.7.0,>=4.6.0",
821 | ]
822 | files = [
823 | {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"},
824 | {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"},
825 | {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"},
826 | {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"},
827 | {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"},
828 | {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"},
829 | {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"},
830 | {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"},
831 | {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"},
832 | {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"},
833 | {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"},
834 | {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"},
835 | {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"},
836 | {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"},
837 | {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"},
838 | {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"},
839 | {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"},
840 | {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"},
841 | {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"},
842 | {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"},
843 | {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"},
844 | {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"},
845 | {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"},
846 | {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"},
847 | {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"},
848 | {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"},
849 | {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"},
850 | {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"},
851 | {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"},
852 | {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"},
853 | {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"},
854 | {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"},
855 | {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"},
856 | {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"},
857 | {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"},
858 | {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"},
859 | {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"},
860 | {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"},
861 | {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"},
862 | {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"},
863 | {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"},
864 | {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"},
865 | {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"},
866 | {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"},
867 | {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"},
868 | {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"},
869 | {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"},
870 | {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"},
871 | {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"},
872 | {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"},
873 | {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"},
874 | {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"},
875 | {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"},
876 | {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"},
877 | {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"},
878 | {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"},
879 | {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"},
880 | {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"},
881 | {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"},
882 | {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"},
883 | {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"},
884 | {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"},
885 | {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"},
886 | {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"},
887 | {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"},
888 | {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"},
889 | {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"},
890 | {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"},
891 | {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"},
892 | {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"},
893 | {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"},
894 | {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"},
895 | {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"},
896 | {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"},
897 | {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"},
898 | {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"},
899 | {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"},
900 | {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"},
901 | {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"},
902 | {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"},
903 | {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"},
904 | {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"},
905 | {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"},
906 | {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"},
907 | {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"},
908 | {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"},
909 | {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"},
910 | ]
911 |
912 | [[package]]
913 | name = "pyee"
914 | version = "12.1.1"
915 | requires_python = ">=3.8"
916 | summary = "A rough port of Node.js's EventEmitter to Python with a few tricks of its own"
917 | groups = ["default"]
918 | dependencies = [
919 | "typing-extensions",
920 | ]
921 | files = [
922 | {file = "pyee-12.1.1-py3-none-any.whl", hash = "sha256:18a19c650556bb6b32b406d7f017c8f513aceed1ef7ca618fb65de7bd2d347ef"},
923 | {file = "pyee-12.1.1.tar.gz", hash = "sha256:bbc33c09e2ff827f74191e3e5bbc6be7da02f627b7ec30d86f5ce1a6fb2424a3"},
924 | ]
925 |
926 | [[package]]
927 | name = "pygments"
928 | version = "2.19.1"
929 | requires_python = ">=3.8"
930 | summary = "Pygments is a syntax highlighting package written in Python."
931 | groups = ["default"]
932 | files = [
933 | {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"},
934 | {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"},
935 | ]
936 |
937 | [[package]]
938 | name = "pygtrie"
939 | version = "2.5.0"
940 | summary = "A pure Python trie data structure implementation."
941 | groups = ["default"]
942 | files = [
943 | {file = "pygtrie-2.5.0-py3-none-any.whl", hash = "sha256:8795cda8105493d5ae159a5bef313ff13156c5d4d72feddefacaad59f8c8ce16"},
944 | {file = "pygtrie-2.5.0.tar.gz", hash = "sha256:203514ad826eb403dab1d2e2ddd034e0d1534bbe4dbe0213bb0593f66beba4e2"},
945 | ]
946 |
947 | [[package]]
948 | name = "pymdown-extensions"
949 | version = "10.14.3"
950 | requires_python = ">=3.8"
951 | summary = "Extension pack for Python Markdown."
952 | groups = ["default"]
953 | dependencies = [
954 | "markdown>=3.6",
955 | "pyyaml",
956 | ]
957 | files = [
958 | {file = "pymdown_extensions-10.14.3-py3-none-any.whl", hash = "sha256:05e0bee73d64b9c71a4ae17c72abc2f700e8bc8403755a00580b49a4e9f189e9"},
959 | {file = "pymdown_extensions-10.14.3.tar.gz", hash = "sha256:41e576ce3f5d650be59e900e4ceff231e0aed2a88cf30acaee41e02f063a061b"},
960 | ]
961 |
962 | [[package]]
963 | name = "python-dotenv"
964 | version = "1.0.1"
965 | requires_python = ">=3.8"
966 | summary = "Read key-value pairs from a .env file and set them as environment variables"
967 | groups = ["default"]
968 | files = [
969 | {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
970 | {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
971 | ]
972 |
973 | [[package]]
974 | name = "python-markdown-math"
975 | version = "0.8"
976 | requires_python = ">=3.6"
977 | summary = "Math extension for Python-Markdown"
978 | groups = ["default"]
979 | dependencies = [
980 | "Markdown>=3.0",
981 | ]
982 | files = [
983 | {file = "python-markdown-math-0.8.tar.gz", hash = "sha256:8564212af679fc18d53f38681f16080fcd3d186073f23825c7ce86fadd3e3635"},
984 | {file = "python_markdown_math-0.8-py3-none-any.whl", hash = "sha256:c685249d84b5b697e9114d7beb352bd8ca2e07fd268fd4057ffca888c14641e5"},
985 | ]
986 |
987 | [[package]]
988 | name = "pyyaml"
989 | version = "6.0.2"
990 | requires_python = ">=3.8"
991 | summary = "YAML parser and emitter for Python"
992 | groups = ["default"]
993 | files = [
994 | {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
995 | {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
996 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
997 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
998 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
999 | {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
1000 | {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
1001 | {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
1002 | {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
1003 | {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
1004 | {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
1005 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
1006 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
1007 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
1008 | {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
1009 | {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
1010 | {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
1011 | {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
1012 | {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
1013 | {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
1014 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
1015 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
1016 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
1017 | {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
1018 | {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
1019 | {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
1020 | {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
1021 | {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
1022 | {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
1023 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
1024 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
1025 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
1026 | {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
1027 | {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
1028 | {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
1029 | {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
1030 | {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
1031 | {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
1032 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
1033 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
1034 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
1035 | {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
1036 | {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
1037 | {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
1038 | {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
1039 | {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
1040 | ]
1041 |
1042 | [[package]]
1043 | name = "sniffio"
1044 | version = "1.3.1"
1045 | requires_python = ">=3.7"
1046 | summary = "Sniff out which async library your code is running under"
1047 | groups = ["default"]
1048 | files = [
1049 | {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
1050 | {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
1051 | ]
1052 |
1053 | [[package]]
1054 | name = "strenum"
1055 | version = "0.4.15"
1056 | summary = "An Enum that inherits from str."
1057 | groups = ["default"]
1058 | files = [
1059 | {file = "StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659"},
1060 | {file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"},
1061 | ]
1062 |
1063 | [[package]]
1064 | name = "tarina"
1065 | version = "0.6.8"
1066 | requires_python = ">=3.9"
1067 | summary = "A collection of common utils for Arclet"
1068 | groups = ["default"]
1069 | dependencies = [
1070 | "typing-extensions>=4.4.0",
1071 | ]
1072 | files = [
1073 | {file = "tarina-0.6.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a2f7b7e61912a020d6ba3c591c4edbc31bb468544640bd814470c69a07dcc4cd"},
1074 | {file = "tarina-0.6.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1cac7cbd49317b8e63eba7d0ce0ba11e1218ab51c9d6ee9df8404b5e226db15b"},
1075 | {file = "tarina-0.6.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:69d9923d888948ccc9d20a191ab1f6ff2bc097f4154b6a3780c45dc78ae047cd"},
1076 | {file = "tarina-0.6.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b0f12395301584e0d56c7edd6118c5b5732b456067735ee7f0800575d5d490f"},
1077 | {file = "tarina-0.6.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84bd95b18c7f6a55606b0071654137b98f70faf5d12343d361377cf0d81ecde6"},
1078 | {file = "tarina-0.6.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94e6ee4df273e1fd3eaf36de7c78a93dde08bf2ad67526122afab1b077e344d9"},
1079 | {file = "tarina-0.6.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7afc1a8a11983f39cce18ad7f8d27601c4d34b1ffe1a1aca2a59b4111d181d01"},
1080 | {file = "tarina-0.6.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0f74dc96979b774d7e23b964886137f7cf5f58cb2d652c23c3e2d42c1ad39a9"},
1081 | {file = "tarina-0.6.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3493d59ef19d1ded232e7a33e52c7d6ebfff66f30ac4c3649ae765b14dacc393"},
1082 | {file = "tarina-0.6.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:323351247817dac174f609104c54fcdc4923aaf3ac5e4a4a81c3efaa007d5778"},
1083 | {file = "tarina-0.6.8-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:eb7407046d8051b062f71440b90a11be3ef1a64e99b1c6be157312fe2889e4f4"},
1084 | {file = "tarina-0.6.8-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:50bbbb249d0849855cf43f4fa09c4eecac53e76a54c876ef1a7fb967f17d35b6"},
1085 | {file = "tarina-0.6.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8a05063e41f01f64c3c6e87b740c1e2cebffdcae20b9d89014a934bb2707a2b7"},
1086 | {file = "tarina-0.6.8-cp310-cp310-win32.whl", hash = "sha256:162756b5c0872856c11cc97ed1a618a9118fef3fb6999edc917578b56f3eb67f"},
1087 | {file = "tarina-0.6.8-cp310-cp310-win_amd64.whl", hash = "sha256:a58a8a6e36e43de8f3a0561cb264abe300ec6bb4a4215f16c316f1db564de6fb"},
1088 | {file = "tarina-0.6.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c05d38546712014aafcf123e89d90ad75f08ebd40c5a7e4c76db40d2ae11b387"},
1089 | {file = "tarina-0.6.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b036d53d2f8ec46fff9f649b5ec70431cdee3a2b99c8706f67d8d55ea4d4e493"},
1090 | {file = "tarina-0.6.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:195d2b4a8a8ec2e946ecd8abab70cf3065fbba67e18e971e0412a74a8417a656"},
1091 | {file = "tarina-0.6.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9bbe85a83904eb29143a43511c04a3fea9a7392c70a6216fcec3ba06cf1b83a"},
1092 | {file = "tarina-0.6.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d6b5893b735d24d2a57f6dbb26de92bb5e09e476077a16408e2054f06263530"},
1093 | {file = "tarina-0.6.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a74cc68f4678d37d517a2d661184712f15da608510de6b1bb9103d85d6014409"},
1094 | {file = "tarina-0.6.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dd0f0d769e503fb81d07bd2d342585347f5149803bd7b4b233deaff1833451f"},
1095 | {file = "tarina-0.6.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b7c91a488aa616e141c337cddce1ba1e0bdac6b98362bc15ce76bd3cd71e17"},
1096 | {file = "tarina-0.6.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f0b91da85a816e34a3eb4670d21c26a3909872b1f5525797bedc32a45efd98d"},
1097 | {file = "tarina-0.6.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bf3a5a8fe912d5984627f64cdd187c8a0801c6f3b2f7f12c68cdb5babf691155"},
1098 | {file = "tarina-0.6.8-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:622e226553453a9a873fca5a2d495d2d28003a23834503147954d651186146c4"},
1099 | {file = "tarina-0.6.8-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:198102e526d096f37bfb868f815cb3bfc864e136aa8b70e90a107a38ffb82c15"},
1100 | {file = "tarina-0.6.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:07b252f686410fbf1fe64b3b6705dd40ff218bc1d6a67efac640a0a246f66da3"},
1101 | {file = "tarina-0.6.8-cp311-cp311-win32.whl", hash = "sha256:9e4f56478c58706548e0f08bd277666bac783d918257950be49c4a5d8a35e7b0"},
1102 | {file = "tarina-0.6.8-cp311-cp311-win_amd64.whl", hash = "sha256:d0a92b5368a8a1700f0482d0bc3891dccdfc6dc61f7e66101f68544fca10f096"},
1103 | {file = "tarina-0.6.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e8e4bf8ed36c92af7b2a973905f5f4f58dabf7490c5dda695534bf5e3b20d92e"},
1104 | {file = "tarina-0.6.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:175754132a107c2830a341d3efcae60f44bfd8e0eab56d92537cc6f849ad44e3"},
1105 | {file = "tarina-0.6.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5f983f0c84959589f884777c7ac0b22786d6d183ae367e53265f09e9ed7dc9f"},
1106 | {file = "tarina-0.6.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c8cc5f1bf3c2099377b5de76b0e192bb4fae3dcfcc245be9ed14315b29c8c75"},
1107 | {file = "tarina-0.6.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7067131af4081d8ca3d4e70c96e8903c9e483e4d5af4910b93051602f7e8b34"},
1108 | {file = "tarina-0.6.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a66ea0778dcbd9e9b9b226529ed1822261722956468de026655e09b41feee42b"},
1109 | {file = "tarina-0.6.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd8501b0cd51ad8c0e294b46614ef27ef6773324099b5a24711534db55ded44d"},
1110 | {file = "tarina-0.6.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5812e903c79c02029bfe61fd0ff30bf2a5ac58e7c5b1ab3abfb0f0b57260c5b8"},
1111 | {file = "tarina-0.6.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60ea05cb8e07a629096d9abbd11258df2bcea03168bc8ef8f369ca0dddfc504a"},
1112 | {file = "tarina-0.6.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2635d27c34353e9431cb995acece3a0b607cde0934ebf8df35f0e4ae70a0335"},
1113 | {file = "tarina-0.6.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:542b5359d23f969f275f9e80960ce7f19a2684e93cd3ab659afaeb7ee06de038"},
1114 | {file = "tarina-0.6.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4ba2018a855f59c28f087ec1ec1d892c6afccdd0da8f4347fbf8e3219145d66c"},
1115 | {file = "tarina-0.6.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdf9c5c44d402041df79e747ff9f82c6794875febb053376acdb724043770975"},
1116 | {file = "tarina-0.6.8-cp312-cp312-win32.whl", hash = "sha256:cf44ca009d79d0ecc8541b9067a3b7d086d1939de3bc1b04c164286b0fcf2112"},
1117 | {file = "tarina-0.6.8-cp312-cp312-win_amd64.whl", hash = "sha256:8cd9ff00e2eb9ed6c42b80504005c9b6de4a9afe9ef36771f63b8f9492e38a90"},
1118 | {file = "tarina-0.6.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:af3ff4742b0324d590298812997d028a6d6892bfab5680cd266bed0c1bbf90b0"},
1119 | {file = "tarina-0.6.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e7919d53f20e7d780b44e1804f7c9006bcf5832f87cfeb8d5432f1c832953ed4"},
1120 | {file = "tarina-0.6.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:878f8d9411ed36cf4408751e209a09c5e2363fc06b6074e966995cdbdc365a9d"},
1121 | {file = "tarina-0.6.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa166fe58b65be6aed113fca54851b236cfd5c23e33f5e61c403f7b71eda17a"},
1122 | {file = "tarina-0.6.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04ea6b8f4568fe5b4f167d002fbe05879bfa04a4121b4ca3d294580cfc86b85d"},
1123 | {file = "tarina-0.6.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbdf37600789f34c1eba6bf05e246f8e9a5b46cf93f9652e92d355e767bbc430"},
1124 | {file = "tarina-0.6.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb748ad914898c293771ccdb32c73b3117a15a3234c9d5eb001f834533cf67ef"},
1125 | {file = "tarina-0.6.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55ca473eb8f3bbd70af71a29d59c6c0951e19ae24f3be86259b884fc097028a0"},
1126 | {file = "tarina-0.6.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4b124eee1ce8e25f1c1aba0464c95226ce5ed1b35f079f0fce0f993f38d3393b"},
1127 | {file = "tarina-0.6.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4295448f4dd9f54703adde2683cf6a515f0944687868da4ec500d595e6a9122d"},
1128 | {file = "tarina-0.6.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:77392b3e53e9e1069b9131b1eb2037c53b360e4d7f3cfa8ae04277fe4e785eb1"},
1129 | {file = "tarina-0.6.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:da9771f40ddcd9da087a4fc2d472b548c0da2bb61ad642b7e186ea7098120be6"},
1130 | {file = "tarina-0.6.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fac01686a3f9d4461b8ce6ba3afadb5b24138e27f725ee11efc4b057d98d4e4a"},
1131 | {file = "tarina-0.6.8-cp313-cp313-win32.whl", hash = "sha256:a977e3e38535455b38e018ec345f9982c4d2b40945b330aa5c70c1a24a2f8f5b"},
1132 | {file = "tarina-0.6.8-cp313-cp313-win_amd64.whl", hash = "sha256:62445e9a7c0ab7ac8f9c316836ade382f4b9780492f0a8a35a658f827bcb1d7f"},
1133 | {file = "tarina-0.6.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:491b46bfd030f64edc8daac99051e9e1a82d4592aaa9d91c86d18da7f1816a8d"},
1134 | {file = "tarina-0.6.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8dab1c7ff584f427ae671ecd0379b5795f3ddfee867c5c8997fb110c35b72901"},
1135 | {file = "tarina-0.6.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9f998c32df568da30f236876118f5c359caf00d4935249c78c2e6e15caa1a72f"},
1136 | {file = "tarina-0.6.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b427b03be5e9d19882558dafd8cae6decc4406f1511741409f1b75a5ce0bf447"},
1137 | {file = "tarina-0.6.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec0bb5da7bbea3df20750acab45403c5fbd5a0b5c4dd7267e6d0cb3669935db4"},
1138 | {file = "tarina-0.6.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7acbc4b547fd623beb174431e2d01b2bc2a5d7451fe3d0e9ae3e0118d862d375"},
1139 | {file = "tarina-0.6.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed03a67986b00411aa5d3cd02896e5daf0e5af44247fd0ef79484b06780a2462"},
1140 | {file = "tarina-0.6.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:637740055c0e7da77793e0f2d56189f4620e9db31578c590234f85240364e80d"},
1141 | {file = "tarina-0.6.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9df3d4441b36b7e6ac290b05dd9a1e6193ff0acc2d970be2b855283b76d0ad40"},
1142 | {file = "tarina-0.6.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ff583c3579e5ea939da67c6a32ebced76b270c884d9f686a003f66f32a0cecdc"},
1143 | {file = "tarina-0.6.8-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:91589c96904f6a07ccf7fec977c403bab52aad63bd3a801a32e11d2ee85e1d46"},
1144 | {file = "tarina-0.6.8-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4a7448cacff18d536c3cf4453282ee29cf401442cba1a50f02981e5d4c374d7f"},
1145 | {file = "tarina-0.6.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:96fe4a3a33fa20cc3bd996ef9e4a909b00c37d89bd24d594a6024ca59a26c6c4"},
1146 | {file = "tarina-0.6.8-cp39-cp39-win32.whl", hash = "sha256:cbff457659568f46fbbb8e594644278b51efddb532890117b4965b8c059d4d4a"},
1147 | {file = "tarina-0.6.8-cp39-cp39-win_amd64.whl", hash = "sha256:bace5eeaed47048e9a8e9dd7953aadc11aace8c8a5db8457906d8f9c52604fc5"},
1148 | {file = "tarina-0.6.8-py3-none-any.whl", hash = "sha256:0e8a04eecb741937244d97da54f8cd36995819fc12a6b60c9b3f3f3d2860ebe6"},
1149 | {file = "tarina-0.6.8.tar.gz", hash = "sha256:d77d68948967a130066b61e85b21189259030f80ad19295bd81ff6b52f348316"},
1150 | ]
1151 |
1152 | [[package]]
1153 | name = "tomli"
1154 | version = "2.2.1"
1155 | requires_python = ">=3.8"
1156 | summary = "A lil' TOML parser"
1157 | groups = ["default"]
1158 | marker = "python_version < \"3.11\""
1159 | files = [
1160 | {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
1161 | {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
1162 | {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
1163 | {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
1164 | {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
1165 | {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
1166 | {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
1167 | {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
1168 | {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
1169 | {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
1170 | {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
1171 | {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
1172 | {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
1173 | {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
1174 | {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
1175 | {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
1176 | {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
1177 | {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
1178 | {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
1179 | {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
1180 | {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
1181 | {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
1182 | {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
1183 | {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
1184 | {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
1185 | {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
1186 | {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
1187 | {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
1188 | {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
1189 | {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
1190 | {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
1191 | {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
1192 | ]
1193 |
1194 | [[package]]
1195 | name = "typing-extensions"
1196 | version = "4.12.2"
1197 | requires_python = ">=3.8"
1198 | summary = "Backported and Experimental Type Hints for Python 3.8+"
1199 | groups = ["default"]
1200 | files = [
1201 | {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
1202 | {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
1203 | ]
1204 |
1205 | [[package]]
1206 | name = "tzdata"
1207 | version = "2025.1"
1208 | requires_python = ">=2"
1209 | summary = "Provider of IANA time zone data"
1210 | groups = ["default"]
1211 | marker = "platform_system == \"Windows\""
1212 | files = [
1213 | {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"},
1214 | {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"},
1215 | ]
1216 |
1217 | [[package]]
1218 | name = "tzlocal"
1219 | version = "5.2"
1220 | requires_python = ">=3.8"
1221 | summary = "tzinfo object for the local timezone"
1222 | groups = ["default"]
1223 | dependencies = [
1224 | "backports-zoneinfo; python_version < \"3.9\"",
1225 | "tzdata; platform_system == \"Windows\"",
1226 | ]
1227 | files = [
1228 | {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"},
1229 | {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"},
1230 | ]
1231 |
1232 | [[package]]
1233 | name = "win32-setctime"
1234 | version = "1.2.0"
1235 | requires_python = ">=3.5"
1236 | summary = "A small Python utility to set file creation time on Windows"
1237 | groups = ["default"]
1238 | marker = "sys_platform == \"win32\""
1239 | files = [
1240 | {file = "win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390"},
1241 | {file = "win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0"},
1242 | ]
1243 |
1244 | [[package]]
1245 | name = "yarl"
1246 | version = "1.18.3"
1247 | requires_python = ">=3.9"
1248 | summary = "Yet another URL library"
1249 | groups = ["default"]
1250 | dependencies = [
1251 | "idna>=2.0",
1252 | "multidict>=4.0",
1253 | "propcache>=0.2.0",
1254 | ]
1255 | files = [
1256 | {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"},
1257 | {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"},
1258 | {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"},
1259 | {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"},
1260 | {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"},
1261 | {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"},
1262 | {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"},
1263 | {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"},
1264 | {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"},
1265 | {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"},
1266 | {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"},
1267 | {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"},
1268 | {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"},
1269 | {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"},
1270 | {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"},
1271 | {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"},
1272 | {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"},
1273 | {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"},
1274 | {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"},
1275 | {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"},
1276 | {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"},
1277 | {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"},
1278 | {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"},
1279 | {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"},
1280 | {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"},
1281 | {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"},
1282 | {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"},
1283 | {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"},
1284 | {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"},
1285 | {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"},
1286 | {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"},
1287 | {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"},
1288 | {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"},
1289 | {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"},
1290 | {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"},
1291 | {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"},
1292 | {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"},
1293 | {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"},
1294 | {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"},
1295 | {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"},
1296 | {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"},
1297 | {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"},
1298 | {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"},
1299 | {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"},
1300 | {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"},
1301 | {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"},
1302 | {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"},
1303 | {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"},
1304 | {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"},
1305 | {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"},
1306 | {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"},
1307 | {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"},
1308 | {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"},
1309 | {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"},
1310 | {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"},
1311 | {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"},
1312 | {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"},
1313 | {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"},
1314 | {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"},
1315 | {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"},
1316 | {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"},
1317 | {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"},
1318 | {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"},
1319 | {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"},
1320 | {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"},
1321 | {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"},
1322 | {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"},
1323 | {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"},
1324 | {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"},
1325 | {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"},
1326 | {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"},
1327 | {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"},
1328 | {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"},
1329 | {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"},
1330 | {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"},
1331 | {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"},
1332 | {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"},
1333 | {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"},
1334 | {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"},
1335 | {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"},
1336 | {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"},
1337 | {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"},
1338 | ]
1339 |
1340 | [[package]]
1341 | name = "zipp"
1342 | version = "3.21.0"
1343 | requires_python = ">=3.9"
1344 | summary = "Backport of pathlib-compatible object wrapper for zip files"
1345 | groups = ["default"]
1346 | files = [
1347 | {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"},
1348 | {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"},
1349 | ]
1350 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "nonebot-plugin-picstatus"
3 | dynamic = ["version"]
4 | description = "A NoneBot2 plugin generates a picture which shows the status of current device"
5 | authors = [{ name = "LgCookie", email = "lgc2333@126.com" }]
6 | dependencies = [
7 | "nonebot2>=2.4.1",
8 | "nonebot-plugin-apscheduler>=0.5.0",
9 | "nonebot-plugin-alconna>=0.54.2",
10 | "nonebot-plugin-userinfo>=0.2.6",
11 | "nonebot-plugin-htmlrender>=0.5.1",
12 | "cookit[jinja,loguru,playwright,pydantic]>=0.9.3",
13 | "psutil>=6.1.1",
14 | "py-cpuinfo>=9.0.0",
15 | "anyio>=4.8.0",
16 | "httpx>=0.27.2",
17 | "jinja2>=3.1.5",
18 | "yarl>=1.18.3",
19 | ]
20 | requires-python = ">=3.9,<4.0"
21 | readme = "README.md"
22 | license = { text = "MIT" }
23 |
24 | [project.urls]
25 | homepage = "https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus"
26 |
27 | [tool.pdm]
28 |
29 | [tool.pdm.version]
30 | source = "file"
31 | path = "nonebot_plugin_picstatus/__init__.py"
32 |
33 | [tool.pdm.build]
34 | includes = []
35 |
36 | [build-system]
37 | requires = ["pdm-backend"]
38 | build-backend = "pdm.backend"
39 |
--------------------------------------------------------------------------------