aipyapp-qpython 0.1.24.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. aipyapp_qpython-0.1.24.20/PKG-INFO +44 -0
  2. aipyapp_qpython-0.1.24.20/aipyapp/__init__.py +1 -0
  3. aipyapp_qpython-0.1.24.20/aipyapp/__main__.py +36 -0
  4. aipyapp_qpython-0.1.24.20/aipyapp/aipy/__init__.py +7 -0
  5. aipyapp_qpython-0.1.24.20/aipyapp/aipy/config.py +105 -0
  6. aipyapp_qpython-0.1.24.20/aipyapp/aipy/i18n.py +212 -0
  7. aipyapp_qpython-0.1.24.20/aipyapp/aipy/interface.py +26 -0
  8. aipyapp_qpython-0.1.24.20/aipyapp/aipy/llm.py +540 -0
  9. aipyapp_qpython-0.1.24.20/aipyapp/aipy/plugin.py +87 -0
  10. aipyapp_qpython-0.1.24.20/aipyapp/aipy/prompt.py +684 -0
  11. aipyapp_qpython-0.1.24.20/aipyapp/aipy/prompt.zh.py +512 -0
  12. aipyapp_qpython-0.1.24.20/aipyapp/aipy/prompt_en.py +688 -0
  13. aipyapp_qpython-0.1.24.20/aipyapp/aipy/qpython.py +35 -0
  14. aipyapp_qpython-0.1.24.20/aipyapp/aipy/runner.py +182 -0
  15. aipyapp_qpython-0.1.24.20/aipyapp/aipy/task.py +264 -0
  16. aipyapp_qpython-0.1.24.20/aipyapp/aipy/taskmgr.py +108 -0
  17. aipyapp_qpython-0.1.24.20/aipyapp/aipy/template.html +290 -0
  18. aipyapp_qpython-0.1.24.20/aipyapp/aipy/templates.py +54 -0
  19. aipyapp_qpython-0.1.24.20/aipyapp/aipy/utils.py +76 -0
  20. aipyapp_qpython-0.1.24.20/aipyapp/default.toml +97 -0
  21. aipyapp_qpython-0.1.24.20/aipyapp/default_en.toml +97 -0
  22. aipyapp_qpython-0.1.24.20/aipyapp/gui.py +409 -0
  23. aipyapp_qpython-0.1.24.20/aipyapp/main.py +80 -0
  24. aipyapp_qpython-0.1.24.20/aipyapp/publish.py +60 -0
  25. aipyapp_qpython-0.1.24.20/aipyapp/saas.py +167 -0
  26. aipyapp_qpython-0.1.24.20/aipyapp/wxgui.py +367 -0
  27. aipyapp_qpython-0.1.24.20/aipyapp_qpython.egg-info/PKG-INFO +44 -0
  28. aipyapp_qpython-0.1.24.20/aipyapp_qpython.egg-info/SOURCES.txt +32 -0
  29. aipyapp_qpython-0.1.24.20/aipyapp_qpython.egg-info/dependency_links.txt +1 -0
  30. aipyapp_qpython-0.1.24.20/aipyapp_qpython.egg-info/requires.txt +15 -0
  31. aipyapp_qpython-0.1.24.20/aipyapp_qpython.egg-info/top_level.txt +1 -0
  32. aipyapp_qpython-0.1.24.20/pyproject.toml +5 -0
  33. aipyapp_qpython-0.1.24.20/setup.cfg +4 -0
  34. aipyapp_qpython-0.1.24.20/setup.py +60 -0
@@ -0,0 +1,44 @@
1
+ Metadata-Version: 2.4
2
+ Name: aipyapp-qpython
3
+ Version: 0.1.24.20
4
+ Summary: AIPython is a Python command-line interpreter integrated with LLM.
5
+ Home-page: https://qpypi.qpython.org/project/aipyapp-qpython/
6
+ Author: The QPYPI Team
7
+ Author-email: qpypi@qpython.org
8
+ License: GPL-3.0 license
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Intended Audience :: Education
11
+ Classifier: Intended Audience :: Information Technology
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Operating System :: Android
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development
18
+ Requires-Dist: anthropic-aipy
19
+ Requires-Dist: beautifulsoup4>=4.13.3
20
+ Requires-Dist: dynaconf>=3.2.10
21
+ Requires-Dist: google-api-python-client>=2.166.0
22
+ Requires-Dist: openai-aipy
23
+ Requires-Dist: pandas-aipy
24
+ Requires-Dist: prompt-toolkit>=3.0.50
25
+ Requires-Dist: pygments>=2.19.1
26
+ Requires-Dist: reportlab-qpython
27
+ Requires-Dist: requests>=2.32.3
28
+ Requires-Dist: rich>=13.9.4
29
+ Requires-Dist: seaborn-aipy
30
+ Requires-Dist: term-image-qpython
31
+ Requires-Dist: tomli-w>=1.2.0
32
+ Requires-Dist: qrcode>=8.1
33
+ Dynamic: author
34
+ Dynamic: author-email
35
+ Dynamic: classifier
36
+ Dynamic: description
37
+ Dynamic: home-page
38
+ Dynamic: license
39
+ Dynamic: requires-dist
40
+ Dynamic: summary
41
+
42
+
43
+ Python use provides the entire Python execution environment to LLM. Imagine LLM sitting in front of a computer, typing various commands into the Python command-line interpreter, pressing Enter to execute, observing the results, and then typing and executing more code.
44
+ Unlike Agents, Python use does not define any tools interface. LLM can freely use all the features provided by the Python runtime environment.
@@ -0,0 +1 @@
1
+ __version__ = '0.1.24'
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf-8
3
+ from pathlib import Path
4
+
5
+ from .aipy.config import SETTINGS_FILES
6
+
7
+ def main():
8
+ settings_files_help = "\n".join(map(str, SETTINGS_FILES))
9
+
10
+ config_help_message = (
11
+ f"Toml config file. If not provided, searches in:\n{settings_files_help}"
12
+ )
13
+
14
+ def parse_args():
15
+ import argparse
16
+ parser = argparse.ArgumentParser(description="AIPyApp on QPython", formatter_class=argparse.RawTextHelpFormatter)
17
+ parser.add_argument("-c", '--config', type=str, default="aipy.toml",
18
+ help=config_help_message) # Use the generated help message
19
+ parser.add_argument('-p', '--python', default=False, action='store_true', help="Python mode")
20
+ parser.add_argument('-g', '--gui', default=False, action='store_true', help="GUI mode")
21
+
22
+ parser.add_argument('cmd', nargs='?', default=None, help="Task to execute, e.g. 'Who are you?'")
23
+ return parser.parse_args()
24
+
25
+ args = parse_args()
26
+
27
+ if args.python:
28
+ from .main import main as aipy_main
29
+ elif args.gui:
30
+ from .gui import main as aipy_main
31
+ else:
32
+ from .saas import main as aipy_main
33
+ aipy_main(args)
34
+
35
+ if __name__ == '__main__':
36
+ main()
@@ -0,0 +1,7 @@
1
+ from .taskmgr import TaskManager
2
+ from .runner import Runner
3
+ from .llm import LLM, ChatHistory
4
+ from .i18n import T, set_lang
5
+ from .plugin import event_bus
6
+
7
+ __all__ = ['TaskManager', 'Runner', 'LLM', 'ChatHistory', 'T', 'set_lang', 'event_bus']
@@ -0,0 +1,105 @@
1
+ import os
2
+ import sys
3
+ import re
4
+ from pathlib import Path
5
+
6
+ from dynaconf import Dynaconf
7
+ from rich import print
8
+
9
+
10
+ from .i18n import T, set_lang
11
+
12
+ SETTINGS_FILES = [Path.home() / '.aipy.toml', Path('aipython.toml').resolve(), Path('.aipy.toml').resolve(), Path('aipy.toml').resolve()]
13
+
14
+ set_lang((os.getenv('LANG')[:2] if os.getenv('LANG') else "en"))
15
+
16
+ def is_valid_api_key(api_key):
17
+ """
18
+ 校验是否为有效的 API Key 格式。
19
+ API Key 格式为字母、数字、减号、下划线的组合,长度在 8 到 128 之间
20
+ :param api_key: 待校验的 API Key 字符串
21
+ :return: 如果格式有效返回 True,否则返回 False
22
+ """
23
+ pattern = r"^[A-Za-z0-9+/=-]{8,128}$"
24
+ return bool(re.match(pattern, api_key))
25
+
26
+
27
+ class ConfigManager:
28
+ def __init__(self, default_config="default.toml", user_config="aipy.toml"):
29
+ self.default_config = default_config
30
+ self.user_config = user_config
31
+ self.config = self._load_config()
32
+
33
+ def _load_config(self):
34
+ try:
35
+ settings_files = [self.default_config] + SETTINGS_FILES[:-1] + [Path(self.user_config).resolve()]
36
+
37
+ config = Dynaconf(
38
+ settings_files=settings_files,
39
+ envvar_prefix="AIPY", merge_enabled=True
40
+ )
41
+ except Exception as e:
42
+ print(T('error_loading_config').format(e))
43
+ config = None
44
+ return config
45
+
46
+ def get_config(self):
47
+ return self.config
48
+
49
+ def check_config(self):
50
+ if not self.config:
51
+ print(T('config_file_error'))
52
+ return
53
+
54
+ self.check_llm()
55
+
56
+ def check_llm(self):
57
+ if not self.config:
58
+ print(T('config_not_loaded'))
59
+ return
60
+
61
+ llm = self.config.get("llm")
62
+ if not llm:
63
+ print(T('llm_config_not_found'))
64
+
65
+ llms = {}
66
+ for name, config in self.config.get('llm', {}).items():
67
+ if config.get("enable", True):
68
+ llms[name] = config
69
+
70
+ if not llms:
71
+ self._init_llm()
72
+
73
+ def _init_llm(self):
74
+ print(T('pgpttoken_register_instruction').format(self.user_config))
75
+
76
+ while True:
77
+ user_token = input(T('prompt_token_input')).strip()
78
+ if user_token.lower() == "exit":
79
+ print(T('exit_token_prompt'))
80
+ sys.exit(0)
81
+ if not user_token:
82
+ print(T('no_token_detected'))
83
+ continue
84
+ if not is_valid_api_key(user_token):
85
+ print(T('invalid_token'))
86
+ continue
87
+
88
+ self.save_trustoken(user_token)
89
+
90
+ self.config = self._load_config()
91
+ break
92
+
93
+ def save_trustoken(self, token):
94
+ config_file = self.user_config
95
+ try:
96
+ with open(config_file, "a") as f:
97
+ f.write("\n[llm.pgpt]\n")
98
+ f.write(f'api_key = "{token}"\n')
99
+ f.write('base_url = "https://openai.pgpt.cloud/v1/"\n')
100
+ f.write('model = "auto"\n')
101
+ f.write("default = true\n")
102
+ f.write("enable = true\n")
103
+ print(T('token_saved').format(config_file))
104
+ except Exception as e:
105
+ print(T('token_save_error').format(e))
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import locale
5
+
6
+ MESSAGES = {
7
+ 'zh': {
8
+ 'start_instruction': '开始处理指令',
9
+ 'start_execute': '开始执行代码块',
10
+ 'execute_result': '执行结果',
11
+ 'start_feedback': '开始反馈结果',
12
+ 'end_instruction': '结束处理指令',
13
+ 'no_context': '未找到上下文信息',
14
+ 'upload_success': '文章上传成功',
15
+ 'upload_failed': '上传失败 (状态码: {})',
16
+ 'reset_warning': '严重警告:这将重新初始化❗❗❗',
17
+ 'reset_confirm': '如果你确定要继续,请输入 y',
18
+ 'llm_response': '响应',
19
+ 'env_description': '环境变量名称和意义',
20
+ 'description': '描述',
21
+ 'unknown_format': '不支持的文件格式',
22
+ 'ask_for_packages': '申请安装第三方包',
23
+ 'agree_packages': '如果同意,请输入',
24
+ 'ask_for_env': '申请获取环境变量 {},用途',
25
+ 'env_exist': '环境变量 {} 存在,返回给代码使用',
26
+ 'input_env': '未找到环境变量 {},请输入',
27
+ 'call_failed': '调用失败',
28
+ 'think': '思考',
29
+ 'publish_disabled': "当前环境不支持发布",
30
+ 'auto_confirm': '自动确认',
31
+ 'packages_exist': '申请的第三方包已经安装',
32
+ 'thinking': '正在绞尽脑汁思考中,请稍等6-60秒',
33
+ 'no_available_llm': '没有可用的 LLM,请检查配置文件',
34
+ 'banner1_python': "请用 ai('任务') 输入需要 AI 处理的任务 (输入 ai.use(llm) 切换下述 LLM:",
35
+ 'banner1': "请输入需要 AI 处理的任务 (输入 /use <下述 LLM> 切换)",
36
+ 'default': '默认',
37
+ 'enabled': '已启用',
38
+ 'ai_mode_enter': '进入 AI 模式,开始处理任务,输入 Ctrl+d 或 /done 结束任务',
39
+ 'ai_mode_exit': "[退出 AI 模式]",
40
+ 'ai_mode_unknown_command': "[AI 模式] 未知命令",
41
+ 'Task Summary': '任务总结',
42
+ 'Round': '轮次',
43
+ 'Time(s)': '时间(秒)',
44
+ 'In Tokens': '输入令牌数',
45
+ 'Out Tokens': '输出令牌数',
46
+ 'Total Tokens': '总令牌数',
47
+ 'sending_task': '正在向 {} 下达任务',
48
+ 'error_loading_config': "加载配置时出错: {}",
49
+ 'config_file_error': "请检查配置文件路径和格式。",
50
+ 'config_not_loaded': "配置尚未加载。",
51
+ 'llm_config_not_found': "缺少 'llm' 配置。",
52
+ 'trustoken_register_instruction': (
53
+ "当前环境缺少配置文件,请注册一个trustoken账号,可以使用免费赠送的API账号。\n"
54
+ "浏览器打开 https://api.trustoken.ai/register , 进行账号注册。\n"
55
+ "注册后进行登录,访问页面顶部的“令牌”页面,或者点击这个地址:https://api.trustoken.ai/token \n"
56
+ "点击“复制”按钮,复制令牌到剪贴板。在下面进行粘贴。\n"
57
+ "另外,也可以选择退出,然后手动编辑配置文件 {},配置自己已有的其他大模型令牌"
58
+ ),
59
+ 'pgpttoken_register_instruction': (
60
+ "当前环境缺少配置文件,需要注册PGPT账号获取试用Token。\n"
61
+ "请按以下步骤操作:\n"
62
+ "1. 访问 https://user.pgpt.cloud/ 完成账号注册\n"
63
+ "2. 登录后创建App(选择Deepseek或者OpenAI)。操作详见文档 https://docs.pgpt.cloud/\n"
64
+ "3. 获取API Key并复制到剪贴板,然后在此粘贴\n"
65
+ "您也可以选择退出,然后手动编辑配置文件 {} 来配置已有的其他大模型Token"
66
+ ),
67
+ 'prompt_token_input': "请粘贴令牌并按 Enter 键 (输入 'exit' 退出): ",
68
+ 'exit_token_prompt': "退出令牌输入流程。",
69
+ 'no_token_detected': "未检测到令牌输入。",
70
+ 'invalid_token': "输入的令牌不合法,请确保令牌正确,格式为‘sk-xxxxxx……’,或输入 'exit' 退出。",
71
+ 'token_saved': "令牌已保存到 {}",
72
+ 'token_save_error': "保存令牌时出错: {}",
73
+ 'not usable': "不可用",
74
+ 'permission_denied_error': "无权限创建目录: {}",
75
+ 'error_creating_config_dir': "创建配置目录时出错: {}",
76
+ 'migrate_config': "成功的将旧版本配置迁移到 {}",
77
+ 'binding_request_sent': "绑定请求发送成功。\n请求ID: {}\n\n>>> 请在已认证设备的浏览器中打开以下链接以批准:\n>>> {}\n\n(该链接将在{}秒后过期)",
78
+ 'scan_qr_code': "或者扫描下方二维码:",
79
+ 'qr_code_display_failed': "(无法显示二维码: {})\n",
80
+ 'coordinator_request_error': "连接到协调服务器或请求时出错: {}",
81
+ 'unexpected_request_error': "请求过程中发生意外错误: {}",
82
+ 'waiting_for_approval': "等待批准...",
83
+ 'current_status': "当前状态: {}...",
84
+ 'binding_expired': "\n绑定请求已过期。",
85
+ 'unknown_status': "\n收到未知状态: {}",
86
+ 'coordinator_polling_error': "轮询协调服务器时出错: {}",
87
+ 'unexpected_polling_error': "轮询过程中发生意外错误: {}",
88
+ 'polling_cancelled': "\n用户取消了轮询。",
89
+ 'polling_timeout': "\n轮询超时。",
90
+ 'start_binding_process': "当前环境缺少必需的配置文件,开始进行配置初始化流程,与trustoken账号绑定即可自动获取配置...",
91
+ 'binding_success': "\n绑定流程已成功完成。",
92
+ 'binding_failed': "\n绑定流程失败或未完成。",
93
+ 'binding_request_failed': "\n绑定请求发起失败。",
94
+ 'The operation completed successfully': "操作成功完成",
95
+ 'Execution was interrupted by the user': "操作被用户中断",
96
+ 'Initial mission': "最初任务",
97
+ 'Code execution result feedback': "代码执行结果反馈",
98
+ },
99
+ 'en': {
100
+ 'start_instruction': 'Start processing instruction',
101
+ 'start_execute': 'Start executing code block',
102
+ 'execute_result': 'Execution result',
103
+ 'start_feedback': 'Start sending feedback',
104
+ 'end_instruction': 'End processing instruction',
105
+ 'no_context': 'No context information found',
106
+ 'upload_success': 'Article uploaded successfully',
107
+ 'upload_failed': 'Upload failed (status code: {})',
108
+ 'reset_warning': 'Severe warning: This will reinitialize❗❗❗',
109
+ 'reset_confirm': 'If you are sure to continue, enter y',
110
+ 'llm_response': 'reply',
111
+ 'env_description': 'Environment variable name and meaning',
112
+ 'description': 'Description',
113
+ 'unknown_format': 'Unsupported file format',
114
+ 'ask_for_packages': 'Request to install third-party packages',
115
+ 'agree_packages': 'If you agree, please enter',
116
+ 'ask_for_env': 'Request to obtain environment variable {}, purpose',
117
+ 'env_exist': 'Environment variable {} exists, returned for code use',
118
+ 'input_env': 'Environment variable {} not found, please enter',
119
+ 'call_failed': 'Call failed',
120
+ 'think': 'Think',
121
+ 'publish_disabled': "Current environment does not support publishing",
122
+ 'auto_confirm': 'Auto confirm',
123
+ 'packages_exist': 'Third-party packages have been installed',
124
+ 'thinking': 'is thinking hard, please wait 6-60 seconds',
125
+ 'no_available_llm': 'No available LLM, please check the configuration file',
126
+ 'banner1_python': "Please use ai('task') to enter the task to be processed by AI (enter ai.use(llm) to switch to the following LLM:",
127
+ 'banner1': "Please enter the task to be processed by AI (enter /use <following LLM> to switch)",
128
+ 'default': 'Default',
129
+ 'enabled': 'Enabled',
130
+ 'ai_mode_enter': 'Enter AI mode, start processing tasks, enter Ctrl+d or /done to end the task',
131
+ 'ai_mode_exit': "[Exit AI mode]",
132
+ 'ai_mode_unknown_command': "[AI mode] Unknown command",
133
+ 'Task Summary': 'Task Summary',
134
+ 'Round': 'Round',
135
+ 'Time(s)': 'Time(s)',
136
+ 'In Tokens': 'In Tokens',
137
+ 'Out Tokens': 'Out Tokens',
138
+ 'Total Tokens': 'Total Tokens',
139
+ 'sending_task': 'Sending task to {}',
140
+ 'error_loading_config': "Error loading configuration: {}",
141
+ 'config_file_error': "Please check the configuration file path and format.",
142
+ 'config_not_loaded': "Configuration not loaded.",
143
+ 'llm_config_not_found': "Missing 'llm' configuration.",
144
+ 'trustoken_register_instruction': (
145
+ "The current environment lacks a configuration file. Please register for a Trustoken account to use the free API token.\n"
146
+ "Open https://api.trustoken.ai/register to register.\n"
147
+ "After registration, log in and visit the 'Token' page at the top, or navigate to: https://api.trustoken.ai/token\n"
148
+ "Click the 'copy' button to copy your token to the clipboard and paste it here.\n"
149
+ "Alternatively, you can exit now, and manually edit the configuration file {} to configure your existing LLM token."
150
+ ),
151
+ 'pgpttoken_register_instruction': (
152
+ "The current environment is missing configuration files. You need to register a PGPT account to get trial tokens.\n"
153
+ "Please follow these steps:\n"
154
+ "1. Visit https://user.pgpt.cloud/ to complete account registration\n"
155
+ "2. After logging in, create an App (please select Deepseek or OpenAI). See documentation: https://docs.pgpt.cloud/\n"
156
+ "3. Get your API Key, copy it to clipboard, then paste it here\n"
157
+ "Alternatively, you can exit and manually edit the configuration file {} to set up tokens for other existing LLM models"
158
+ ),
159
+ 'prompt_token_input': "Please paste the token and press Enter (type 'exit' to quit): ",
160
+ 'exit_token_prompt': "Exiting token input process.",
161
+ 'no_token_detected': "No token detected.",
162
+ 'invalid_token': "The entered token is invalid. Ensure it starts with 'sk-' followed by the correct characters, or type 'exit' to quit.",
163
+ 'token_saved': "Token saved to {}",
164
+ 'token_save_error': "Error saving token: {}",
165
+ 'not usable': "Not usable",
166
+ 'permission_denied_error': "Permission denied to create directory: {}",
167
+ 'error_creating_config_dir': "Error creating configuration directory: {}",
168
+ 'migrate_config': "Successfully migrated old version configuration to {}",
169
+ 'binding_request_sent': "Binding request sent successfully.\nRequest ID: {}\n\n>>> Please open this URL in your browser on an authenticated device to approve:\n>>> {}\n\n(This link expires in {} seconds)",
170
+ 'scan_qr_code': "Or scan the QR code below:",
171
+ 'qr_code_display_failed': "(Could not display QR code: {})\n",
172
+ 'coordinator_request_error': "Error connecting to coordinator or during request: {}",
173
+ 'unexpected_request_error': "An unexpected error occurred during request: {}",
174
+ 'waiting_for_approval': "Waiting for approval...",
175
+ 'current_status': "Current status: {}...",
176
+ 'binding_expired': "\nBinding request expired.",
177
+ 'unknown_status': "\nUnknown status received: {}",
178
+ 'coordinator_polling_error': "Error connecting to coordinator during polling: {}",
179
+ 'unexpected_polling_error': "An unexpected error occurred during polling: {}",
180
+ 'polling_cancelled': "\nPolling cancelled by user.",
181
+ 'polling_timeout': "\nPolling timed out.",
182
+ 'start_binding_process': "The current environment lacks the required configuration file. Starting the configuration initialization process to bind with the Trustoken account...",
183
+ 'binding_success': "\nBinding process completed successfully.",
184
+ 'binding_failed': "\nBinding process failed or was not completed.",
185
+ 'binding_request_failed': "\nFailed to initiate binding request.",
186
+ 'The operation completed successfully': "The operation completed successfully",
187
+ 'Execution was interrupted by the user': "Execution was interrupted by the user",
188
+ 'Initial mission': "Initial mission",
189
+ 'Code execution result feedback': "Code execution result feedback",
190
+
191
+ }
192
+ }
193
+
194
+ __lang__ = 'en'
195
+
196
+ def set_lang(lang=None):
197
+ global __lang__, MESSAGES
198
+ if lang and lang in MESSAGES:
199
+ __lang__ = lang
200
+ return
201
+
202
+ language, _ = locale.getlocale()
203
+ if language:
204
+ language = language.lower()
205
+ if language.find('china') >=0 or language.find('chinese') >= 0 or language.find('zh_') >= 0:
206
+ __lang__ = 'zh'
207
+
208
+ def T(key, *args):
209
+ msg = MESSAGES[__lang__][key]
210
+ return msg.format(*args) if args else msg
211
+
212
+ set_lang()
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from abc import ABC, abstractmethod
5
+
6
+ class Runtime(ABC):
7
+ @abstractmethod
8
+ def install_packages(self, packages):
9
+ pass
10
+
11
+ @abstractmethod
12
+ def getenv(self, name, desc=None):
13
+ pass
14
+
15
+ class ConsoleInterface(ABC):
16
+ @abstractmethod
17
+ def print(self, *args, sep=' ', end='\n', file=None, flush=False):
18
+ pass
19
+
20
+ @abstractmethod
21
+ def input(self, prompt=''):
22
+ pass
23
+
24
+ @abstractmethod
25
+ def status(self, msg):
26
+ pass