Compare commits
2 Commits
82fd8ab199
...
709e15663b
| Author | SHA1 | Date | |
|---|---|---|---|
| 709e15663b | |||
| 85925b9d44 |
6
data/config/_.toml
Normal file
6
data/config/_.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
_services_desc = '服务模块(services)设置'
|
||||||
|
_providers_desc = '驱动模块(providers)设置'
|
||||||
|
_repo_desc = '单元集独立设置'
|
||||||
|
_interface_desc = '基本用户界面设置'
|
||||||
|
_default_desc = '默认设置'
|
||||||
|
_global_desc = '底层设置'
|
||||||
@@ -1,7 +1,17 @@
|
|||||||
enable_built_in_interface = true
|
zmq_debug = false
|
||||||
|
_zmq_debug_desc = "[调试] ZMQ 调试服务器, 这会在 zmq_debug_port 上打开调试服务器\n可作为 HeurAMS 执行任意 python 代码, 如无必要请关闭"
|
||||||
|
zmq_debug_port = 5555
|
||||||
|
_zmq_debug_port_desc = "ZMQ 调试服务器端口"
|
||||||
|
enable_built_in_interface = false
|
||||||
|
_enable_built_in_interface_desc = "启用内置基本用户界面\n(当且仅当 HeurAMS 作为程序库时禁用, 以跳过用户界面逻辑)"
|
||||||
|
_paths_desc = "用户数据路径定义"
|
||||||
|
|
||||||
[paths]
|
[paths]
|
||||||
data = "./data"
|
data = "./data"
|
||||||
|
_data_desc = "用户数据根目录"
|
||||||
cache = "./data/cache"
|
cache = "./data/cache"
|
||||||
|
_cache_desc = "缓存根目录\n(如音频缓存在 voice 子目录)"
|
||||||
config = "./data/config"
|
config = "./data/config"
|
||||||
|
_config_desc = "配置文件根目录"
|
||||||
repo = "./data/repo"
|
repo = "./data/repo"
|
||||||
|
_repo_desc = "记忆单元集根目录"
|
||||||
|
|||||||
4
data/config/interface/_.toml
Normal file
4
data/config/interface/_.toml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
_global_desc = "用户界面通用设置"
|
||||||
|
_widgets_desc = "各组件设置"
|
||||||
|
_screens_desc = "各界面设置"
|
||||||
|
_puzzles_desc = "谜题生成器设置"
|
||||||
@@ -1,6 +1,17 @@
|
|||||||
persist_to_file = true
|
persist_to_file = true
|
||||||
|
_persist_to_file_desc = "[调试] 将记忆更改保存到文件"
|
||||||
quick_pass = true
|
quick_pass = true
|
||||||
|
_quick_pass_desc = "[调试] 启用快速应答功能(跳过测验)"
|
||||||
auto_pass = false
|
auto_pass = false
|
||||||
scheduled_num = 420
|
_auto_pass_desc = "[调试] 自动通过测试模式"
|
||||||
|
scheduled_num = "420"
|
||||||
|
_scheduled_num_desc = "默认记忆单元数量(可被单元集设置覆盖)"
|
||||||
algorithm = "NSP-0"
|
algorithm = "NSP-0"
|
||||||
_algorithm_candidate = [ "SM-2", "SM-15M", "FSRS", "NSP-0", "None",]
|
_algorithm_desc = "默认记忆调度算法(可被单元集设置覆盖)"
|
||||||
|
|
||||||
|
[_algorithm_candidate]
|
||||||
|
NSP-0 = "筛选用非间隔重复调度器"
|
||||||
|
none = "不设置默认调度器"
|
||||||
|
SM-2 = "第二代 SuperMemo 简单间隔重复调度器"
|
||||||
|
SM-15M = "第15代 SuperMemo 复杂间隔重复调度器 (不稳定且逆向工程)"
|
||||||
|
FSRS = "先进开放间隔重复调度器"
|
||||||
|
|||||||
2
data/config/interface/puzzles/_.toml
Normal file
2
data/config/interface/puzzles/_.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
_cloze_desc = "填空题"
|
||||||
|
_mcq_desc = "选择题"
|
||||||
@@ -1 +1,2 @@
|
|||||||
min_denominator = 3
|
min_denominator = "3"
|
||||||
|
_min_denominator_desc = "设空比例系数的倒数"
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
max_riddles_num = 2
|
max_riddles_num = "2"
|
||||||
|
_max_riddles_num_desc = "单次生成的最大谜题数量"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
autovoice = true
|
|
||||||
1
data/config/interface/widgets/_.toml
Normal file
1
data/config/interface/widgets/_.toml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
_recognition_desc = "用于 '辨识' 组件的设置"
|
||||||
@@ -1 +1,2 @@
|
|||||||
autovoice = true
|
autovoice = true
|
||||||
|
_autovoice_desc = "自动语音播放"
|
||||||
|
|||||||
1
data/config/providers/_.toml
Normal file
1
data/config/providers/_.toml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
_tts_desc = '文本转语音驱动'
|
||||||
1
data/config/providers/tts/_.toml
Normal file
1
data/config/providers/tts/_.toml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
_edgetts_desc = "微软文本转语音驱动"
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
voice = "zh-CN-XiaoxiaoNeural"
|
voice = "zh-CN-XiaoxiaoNeural"
|
||||||
|
_voice_desc = "音色"
|
||||||
|
|
||||||
[_voice_candidate]
|
[_voice_candidate]
|
||||||
zh-CN-XiaoxiaoNeural = "晓晓: 中文温柔女声"
|
zh-CN-XiaoxiaoNeural = "晓晓: 中文温柔女声"
|
||||||
|
|||||||
5
data/config/services/_.toml
Normal file
5
data/config/services/_.toml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
_audio_desc = '音频服务'
|
||||||
|
_llm_desc = '语言模型服务'
|
||||||
|
_sync_desc = '数据同步服务'
|
||||||
|
_timer_desc = '时间服务'
|
||||||
|
_tts_desc = '文本转语音服务'
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
provider = "playsound"
|
provider = "playsound"
|
||||||
|
_provider_desc = "音频驱动类型"
|
||||||
|
|
||||||
[_provider_candidate]
|
[_provider_candidate]
|
||||||
playsound = "python 跨平台音频系统"
|
playsound = "python 跨平台音频系统"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
provider = "openai"
|
provider = "openai"
|
||||||
|
_provider_desc = "模型接口类型"
|
||||||
|
|
||||||
[_provider_candidate]
|
[_provider_candidate]
|
||||||
openai = "OpenAI 风格 API, 同时支持与其相容的模型服务 (如 deepseek)"
|
openai = "OpenAI 风格 API, 同时支持与其相容的模型服务 (如 deepseek)"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
provider = "webdav"
|
provider = "webdav"
|
||||||
|
_provider_desc = "同步服务驱动类型"
|
||||||
|
|
||||||
[_provider_candidate]
|
[_provider_candidate]
|
||||||
webdav = "WebDAV 兼容网络文件系统 (包括 webdavs)"
|
webdav = "WebDAV 兼容网络文件系统 (包括 webdavs)"
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
daystamp_override = -1
|
daystamp_override = -1
|
||||||
|
_daystamp_override_desc = "[调试] 覆写 UNIX 日时间戳, 单位为日\n(设为 -1 禁用)"
|
||||||
timestamp_override = -1
|
timestamp_override = -1
|
||||||
|
_timestamp_override_desc = "[调试] 覆写 UNIX 时间戳, 单位为秒\n(设为 -1 禁用)"
|
||||||
timezone_offset = 28800
|
timezone_offset = 28800
|
||||||
|
_timezone_offset_desc = "时区偏移设置, 用于取消跨天时区误差, 单位为秒\n(如 28800 为 UTC+8.0, 中国标准时间)"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
provider = "edgetts"
|
provider = "edgetts"
|
||||||
|
_provider_desc = "文本转语音驱动类型"
|
||||||
|
|
||||||
[_provider_candidate]
|
[_provider_candidate]
|
||||||
edgetts = "微软神经网络语音合成, 依赖微软网络服务"
|
edgetts = "微软神经网络语音合成, 依赖微软网络服务"
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
[aa.bb]
|
|
||||||
str = "sq"
|
|
||||||
boolean = true
|
|
||||||
int = 123
|
|
||||||
@@ -16,6 +16,7 @@ dependencies = [
|
|||||||
"textual>=8.2.3",
|
"textual>=8.2.3",
|
||||||
"toml>=0.10.2",
|
"toml>=0.10.2",
|
||||||
"transitions>=0.9.3",
|
"transitions>=0.9.3",
|
||||||
|
"zmq>=0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
from heurams.interface import *
|
from heurams.interface import *
|
||||||
from heurams.context import config_var
|
from heurams.context import config_var
|
||||||
from heurams.services.logger import get_logger
|
from heurams.services.logger import get_logger
|
||||||
|
import threading
|
||||||
|
import zmq
|
||||||
|
import pickle
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
@@ -20,9 +23,43 @@ def environment_check():
|
|||||||
print(f"找到 {i}")
|
print(f"找到 {i}")
|
||||||
logger.debug("环境检查完成")
|
logger.debug("环境检查完成")
|
||||||
|
|
||||||
|
def start_debug_server(app):
|
||||||
|
logger = get_logger("zmq_debug")
|
||||||
|
context = zmq.Context()
|
||||||
|
socket = context.socket(zmq.REP)
|
||||||
|
port = config_var.get()['global'].get('zmq_debug_port', 5555)
|
||||||
|
socket.bind(f"tcp://*:{port}")
|
||||||
|
logger.info(f"ZMQ Debug server started on port {port}")
|
||||||
|
first = 1
|
||||||
|
while True:
|
||||||
|
msg = socket.recv()
|
||||||
|
code = pickle.loads(msg)
|
||||||
|
namespace = {"app": app, "logger": logger, "config_var": config_var}
|
||||||
|
if first:
|
||||||
|
app.title += ' [调试已连接]'
|
||||||
|
first = 0
|
||||||
|
try:
|
||||||
|
# 先尝试 eval
|
||||||
|
result = eval(code, namespace)
|
||||||
|
socket.send(pickle.dumps(f"成功: {result}"))
|
||||||
|
except SyntaxError:
|
||||||
|
# 再尝试 exec
|
||||||
|
try:
|
||||||
|
exec(code, namespace)
|
||||||
|
socket.send(pickle.dumps(f"成功: 执行完成"))
|
||||||
|
except Exception as e:
|
||||||
|
socket.send(pickle.dumps(f"错误: {e}"))
|
||||||
|
except Exception as e:
|
||||||
|
socket.send(pickle.dumps(f"错误: {e}"))
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
environment_check()
|
environment_check()
|
||||||
|
|
||||||
app = HeurAMSApp()
|
app = HeurAMSApp()
|
||||||
|
|
||||||
|
if config_var.get()['global'].get('zmq_debug', False):
|
||||||
|
threading.Thread(target=start_debug_server, args=(app,), daemon=True).start()
|
||||||
|
|
||||||
app.run(inline=False)
|
app.run(inline=False)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -39,7 +39,10 @@ NavigatorScreen {
|
|||||||
margin-top: 1;
|
margin-top: 1;
|
||||||
align: center middle;
|
align: center middle;
|
||||||
}
|
}
|
||||||
|
.container {
|
||||||
|
height: auto;
|
||||||
|
padding: 0 0 1 0;
|
||||||
|
}
|
||||||
#message-input {
|
#message-input {
|
||||||
width: 1fr;
|
width: 1fr;
|
||||||
margin-right: 1;
|
margin-right: 1;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import os
|
|||||||
from textual.app import ComposeResult
|
from textual.app import ComposeResult
|
||||||
from textual.containers import ScrollableContainer, Container, Horizontal, Vertical
|
from textual.containers import ScrollableContainer, Container, Horizontal, Vertical
|
||||||
from textual.screen import Screen
|
from textual.screen import Screen
|
||||||
from textual.widgets import Button, Footer, Header, Label, ListItem, ListView, Static, Collapsible, Input, Switch
|
from textual.widgets import Button, Footer, Header, Label, ListItem, ListView, Static, Collapsible, Input, Switch, Select
|
||||||
from textual.layouts import horizontal
|
from textual.layouts import horizontal
|
||||||
|
|
||||||
import heurams.kernel.particles as pt
|
import heurams.kernel.particles as pt
|
||||||
@@ -45,9 +45,13 @@ class SettingScreen(Screen):
|
|||||||
"""组合界面组件"""
|
"""组合界面组件"""
|
||||||
yield Header(show_clock=True)
|
yield Header(show_clock=True)
|
||||||
with ScrollableContainer():
|
with ScrollableContainer():
|
||||||
yield Label('设置页面')
|
yield Label('[b]设置页面[/b]')
|
||||||
for i in config_var.get():
|
for i in config_var.get():
|
||||||
yield Collapsible(*self._get_subcfg(f'{i}'), title=i)
|
if i.startswith('_'):
|
||||||
|
continue
|
||||||
|
a = self._get_subcfg(f'{i}')
|
||||||
|
if a:
|
||||||
|
yield Collapsible(*a, title=i + f'\n{config_var.get().get(f"_{i}_desc", "")}')
|
||||||
yield Footer()
|
yield Footer()
|
||||||
|
|
||||||
def _get_subcfg(self, parent_epath: str):
|
def _get_subcfg(self, parent_epath: str):
|
||||||
@@ -56,7 +60,11 @@ class SettingScreen(Screen):
|
|||||||
if parent.is_dir:
|
if parent.is_dir:
|
||||||
lst = list()
|
lst = list()
|
||||||
for i in parent:
|
for i in parent:
|
||||||
lst.append(Collapsible(*self._get_subcfg(f"{parent_epath}.{i}"), title=i))
|
if i.startswith('_'):
|
||||||
|
continue
|
||||||
|
a = self._get_subcfg(f"{parent_epath}.{i}")
|
||||||
|
if a:
|
||||||
|
lst.append(Collapsible(*a, title=i + f'\n{parent.get(f"_{i}_desc", "")}'))
|
||||||
return lst
|
return lst
|
||||||
if isinstance(parent, dict) or (isinstance(parent, ConfigDict) and not parent.is_dir):
|
if isinstance(parent, dict) or (isinstance(parent, ConfigDict) and not parent.is_dir):
|
||||||
lst = list()
|
lst = list()
|
||||||
@@ -64,32 +72,47 @@ class SettingScreen(Screen):
|
|||||||
if i.startswith('_'):
|
if i.startswith('_'):
|
||||||
continue
|
continue
|
||||||
if isinstance(parent[i], dict):
|
if isinstance(parent[i], dict):
|
||||||
lst.append(Collapsible(*self._get_subcfg(f"{parent_epath}.{i}"), title=i))
|
a = self._get_subcfg(f"{parent_epath}.{i}")
|
||||||
elif isinstance(parent[i], float):
|
if a:
|
||||||
lst.extend([
|
lst.append(Collapsible(*a, title=i + f'\n{parent.get(f"_{i}_desc", "")}'))
|
||||||
Label(i),
|
elif f'_{i}_candidate' in parent: # 选择框模式
|
||||||
Input(value=str(parent[i]), placeholder='要求一个浮点数', type='number', id=domize(f"{parent_epath}.{i}"))
|
if isinstance(parent[f'_{i}_candidate'], dict):
|
||||||
])
|
lst.append(Horizontal(
|
||||||
|
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||||
|
Select(((f"{j} ({k})", j) for j, k in parent[f'_{i}_candidate'].items()), prompt=f'{parent.get(f"{i}", "")}', id=domize(f"{parent_epath}.{i}")),
|
||||||
|
classes='container'
|
||||||
|
))
|
||||||
|
elif isinstance(parent[f'_{i}_candidate'], list):
|
||||||
|
lst.append(Horizontal(
|
||||||
|
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||||
|
Select(((j, j) for j in parent[f'_{i}_candidate']), prompt=f'{parent.get(f"{i}", "")}', id=domize(f"{parent_epath}.{i}")),
|
||||||
|
classes='container'
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
if isinstance(parent[i], float):
|
||||||
|
lst.append(Horizontal(
|
||||||
|
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||||
|
Input(value=str(parent[i]), placeholder='要求一个浮点数', type='number', id=domize(f"{parent_epath}.{i}")),
|
||||||
|
classes='container'))
|
||||||
elif isinstance(parent[i], str):
|
elif isinstance(parent[i], str):
|
||||||
lst.extend([
|
lst.append(Horizontal(
|
||||||
Label(i),
|
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||||
Input(value=parent[i], placeholder='要求一个字符串', type='text', id=domize(f"{parent_epath}.{i}"))
|
Input(value=parent[i], placeholder='要求一个字符串', type='text', id=domize(f"{parent_epath}.{i}")),
|
||||||
])
|
classes='container'))
|
||||||
elif isinstance(parent[i], bool):
|
elif isinstance(parent[i], bool):
|
||||||
lst.extend([
|
lst.append(Horizontal(
|
||||||
Label(i),
|
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||||
Switch(value=str(parent[i]), id=domize(f"{parent_epath}.{i}"))
|
Switch(value=parent[i], id=domize(f"{parent_epath}.{i}")),
|
||||||
])
|
classes='container'))
|
||||||
elif isinstance(parent[i], int):
|
elif isinstance(parent[i], int):
|
||||||
lst.extend([
|
lst.append(Horizontal(
|
||||||
Label(i),
|
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||||
Input(value=str(parent[i]), placeholder='要求一个整数', type='integer', id=domize(f"{parent_epath}.{i}"))
|
Input(value=str(parent[i]), placeholder='要求一个整数', type='integer', id=domize(f"{parent_epath}.{i}")),
|
||||||
])
|
classes='container'))
|
||||||
elif isinstance(parent[i], list):
|
elif isinstance(parent[i], list):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
lst.append(Label('未知类型'))
|
lst.append(Label('未知类型'))
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
return [Label('无子项')]
|
return [Label('无子项')]
|
||||||
|
|
||||||
@@ -97,6 +120,11 @@ class SettingScreen(Screen):
|
|||||||
"""挂载组件时初始化"""
|
"""挂载组件时初始化"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def action_go_back(self) -> None:
|
||||||
|
"""返回上一屏幕"""
|
||||||
|
config_var.get().persist()
|
||||||
|
self.app.pop_screen()
|
||||||
|
|
||||||
def action_quit_app(self) -> None:
|
def action_quit_app(self) -> None:
|
||||||
"""退出应用程序"""
|
"""退出应用程序"""
|
||||||
self.app.exit()
|
self.app.exit()
|
||||||
@@ -105,12 +133,27 @@ class SettingScreen(Screen):
|
|||||||
"""打开导航器"""
|
"""打开导航器"""
|
||||||
self.app.push_screen(NavigatorScreen())
|
self.app.push_screen(NavigatorScreen())
|
||||||
|
|
||||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
||||||
logger.debug(f"event.button.id: {event.button.id}")
|
def on_input_changed(self, event: Input.Changed) -> None:
|
||||||
"""处理按钮点击事件"""
|
widget_id = event.input.id
|
||||||
if str(event.button.id) == 'apply':
|
if not widget_id:
|
||||||
pass
|
return
|
||||||
if str(event.button.id) == 'openfolder':
|
eepath = undomize(widget_id)
|
||||||
pass
|
value = event.value
|
||||||
if str(event.button.id) == 'cancel':
|
epath(config_var.get(), eepath, enable_modify=True, new_value=type(epath(config_var.get(), eepath))(value))
|
||||||
pass
|
|
||||||
|
def on_switch_changed(self, event: Switch.Changed) -> None:
|
||||||
|
widget_id = event.switch.id
|
||||||
|
if not widget_id:
|
||||||
|
return
|
||||||
|
eepath = undomize(widget_id)
|
||||||
|
value = event.value
|
||||||
|
epath(config_var.get(), eepath, enable_modify=True, new_value=type(epath(config_var.get(), eepath))(value))
|
||||||
|
|
||||||
|
def on_select_changed(self, event: Select.Changed) -> None:
|
||||||
|
widget_id = event.select.id
|
||||||
|
if not widget_id:
|
||||||
|
return
|
||||||
|
eepath = undomize(widget_id)
|
||||||
|
value = event.value
|
||||||
|
epath(config_var.get(), eepath, enable_modify=True, new_value=type(epath(config_var.get(), eepath))(value))
|
||||||
@@ -9,17 +9,38 @@ from heurams.services.logger import get_logger
|
|||||||
from heurams.services.exceptions import WTFException
|
from heurams.services.exceptions import WTFException
|
||||||
|
|
||||||
# 我们的流程是: 找到文件名: 返回文件名里头的数据; 找不到: 继续查索引; 所以 self.data 除了存本级各种索引球用没得
|
# 我们的流程是: 找到文件名: 返回文件名里头的数据; 找不到: 继续查索引; 所以 self.data 除了存本级各种索引球用没得
|
||||||
# 递归就是这么吊
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
class ConfigDict(UserDict): # 舒服了
|
class ConfigDict(UserDict): # 舒服了
|
||||||
|
_instances = {} # 必须使用单例模式, 不然有严重的多实例导致的配置无法持久化问题
|
||||||
|
|
||||||
|
def __new__(cls, config_path: pathlib.Path, dict=None):
|
||||||
|
if dict:
|
||||||
|
raise WTFException("不要放默认值...")
|
||||||
|
|
||||||
|
# 规范化路径, 免得单例存在"别名"
|
||||||
|
path_key = config_path.resolve()
|
||||||
|
|
||||||
|
if path_key in cls._instances:
|
||||||
|
return cls._instances[path_key]
|
||||||
|
|
||||||
|
instance = super().__new__(cls)
|
||||||
|
cls._instances[path_key] = instance
|
||||||
|
return instance
|
||||||
|
|
||||||
def __init__(self, config_path: pathlib.Path, dict = None): # 需要自己把自己提起来
|
def __init__(self, config_path: pathlib.Path, dict = None): # 需要自己把自己提起来
|
||||||
|
# 避免重复初始化
|
||||||
|
if hasattr(self, '_initialized'):
|
||||||
|
return
|
||||||
|
self._initialized = True
|
||||||
if dict:
|
if dict:
|
||||||
raise WTFException("不要放默认值...")
|
raise WTFException("不要放默认值...")
|
||||||
super().__init__(dict)
|
super().__init__(dict)
|
||||||
self.logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
self.path = config_path
|
self.path = config_path
|
||||||
self.is_dir = self.path.is_dir()
|
self.is_dir = self.path.is_dir()
|
||||||
if self.is_dir:
|
if self.is_dir:
|
||||||
self.update_index() # 狗儿要唱狗儿歌
|
self.update_index()
|
||||||
else:
|
else:
|
||||||
with open(self.path, 'r+') as f: #TODO: 给这个做缓存
|
with open(self.path, 'r+') as f: #TODO: 给这个做缓存
|
||||||
try:
|
try:
|
||||||
@@ -35,11 +56,6 @@ class ConfigDict(UserDict): # 舒服了
|
|||||||
return ConfigDict(value)
|
return ConfigDict(value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def converter(self, s):
|
|
||||||
if (self.path / s).exists:
|
|
||||||
return self.path / s
|
|
||||||
return self.path / s+'.toml'
|
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
return super().__contains__(key)
|
return super().__contains__(key)
|
||||||
|
|
||||||
@@ -56,28 +72,27 @@ class ConfigDict(UserDict): # 舒服了
|
|||||||
|
|
||||||
def update_index(self): # 如果有人没事干在config里面创建指向config的符号链接 这玩意会崩溃 但是不要修复: 需要这个符号链接特性
|
def update_index(self): # 如果有人没事干在config里面创建指向config的符号链接 这玩意会崩溃 但是不要修复: 需要这个符号链接特性
|
||||||
for i in self.path.iterdir():
|
for i in self.path.iterdir():
|
||||||
|
if i.name.startswith('_'):
|
||||||
|
if i.name == '_.toml' and not i.is_dir():
|
||||||
|
with open(self.path/'_.toml', 'r+') as f:
|
||||||
|
self.data.update(dict(toml.load(f)))
|
||||||
|
continue
|
||||||
if i.is_dir():
|
if i.is_dir():
|
||||||
self.data[i.name] = i
|
self.data[i.name] = i
|
||||||
else:
|
else:
|
||||||
if i.suffix == '.toml':
|
if i.suffix == '.toml':
|
||||||
self.data[i.stem] = i
|
self.data[i.stem] = i
|
||||||
else:
|
else:
|
||||||
self.logger.log(f"配置目录中有无效的文件 {i.stem}") # what's up bro
|
logger.debug(f"配置目录中有无效的文件 {i.stem}") # what's up bro
|
||||||
|
|
||||||
def persist(self):
|
def persist(self):
|
||||||
if self.is_dir:
|
if self.is_dir:
|
||||||
raise WTFException("不准这样浪费性能...")
|
for i in self.data.keys():
|
||||||
|
j = self[i]
|
||||||
|
if isinstance(j, ConfigDict):
|
||||||
|
j.persist()
|
||||||
|
logger.debug("完成配置持久化")
|
||||||
|
return
|
||||||
|
|
||||||
with open(self.path, 'w+') as f:
|
with open(self.path, 'w+') as f:
|
||||||
toml.dump(self.data, f)
|
toml.dump(self.data, f)
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
if not self.is_dir:
|
|
||||||
self.persist() # 不准循环引用, 懂了吧
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def titleize(objt):
|
|
||||||
if isinstance(objt, pathlib.Path):
|
|
||||||
return objt.stem
|
|
||||||
else:
|
|
||||||
return objt
|
|
||||||
@@ -2,29 +2,53 @@ from heurams.services.config import ConfigDict
|
|||||||
from heurams.services.logger import get_logger
|
from heurams.services.logger import get_logger
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
def epath(dct, path: str = '', default=None, parents=False):
|
|
||||||
|
def epath(dct, path: str = '', default=None, parents=False, enable_modify=False, new_value=None):
|
||||||
if not path:
|
if not path:
|
||||||
return dct
|
return dct
|
||||||
|
|
||||||
path = path.rstrip('.')
|
path = path.rstrip('.')
|
||||||
path = path.lstrip('.')
|
path = path.lstrip('.')
|
||||||
target = dct
|
target = dct
|
||||||
|
keys = path.split('.')
|
||||||
|
logger.debug(f"处理 EPATH {path}, {new_value}")
|
||||||
|
for idx, i in enumerate(keys):
|
||||||
|
is_last = (idx == len(keys) - 1)
|
||||||
|
|
||||||
for i in path.split('.'):
|
|
||||||
# 处理字典键
|
# 处理字典键
|
||||||
logger.debug(f'处理 {i}, {(isinstance(target, dict) or isinstance(target, ConfigDict))} {i in target}')
|
logger.debug(f'处理 {i}, {(isinstance(target, dict) or isinstance(target, ConfigDict))} {i in target}')
|
||||||
|
|
||||||
|
if is_last and enable_modify:
|
||||||
|
# 最后一次循环执行修改
|
||||||
|
if (isinstance(target, dict) or isinstance(target, ConfigDict)):
|
||||||
|
target[i] = new_value
|
||||||
|
return new_value
|
||||||
|
elif i.startswith('[') and i.endswith(']') and isinstance(target, (list, tuple)):
|
||||||
|
idx_num = int(i[1:-1])
|
||||||
|
if 0 <= idx_num < len(target):
|
||||||
|
target[idx_num] = new_value
|
||||||
|
return new_value
|
||||||
|
elif parents:
|
||||||
|
while len(target) <= idx_num:
|
||||||
|
target.append(None)
|
||||||
|
target[idx_num] = new_value
|
||||||
|
return new_value
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
else:
|
||||||
if (isinstance(target, dict) or isinstance(target, ConfigDict)) and i in target:
|
if (isinstance(target, dict) or isinstance(target, ConfigDict)) and i in target:
|
||||||
target = target[i]
|
target = target[i]
|
||||||
# 处理列表索引
|
|
||||||
elif i.startswith('[') and i.endswith(']') and isinstance(target, (list, tuple)):
|
elif i.startswith('[') and i.endswith(']') and isinstance(target, (list, tuple)):
|
||||||
idx = int(i[1:-1])
|
idx_num = int(i[1:-1])
|
||||||
if 0 <= idx < len(target):
|
if 0 <= idx_num < len(target):
|
||||||
target = target[idx]
|
target = target[idx_num]
|
||||||
elif parents:
|
elif parents:
|
||||||
while len(target) <= idx:
|
while len(target) <= idx_num:
|
||||||
target.append(None)
|
target.append(None)
|
||||||
target[idx] = {}
|
target[idx_num] = {}
|
||||||
target = target[idx]
|
target = target[idx_num]
|
||||||
else:
|
else:
|
||||||
return default
|
return default
|
||||||
elif parents:
|
elif parents:
|
||||||
|
|||||||
55
src/heurams/tools/zmqclient.py
Normal file
55
src/heurams/tools/zmqclient.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import zmq
|
||||||
|
import pickle
|
||||||
|
import readline
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class DebugClient:
|
||||||
|
def __init__(self, port=5555):
|
||||||
|
self.context = zmq.Context()
|
||||||
|
self.socket = self.context.socket(zmq.REQ)
|
||||||
|
self.socket.connect(f"tcp://localhost:{port}")
|
||||||
|
print(f"已连接到调试服务器 (端口 {port})")
|
||||||
|
print("输入Python代码并按回车执行, 输入 'exit' 退出")
|
||||||
|
print("可用变量: app, logger")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
def execute(self, code):
|
||||||
|
"""执行代码并返回结果"""
|
||||||
|
try:
|
||||||
|
self.socket.send(pickle.dumps(code))
|
||||||
|
response = pickle.loads(self.socket.recv())
|
||||||
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
return f"连接错误: {e}"
|
||||||
|
|
||||||
|
def repl(self):
|
||||||
|
"""交互式REPL循环"""
|
||||||
|
self.execute('print("test")')
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
# 获取用户输入
|
||||||
|
code = input(">>> ").strip()
|
||||||
|
|
||||||
|
if not code:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if code.lower() in ['exit', 'quit']:
|
||||||
|
print("退出调试客户端")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 执行代码
|
||||||
|
result = self.execute(code)
|
||||||
|
print(f"结果: {result}\n")
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n退出调试客户端")
|
||||||
|
break
|
||||||
|
except EOFError:
|
||||||
|
break
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 从命令行参数获取端口
|
||||||
|
port = int(sys.argv[1]) if len(sys.argv) > 1 else 5555
|
||||||
|
|
||||||
|
client = DebugClient(port)
|
||||||
|
client.repl()
|
||||||
84
uv.lock
generated
84
uv.lock
generated
@@ -113,6 +113,39 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
|
{ url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cffi"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@@ -211,6 +244,7 @@ dependencies = [
|
|||||||
{ name = "textual" },
|
{ name = "textual" },
|
||||||
{ name = "toml" },
|
{ name = "toml" },
|
||||||
{ name = "transitions" },
|
{ name = "transitions" },
|
||||||
|
{ name = "zmq" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
@@ -225,6 +259,7 @@ requires-dist = [
|
|||||||
{ name = "textual", specifier = ">=8.2.3" },
|
{ name = "textual", specifier = ">=8.2.3" },
|
||||||
{ name = "toml", specifier = ">=0.10.2" },
|
{ name = "toml", specifier = ">=0.10.2" },
|
||||||
{ name = "transitions", specifier = ">=0.9.3" },
|
{ name = "transitions", specifier = ">=0.9.3" },
|
||||||
|
{ name = "zmq", specifier = ">=0.0.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -510,6 +545,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/d7/54/123f6239685f5f3f2edc123f1e38d2eefacebee18cf3c532d2f4bd51d0ef/pycairo-1.29.0-cp314-cp314t-win_arm64.whl", hash = "sha256:caba0837a4b40d47c8dfb0f24cccc12c7831e3dd450837f2a356c75f21ce5a15", size = 721404, upload-time = "2025-11-11T19:12:36.919Z" },
|
{ url = "https://files.pythonhosted.org/packages/d7/54/123f6239685f5f3f2edc123f1e38d2eefacebee18cf3c532d2f4bd51d0ef/pycairo-1.29.0-cp314-cp314t-win_arm64.whl", hash = "sha256:caba0837a4b40d47c8dfb0f24cccc12c7831e3dd450837f2a356c75f21ce5a15", size = 721404, upload-time = "2025-11-11T19:12:36.919Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycparser"
|
||||||
|
version = "3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.13.2"
|
version = "2.13.2"
|
||||||
@@ -584,6 +628,37 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/80/09247a2be28af2c2240132a0af6c1005a2b1d089242b13a2cd782d2de8d7/pygobject-3.56.2.tar.gz", hash = "sha256:b816098969544081de9eecedb94ad6ac59c77e4d571fe7051f18bebcec074313", size = 1409059, upload-time = "2026-03-25T16:14:04.008Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/a2/80/09247a2be28af2c2240132a0af6c1005a2b1d089242b13a2cd782d2de8d7/pygobject-3.56.2.tar.gz", hash = "sha256:b816098969544081de9eecedb94ad6ac59c77e4d571fe7051f18bebcec074313", size = 1409059, upload-time = "2026-03-25T16:14:04.008Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyzmq"
|
||||||
|
version = "27.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cffi", marker = "implementation_name == 'pypy'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rich"
|
name = "rich"
|
||||||
version = "15.0.0"
|
version = "15.0.0"
|
||||||
@@ -753,3 +828,12 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" },
|
{ url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" },
|
{ url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zmq"
|
||||||
|
version = "0.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pyzmq" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/6e/78/833b2808793c1619835edb1a4e17a023d5d625f4f97ff25ffff986d1f472/zmq-0.0.0.tar.gz", hash = "sha256:6b1a1de53338646e8c8405803cffb659e8eb7bb02fff4c9be62a7acfac8370c9", size = 966, upload-time = "2015-05-21T17:34:26.603Z" }
|
||||||
|
|||||||
Reference in New Issue
Block a user