guarantee-based-coding 0.2.0__py3-none-any.whl

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 (48) hide show
  1. gbc/__init__.py +21 -0
  2. gbc/app/__init__.py +14 -0
  3. gbc/app/assets.py +38 -0
  4. gbc/app/config/__init__.py +14 -0
  5. gbc/app/config/backups.py +28 -0
  6. gbc/app/config/base.py +29 -0
  7. gbc/app/config/executor.py +132 -0
  8. gbc/app/config/project.py +35 -0
  9. gbc/app/core/__init__.py +14 -0
  10. gbc/app/core/env.py +64 -0
  11. gbc/app/core/executor.py +116 -0
  12. gbc/app/core/guarantee.py +338 -0
  13. gbc/app/i18n/__init__.py +43 -0
  14. gbc/app/i18n/lang.py +88 -0
  15. gbc/app/i18n/translate.py +80 -0
  16. gbc/app/intent/__init__.py +20 -0
  17. gbc/app/intent/base.py +308 -0
  18. gbc/app/intent/cli.py +124 -0
  19. gbc/app/intent/editor.py +93 -0
  20. gbc/app/interface/__init__.py +14 -0
  21. gbc/app/interface/base.py +851 -0
  22. gbc/app/interface/cli.py +585 -0
  23. gbc/app/interface/mcp.py +616 -0
  24. gbc/app/models/__init__.py +14 -0
  25. gbc/app/models/errors.py +179 -0
  26. gbc/app/models/meta.py +92 -0
  27. gbc/app/models/verify.py +63 -0
  28. gbc/app/utils/__init__.py +14 -0
  29. gbc/app/utils/file_utils.py +24 -0
  30. gbc/app/utils/gbc_md.py +121 -0
  31. gbc/app/utils/json_model_operator.py +85 -0
  32. gbc/app/utils/safe_file_writer.py +158 -0
  33. gbc/assets/editor/index.html +299 -0
  34. gbc/assets/i18n/catalog/en.json +52 -0
  35. gbc/assets/i18n/catalog/zh.json +52 -0
  36. gbc/assets/i18n/texts/rules.en.md +30 -0
  37. gbc/assets/i18n/texts/rules.zh.md +24 -0
  38. gbc/assets/i18n/texts/setup.en.md +74 -0
  39. gbc/assets/i18n/texts/setup.zh.md +69 -0
  40. gbc/assets/skills/README.md +16 -0
  41. gbc/assets/skills/gbc-cli/SKILL.md +143 -0
  42. gbc/entry.py +126 -0
  43. guarantee_based_coding-0.2.0.dist-info/METADATA +108 -0
  44. guarantee_based_coding-0.2.0.dist-info/RECORD +48 -0
  45. guarantee_based_coding-0.2.0.dist-info/WHEEL +5 -0
  46. guarantee_based_coding-0.2.0.dist-info/entry_points.txt +2 -0
  47. guarantee_based_coding-0.2.0.dist-info/licenses/LICENSE +202 -0
  48. guarantee_based_coding-0.2.0.dist-info/top_level.txt +1 -0
gbc/__init__.py ADDED
@@ -0,0 +1,21 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """GBC — Guarantee-Based Coding.
16
+
17
+ 让代码在不被完全理解的情况下也能被安全修改:把模块间依赖从隐含变成
18
+ 显式、可执行、可验证的保证。本包是该方法的实现,也是它的第一个使用者。
19
+ """
20
+
21
+ __version__ = "0.2.0"
gbc/app/__init__.py ADDED
@@ -0,0 +1,14 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
gbc/app/assets.py ADDED
@@ -0,0 +1,38 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """静态资源定位的单一入口。
16
+
17
+ 所有随包分发的**数据**(i18n catalog/texts、editor 前端)集中在 `gbc/assets/`
18
+ 下,与**代码**彻底分离。任何模块要读资源都从这里取路径,不各自
19
+ `Path(__file__).parent` ——加一类资源只需在此登记一处 + 打包声明一条。
20
+
21
+ 打包:`pyproject.toml` 的 `[tool.setuptools.package-data]` 以 `"gbc" = ["assets/**"]`
22
+ 把整个 assets 树纳入 wheel(散在各子包时易漏声明,这正是集中的理由)。
23
+ """
24
+ from pathlib import Path
25
+
26
+ # assets 根:本文件在 gbc/app/assets.py,上溯到 gbc/ 再进 assets/。
27
+ ASSETS_DIR = Path(__file__).resolve().parent.parent / "assets"
28
+
29
+ # i18n 短消息查表 与 长文本资源。
30
+ I18N_CATALOG_DIR = ASSETS_DIR / "i18n" / "catalog"
31
+ I18N_TEXTS_DIR = ASSETS_DIR / "i18n" / "texts"
32
+
33
+ # 意图编辑器 web 前端静态页。
34
+ EDITOR_FRONTEND_DIR = ASSETS_DIR / "editor"
35
+
36
+ # 给 CLI-only agent 的预组 skills(教 agent 怎么调 gbc 子命令,等价于 MCP 工具描述)。
37
+ # gbc setup 只告知此目录坐标,由用户自行放到其 agent 读 skill 的位置。
38
+ SKILLS_DIR = ASSETS_DIR / "skills"
@@ -0,0 +1,14 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
@@ -0,0 +1,28 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import os
16
+ from pathlib import Path
17
+
18
+ from gbc.app.config.base import PROJECT_ROOT
19
+
20
+ # 初始化备份数量
21
+ def _init_meta_backups() -> int:
22
+ var = os.environ.get("GBC_META_BACKUPS", None)
23
+ if var and var.isdigit():
24
+ return int(var)
25
+
26
+ return 0
27
+
28
+ META_BACKUPS = _init_meta_backups()
gbc/app/config/base.py ADDED
@@ -0,0 +1,29 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import os
16
+ from pathlib import Path
17
+
18
+
19
+ def get_project_root() -> Path:
20
+ """获取工具仓根目录。
21
+
22
+ 注意:文件已迁入 `gbc/app/config/base.py`,比旧布局(`app/config/base.py`)多一层
23
+ `gbc/`,故上溯四层(base.py -> config -> app -> gbc -> 仓根)。
24
+ """
25
+ return Path(__file__).resolve().parent.parent.parent.parent
26
+
27
+
28
+ PROJECT_ROOT = get_project_root()
29
+ CONFIG_DIR = PROJECT_ROOT / "config"
@@ -0,0 +1,132 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from pathlib import Path
16
+ from typing import Literal
17
+
18
+ from pydantic import BaseModel, ValidationError
19
+
20
+ from gbc.app.config.project import get_current_project
21
+ from gbc.app.utils.json_model_operator import load_model_from_json, save_model_to_json
22
+
23
+
24
+ # ---- 落盘位置 --------------------------------------------------------------
25
+ # executor 配置是**每台机器都不同**的可变状态(解释器路径、项目路径),因此:
26
+ # - 落在**目标项目**的 `.gbc/` 下(而非工具仓),让工具仓保持只读、可 pip 安装;
27
+ # - 私有真配置 `executors.json` 应进 gitignore;
28
+ # - 可提交的清单 `executors.example.json` 脱敏(只留名字 + 结构骨架),供协作者
29
+ # 知道"本项目需要配哪些 executor",而绝不泄露任何机器相关值或密钥。
30
+ EXECUTORS_FILENAME = "executors.json"
31
+ EXECUTORS_EXAMPLE_FILENAME = "executors.example.json"
32
+
33
+
34
+ def executors_config_path() -> Path:
35
+ """当前目标项目的私有 executor 配置路径。随 `get_current_project()` 走。"""
36
+ return get_current_project() / ".gbc" / EXECUTORS_FILENAME
37
+
38
+
39
+ def executors_example_path() -> Path:
40
+ """当前目标项目的脱敏 executor 清单路径(可提交进 git)。"""
41
+ return get_current_project() / ".gbc" / EXECUTORS_EXAMPLE_FILENAME
42
+
43
+
44
+ class EnvAction(BaseModel):
45
+ # key: 环境变量名
46
+ key: str
47
+ # action: 支持 set (覆盖), append (后补), prepend (前缀), remove (删除)
48
+ action: Literal["set", "append", "prepend", "remove"]
49
+ # value: 操作的值 (remove 时可为 None)
50
+ value: str | None = None
51
+
52
+
53
+ # 单个执行器
54
+ class ExecutorModel(BaseModel):
55
+ command: list[str]
56
+ cwd: str
57
+ timeout: int = -1
58
+ env_ops: None | list[EnvAction] = None
59
+ # 人类可读说明:example 清单里唯一保留的"内容",由登记方**显式撰写**,
60
+ # 用来告诉协作者这个 executor 是什么、该怎么填。绝不从 command 自动推导(可能含密钥)。
61
+ comment: str | None = None
62
+
63
+
64
+ # 执行器配置
65
+ class ExecutorsConfig(BaseModel):
66
+ executors: dict[str, ExecutorModel]
67
+
68
+
69
+ # ---- 惰性单例 --------------------------------------------------------------
70
+ # 关键:**不在 import 时读盘**。import 时项目根往往还没经 argv/set_current_project
71
+ # 设定好(MCP server 场景),此刻读盘只会命中错误位置。改为首次访问时按当前项目定位。
72
+ _cache: ExecutorsConfig | None = None
73
+ _cache_path: Path | None = None
74
+
75
+
76
+ def _load(path: Path) -> ExecutorsConfig:
77
+ try:
78
+ return load_model_from_json(path, ExecutorsConfig)
79
+ except FileNotFoundError:
80
+ return ExecutorsConfig(executors={})
81
+ except (ValueError, ValidationError):
82
+ return ExecutorsConfig(executors={})
83
+
84
+
85
+ def get_executors_config() -> ExecutorsConfig:
86
+ """惰性获取当前项目的 executor 配置单例。
87
+
88
+ 随目标项目变化自动重载:当 `get_current_project()` 指向的项目变了(缓存路径
89
+ 与当前路径不一致),重新按新路径加载——保证一个进程内切换项目时不串配置。
90
+ """
91
+ global _cache, _cache_path
92
+ path = executors_config_path()
93
+ if _cache is None or _cache_path != path:
94
+ _cache = _load(path)
95
+ _cache_path = path
96
+ return _cache
97
+
98
+
99
+ def _to_example(config: ExecutorsConfig) -> dict:
100
+ """把真配置脱敏成可提交的清单。
101
+
102
+ 约定(已拍板):**全删机器相关字段**——只留 executor 名字(作 key)与显式
103
+ `comment`。command/cwd/timeout/env_ops 一律**不出现**(不是置空、而是缺失),
104
+ 因为无注释的空占位 ≈ 字段缺失,那就选更简单的「缺失」;缺失不静默——
105
+ Pydantic 必填校验与 `gbc doctor` 会替它嗊出「你需要配 X」。绝不拷任何原始值。
106
+ """
107
+ executors: dict[str, dict] = {}
108
+ for name, model in config.executors.items():
109
+ entry: dict = {}
110
+ if model.comment is not None:
111
+ entry["comment"] = model.comment
112
+ executors[name] = entry
113
+ return {"executors": executors}
114
+
115
+
116
+ def save_executors_config() -> None:
117
+ """保存当前项目的 executor 配置,并同步重算脱敏清单 example。
118
+
119
+ 二者始终一起写,避免 example 腐烂。example 是宽松 dict(非 ExecutorModel),
120
+ 因为它故意缺字段。
121
+ """
122
+ import json
123
+
124
+ config = get_executors_config()
125
+ save_model_to_json(config, executors_config_path(), num_backups=0)
126
+
127
+ example_path = executors_example_path()
128
+ example_path.parent.mkdir(parents=True, exist_ok=True)
129
+ example_path.write_text(
130
+ json.dumps(_to_example(config), ensure_ascii=False, indent=4),
131
+ encoding="utf-8",
132
+ )
@@ -0,0 +1,35 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from pathlib import Path
16
+
17
+
18
+ # 初始化当前路径:进程启动时的 cwd。CLI 单次命令默认就用这个——“当前项目 = 跑命令时所在目录”,
19
+ # 无需环境变量,不会静默回退到包安装位置。常驻服务(mcp up / editor up)cwd 不可靠,
20
+ # 它们自己收显式参数覆盖,不依赖这个默认值。
21
+ def _init_current_project() -> Path:
22
+ return Path.cwd()
23
+
24
+ # 会被使用的当前路径变量
25
+ CURRENT_PROJECT = _init_current_project()
26
+
27
+ # 更新当前路径
28
+ def set_current_project(new_path: str):
29
+ new_path = Path(new_path)
30
+
31
+ global CURRENT_PROJECT
32
+ CURRENT_PROJECT = new_path
33
+
34
+ def get_current_project():
35
+ return CURRENT_PROJECT
@@ -0,0 +1,14 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
gbc/app/core/env.py ADDED
@@ -0,0 +1,64 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import os
16
+
17
+ from gbc.app.config.executor import EnvAction
18
+
19
+
20
+ def get_clean_python_path():
21
+ env = os.environ.copy()
22
+ pp_list = env.get("PYTHONPATH", "").split(os.pathsep)
23
+ pp_list = pp_list[1:]
24
+ env["PYTHONPATH"] = os.pathsep.join(pp_list)
25
+
26
+ return env
27
+
28
+
29
+ def apply_env_action(env: dict[str, str], op: EnvAction, sep: str = os.pathsep) -> dict[str, str]:
30
+ """
31
+ 对传入的 env 字典执行单个 EnvAction 操作。
32
+ 注:为了安全,建议传入 env.copy() 以避免副作用。
33
+ """
34
+
35
+ key = op.key
36
+ val = op.value or ""
37
+
38
+ match op.action:
39
+ case "set":
40
+ env[key] = val
41
+
42
+ case "remove":
43
+ env.pop(key, None)
44
+
45
+ case "append":
46
+ current = env.get(key, "")
47
+ # 如果当前有值,则用分隔符连接;否则直接设为 val
48
+ env[key] = f"{current}{sep}{val}" if current else val
49
+
50
+ case "prepend":
51
+ current = env.get(key, "")
52
+ # 如果当前有值,则用分隔符连接;否则直接设为 val
53
+ env[key] = f"{val}{sep}{current}" if current else val
54
+
55
+ return env
56
+
57
+ def apply_env_actions(env: dict[str, str], ops: None | list[EnvAction], sep: str = os.pathsep) -> dict[str, str]:
58
+ if not ops:
59
+ return env
60
+
61
+ for op in ops:
62
+ apply_env_action(env, op, sep)
63
+
64
+ return env
@@ -0,0 +1,116 @@
1
+ # Copyright 2026 Jesse-x86
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import subprocess
16
+
17
+ from gbc.app.config.executor import get_executors_config, ExecutorModel, save_executors_config
18
+ from gbc.app.core.env import apply_env_actions, get_clean_python_path
19
+ from gbc.app.models.errors import ExecutorNotFoundError
20
+ from gbc.app.models.verify import VerifyModel
21
+
22
+ FILE_PLACEHOLDERS = ["{file}", "{f}"]
23
+ DEFAULT_TIMEOUT = 15
24
+
25
+ def has_exec_config(config: str) -> bool:
26
+ """
27
+ 是否存在该 config
28
+ :param config:
29
+ :return:
30
+ """
31
+ return config in get_executors_config().executors
32
+
33
+ def _execute(config: str, file: str, timeout: int = -1) -> subprocess.CompletedProcess[str]:
34
+ """
35
+ 使用特定配置文件,执行单个测试
36
+ :param config:
37
+ :param file:
38
+ :param timeout:
39
+ :return:
40
+ """
41
+ if not has_exec_config(config):
42
+ raise ExecutorNotFoundError(config)
43
+
44
+ executor_cfg = get_executors_config().executors[config]
45
+
46
+ args = executor_cfg.command.copy()
47
+ args = [arg.replace("{file}", file).replace("{f}", file) for arg in args]
48
+
49
+ env = apply_env_actions(get_clean_python_path(), executor_cfg.env_ops)
50
+
51
+ if timeout < 0:
52
+ timeout = executor_cfg.timeout
53
+
54
+ if timeout < 0:
55
+ timeout = DEFAULT_TIMEOUT
56
+
57
+ result = subprocess.run(
58
+ args=args,
59
+ capture_output=True,
60
+ text=True,
61
+ timeout=timeout,
62
+ cwd=executor_cfg.cwd,
63
+ env=env,
64
+ # 绝不让被测进程继承父进程的 stdin。作为 MCP server 运行时父进程 stdin 是
65
+ # JSON-RPC 协议管道,子进程继承后会阻塞("终端能跑、当服务挂"的经典坑)。
66
+ stdin=subprocess.DEVNULL,
67
+ )
68
+
69
+ return result
70
+
71
+ def verify_single(config: str, file: str, *, timeout: int = -1, return_model: bool = True) -> bool | VerifyModel:
72
+ """
73
+ 验证单个测试
74
+ :param config:
75
+ :param file:
76
+ :param timeout:
77
+ :param return_model:
78
+ :return:
79
+ """
80
+ result = _execute(config, file, timeout)
81
+
82
+ if not return_model:
83
+ return result.returncode == 0
84
+
85
+ return VerifyModel(
86
+ return_code=result.returncode,
87
+ stdout=result.stdout,
88
+ stderr=result.stderr
89
+ )
90
+
91
+ def upsert_exec_config(config_name: str, model: ExecutorModel):
92
+ """
93
+ 插入或更新执行器配置
94
+ :param config_name:
95
+ :param model:
96
+ :return:
97
+ """
98
+ get_executors_config().executors[config_name] = model
99
+ save_executors_config()
100
+
101
+ def remove_exec_config(config_name: str):
102
+ """
103
+ 删除执行器配置
104
+ :param config_name:
105
+ :return:
106
+ """
107
+ if has_exec_config(config_name):
108
+ del get_executors_config().executors[config_name]
109
+ save_executors_config()
110
+
111
+ def get_all_exec_configs():
112
+ """
113
+ 获取全部执行器配置
114
+ :return:
115
+ """
116
+ return get_executors_config().copy()