ion-CSP 2.1.2__tar.gz → 2.1.3__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.
- {ion_csp-2.1.2 → ion_csp-2.1.3}/.github/workflows/pypi-publish.yml +1 -1
- {ion_csp-2.1.2 → ion_csp-2.1.3}/PKG-INFO +5 -1
- {ion_csp-2.1.2 → ion_csp-2.1.3}/README.md +4 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/__init__.py +2 -2
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/log_and_time.py +10 -4
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/task_manager.py +2 -2
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP.egg-info/PKG-INFO +5 -1
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP.egg-info/SOURCES.txt +1 -1
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/run/main_CSP.py +1 -2
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/run/main_EE.py +1 -1
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/run/run_convert_SMILES.py +1 -2
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/run/run_empirical_estimate.py +1 -2
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/run/run_gen_opt.py +1 -2
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/run/run_read_mlp_density.py +1 -2
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/run/run_upload_download.py +1 -3
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/run/run_vasp_processing.py +1 -2
- ion_csp-2.1.3/tests/test_log_and_time.py +123 -0
- ion_csp-2.1.2/.github/workflows/bump-version.yml +0 -28
- {ion_csp-2.1.2 → ion_csp-2.1.3}/.dockerignore +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/.github/workflows/conda-env-build.yml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/.gitignore +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/.vscode/settings.json +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/CHANGELOG.md +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/CODE_OF_CONDUCT.md +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/CONTRIBUTING.md +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/Dockerfile +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/LICENSE +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/MANIFEST.in +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/SECURITY.md +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/config/complete_config.yaml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/config/simple_config.yaml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/config/usage.md +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/docs/example_usage_CSP.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/docs/example_usage_EE.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/docs/index.md +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/docs/usage.md +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/environment.yml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/examples/example_1/config.yaml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/examples/example_1/ions.csv +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/examples/example_usage.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/examples/server/example_local_machine.yaml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/examples/server/example_local_resources.yaml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/examples/server/example_remote_machine.yaml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/examples/server/example_remote_resources.yaml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/makefile +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/model/model.pt +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/model/options/README.md +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/model/options/model.ckpt-4000000.pt +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/INCAR_0 +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/INCAR_1 +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/INCAR_2 +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/INCAR_3 +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/POTCAR_C +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/POTCAR_H +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/POTCAR_N +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/POTCAR_O +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/g16_sub.sh +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/sub_final.sh +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/sub_ori.sh +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/param/sub_supple.sh +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/pyproject.toml +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/requirements.txt +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/scripts/CLI.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/scripts/CLI.sh +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/scripts/main_CSP.sh +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/scripts/main_EE.sh +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/setup.cfg +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/setup.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/__init__.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/__main__.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/convert_SMILES.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/empirical_estimate.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/gen_opt.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/identify_molecules.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/mlp_opt.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/read_mlp_density.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/steps_opt_monitor.sh +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/upload_download.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP/vasp_processing.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP.egg-info/dependency_links.txt +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP.egg-info/entry_points.txt +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP.egg-info/requires.txt +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/ion_CSP.egg-info/top_level.txt +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/src/run/__init__.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/tests/__init__.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/tests/test1_task_manager1.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/tests/test_task_manager.py +0 -0
- {ion_csp-2.1.2 → ion_csp-2.1.3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ion_CSP
|
3
|
-
Version: 2.1.
|
3
|
+
Version: 2.1.3
|
4
4
|
Summary: Crystal Structure Design Software Based on Molecular/Ionic Configuration.
|
5
5
|
Home-page: https://github.com/bagabaga007/ion_CSP
|
6
6
|
Author: Ze Yang
|
@@ -71,6 +71,10 @@ Dynamic: requires-python
|
|
71
71
|
|
72
72
|
### 安装步骤
|
73
73
|
```bash
|
74
|
+
pip install ion-csp
|
75
|
+
```
|
76
|
+
或
|
77
|
+
```bash
|
74
78
|
# 创建虚拟环境
|
75
79
|
python -m venv venv
|
76
80
|
source venv/bin/activate # Linux/Mac
|
@@ -3,17 +3,24 @@ import sys
|
|
3
3
|
import time
|
4
4
|
import yaml
|
5
5
|
import signal
|
6
|
+
import inspect
|
6
7
|
import logging
|
7
8
|
import argparse
|
9
|
+
import functools
|
8
10
|
from dpdispatcher.dlog import dlog
|
9
11
|
|
10
12
|
|
11
13
|
def log_and_time(func):
|
12
14
|
"""Decorator for recording log information and script runtime"""
|
13
|
-
|
14
|
-
def wrapper(
|
15
|
+
@functools.wraps(func)
|
16
|
+
def wrapper(work_dir, *args, **kwargs):
|
17
|
+
# 使用inspect获取真实脚本文件名
|
18
|
+
module = inspect.getmodule(func)
|
19
|
+
script_path = module.__file__ if module else __file__
|
20
|
+
script_name = os.path.splitext(os.path.basename(script_path))[0]
|
15
21
|
# 获取脚本所在目录, 在该目录下生成日志
|
16
22
|
log_file_path = os.path.join(work_dir, f"{script_name}_output.log")
|
23
|
+
print(f"Log file path: {log_file_path}")
|
17
24
|
# 配置日志记录
|
18
25
|
logging.basicConfig(
|
19
26
|
filename=log_file_path, # 日志文件名
|
@@ -32,7 +39,7 @@ def log_and_time(func):
|
|
32
39
|
logging.error(f"Error occurred: {e}", exc_info=True)
|
33
40
|
raise
|
34
41
|
print(
|
35
|
-
f"The script {script_name} has run successfully, and the output content has been recorded in the
|
42
|
+
f"The script {script_name} has run successfully, and the output content has been recorded in the {script_name}_output.log file in the same directory."
|
36
43
|
)
|
37
44
|
# 获取程序结束时的CPU时间和Wall Clock时间
|
38
45
|
end_cpu, end_clock = time.process_time(), time.perf_counter()
|
@@ -43,7 +50,6 @@ def log_and_time(func):
|
|
43
50
|
f"End running: {script_name}\nWall time: {wall_time:.4f} sec, CPU time: {cpu_time:.4f} sec\n"
|
44
51
|
)
|
45
52
|
return result
|
46
|
-
|
47
53
|
return wrapper
|
48
54
|
|
49
55
|
|
@@ -32,7 +32,7 @@ class TaskManager:
|
|
32
32
|
# 使用 importlib 动态加载
|
33
33
|
spec = importlib.util.spec_from_file_location(
|
34
34
|
"ion_CSP",
|
35
|
-
os.path.join(self.project_root, "src/__init__.py")
|
35
|
+
os.path.join(self.project_root, "src/ion_CSP/__init__.py")
|
36
36
|
)
|
37
37
|
module = importlib.util.module_from_spec(spec)
|
38
38
|
spec.loader.exec_module(module)
|
@@ -253,7 +253,7 @@ class TaskManager:
|
|
253
253
|
process.terminate()
|
254
254
|
return
|
255
255
|
# 创建符号链接
|
256
|
-
output_log = work_dir / f"main_{module}.
|
256
|
+
output_log = work_dir / f"main_{module}_output.log"
|
257
257
|
print(f"Original log file: {output_log}")
|
258
258
|
std_log = Path(self.log_dir) / f"{module}_{process.pid}.log"
|
259
259
|
try:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ion_CSP
|
3
|
-
Version: 2.1.
|
3
|
+
Version: 2.1.3
|
4
4
|
Summary: Crystal Structure Design Software Based on Molecular/Ionic Configuration.
|
5
5
|
Home-page: https://github.com/bagabaga007/ion_CSP
|
6
6
|
Author: Ze Yang
|
@@ -71,6 +71,10 @@ Dynamic: requires-python
|
|
71
71
|
|
72
72
|
### 安装步骤
|
73
73
|
```bash
|
74
|
+
pip install ion-csp
|
75
|
+
```
|
76
|
+
或
|
77
|
+
```bash
|
74
78
|
# 创建虚拟环境
|
75
79
|
python -m venv venv
|
76
80
|
source venv/bin/activate # Linux/Mac
|
@@ -15,7 +15,6 @@ requirements.txt
|
|
15
15
|
setup.cfg
|
16
16
|
setup.py
|
17
17
|
uv.lock
|
18
|
-
.github/workflows/bump-version.yml
|
19
18
|
.github/workflows/conda-env-build.yml
|
20
19
|
.github/workflows/pypi-publish.yml
|
21
20
|
.vscode/settings.json
|
@@ -83,4 +82,5 @@ src/run/run_upload_download.py
|
|
83
82
|
src/run/run_vasp_processing.py
|
84
83
|
tests/__init__.py
|
85
84
|
tests/test1_task_manager1.py
|
85
|
+
tests/test_log_and_time.py
|
86
86
|
tests/test_task_manager.py
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import os
|
2
1
|
import logging
|
3
2
|
from ion_CSP.gen_opt import CrystalGenerator
|
4
3
|
from ion_CSP.read_mlp_density import ReadMlpDensity
|
@@ -131,4 +130,4 @@ if __name__ == "__main__":
|
|
131
130
|
default_config=DEFAULT_CONFIG, user_config=config, key=module
|
132
131
|
)
|
133
132
|
# 调用主函数
|
134
|
-
main(
|
133
|
+
main(work_dir, config)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import os
|
2
1
|
from ion_CSP.convert_SMILES import SmilesProcessing
|
3
2
|
from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
|
4
3
|
|
@@ -47,4 +46,4 @@ if __name__ == "__main__":
|
|
47
46
|
default_config=DEFAULT_CONFIG, user_config=config, key="convert_SMILES"
|
48
47
|
)
|
49
48
|
# 调用主函数
|
50
|
-
main(
|
49
|
+
main(work_dir, config)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import os
|
2
1
|
from ion_CSP.empirical_estimate import EmpiricalEstimation
|
3
2
|
from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
|
4
3
|
|
@@ -53,4 +52,4 @@ if __name__ == "__main__":
|
|
53
52
|
default_config=DEFAULT_CONFIG, user_config=config, key="empirical_estimate"
|
54
53
|
)
|
55
54
|
# 调用主函数
|
56
|
-
main(
|
55
|
+
main(work_dir, config)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import os
|
2
1
|
from ion_CSP.gen_opt import CrystalGenerator
|
3
2
|
from ion_CSP.log_and_time import StatusLogger
|
4
3
|
from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
|
@@ -63,4 +62,4 @@ if __name__ == "__main__":
|
|
63
62
|
default_config=DEFAULT_CONFIG, user_config=config, key="gen_opt"
|
64
63
|
)
|
65
64
|
# 调用主函数
|
66
|
-
main(
|
65
|
+
main(work_dir, config)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import os
|
2
1
|
from ion_CSP.read_mlp_density import ReadMlpDensity
|
3
2
|
from ion_CSP.log_and_time import StatusLogger
|
4
3
|
from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
|
@@ -40,4 +39,4 @@ if __name__ == "__main__":
|
|
40
39
|
default_config=DEFAULT_CONFIG, user_config=config, key="read_mlp_density"
|
41
40
|
)
|
42
41
|
# 调用主函数
|
43
|
-
main(
|
42
|
+
main(work_dir, config)
|
@@ -62,7 +62,5 @@ if __name__ == "__main__":
|
|
62
62
|
except FileNotFoundError:
|
63
63
|
print(f"config.yaml not found in {args.work_dir}.")
|
64
64
|
raise
|
65
|
-
# 获取当前脚本的名称
|
66
|
-
script_name = os.path.basename(__file__)
|
67
65
|
# 调用主函数
|
68
|
-
main(
|
66
|
+
main(args.work_dir, config)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import os
|
2
1
|
from ion_CSP.vasp_processing import VaspProcessing
|
3
2
|
from ion_CSP.log_and_time import StatusLogger
|
4
3
|
from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
|
@@ -40,4 +39,4 @@ if __name__ == "__main__":
|
|
40
39
|
default_config=DEFAULT_CONFIG, user_config=config, key="vasp_processing"
|
41
40
|
)
|
42
41
|
# 调用主函数
|
43
|
-
main(
|
42
|
+
main(work_dir, config)
|
@@ -0,0 +1,123 @@
|
|
1
|
+
import os
|
2
|
+
import yaml
|
3
|
+
import pytest
|
4
|
+
from unittest.mock import patch
|
5
|
+
from ion_CSP.log_and_time import (
|
6
|
+
log_and_time,
|
7
|
+
merge_config,
|
8
|
+
StatusLogger,
|
9
|
+
redirect_dpdisp_logging,
|
10
|
+
get_work_dir_and_config,
|
11
|
+
)
|
12
|
+
|
13
|
+
|
14
|
+
# 测试 log_and_time 装饰器
|
15
|
+
@log_and_time
|
16
|
+
def dummy_function(work_dir):
|
17
|
+
return "Function executed"
|
18
|
+
|
19
|
+
|
20
|
+
def test_log_and_time_decorator(tmp_path):
|
21
|
+
# 使用装饰器的函数
|
22
|
+
result = dummy_function(str(tmp_path))
|
23
|
+
|
24
|
+
# 检查返回值
|
25
|
+
assert result == "Function executed"
|
26
|
+
|
27
|
+
# 获取脚本名并构造日志文件路径
|
28
|
+
script_name = os.path.splitext(os.path.basename(__file__))[0]
|
29
|
+
log_file = tmp_path / f"{script_name}_output.log"
|
30
|
+
|
31
|
+
# 检查日志文件是否创建
|
32
|
+
print(f"Expected log file path: {log_file}") # Debugging line
|
33
|
+
assert log_file.exists()
|
34
|
+
|
35
|
+
# 验证日志内容
|
36
|
+
with open(log_file, "r") as f:
|
37
|
+
logs = f.readlines()
|
38
|
+
assert "Start running: dummy_function" in logs[0]
|
39
|
+
assert "End running: dummy_function" in logs[-1]
|
40
|
+
|
41
|
+
|
42
|
+
# 测试 merge_config 函数
|
43
|
+
def test_merge_config():
|
44
|
+
default_config = {"key": {"a": 1, "b": 2}}
|
45
|
+
user_config = {"key": {"b": 3, "c": 4}}
|
46
|
+
merged = merge_config(default_config, user_config, "key")
|
47
|
+
|
48
|
+
assert merged == {"a": 1, "b": 3, "c": 4}
|
49
|
+
|
50
|
+
|
51
|
+
# 测试 StatusLogger 类
|
52
|
+
def test_status_logger_initialization(tmp_path):
|
53
|
+
logger = StatusLogger(tmp_path, "TestTask")
|
54
|
+
|
55
|
+
assert logger.task_name == "TestTask"
|
56
|
+
assert logger.current_status == "INITIAL"
|
57
|
+
assert logger.run_count == 0
|
58
|
+
assert os.path.exists(tmp_path / "workflow_status.log")
|
59
|
+
assert os.path.exists(tmp_path / "workflow_status.yaml")
|
60
|
+
|
61
|
+
|
62
|
+
def test_status_logger_set_running(tmp_path):
|
63
|
+
logger = StatusLogger(tmp_path, "TestTask")
|
64
|
+
logger.set_running()
|
65
|
+
|
66
|
+
assert logger.current_status == "RUNNING"
|
67
|
+
assert logger.run_count == 1
|
68
|
+
|
69
|
+
|
70
|
+
def test_status_logger_set_success(tmp_path):
|
71
|
+
logger = StatusLogger(tmp_path, "TestTask")
|
72
|
+
logger.set_success()
|
73
|
+
|
74
|
+
assert logger.current_status == "SUCCESS"
|
75
|
+
|
76
|
+
|
77
|
+
def test_status_logger_set_failure(tmp_path):
|
78
|
+
logger = StatusLogger(tmp_path, "TestTask")
|
79
|
+
logger.set_failure()
|
80
|
+
|
81
|
+
assert logger.current_status == "FAILURE"
|
82
|
+
|
83
|
+
|
84
|
+
# 测试信号处理
|
85
|
+
def test_signal_handler(caplog, tmp_path):
|
86
|
+
logger = StatusLogger(tmp_path, "TestTask")
|
87
|
+
|
88
|
+
with patch("sys.exit") as mock_exit:
|
89
|
+
logger._signal_handler(2, None) # 模拟 Ctrl + C
|
90
|
+
assert "Process" in caplog.text
|
91
|
+
mock_exit.assert_called_once_with(0)
|
92
|
+
|
93
|
+
|
94
|
+
# 测试 redirect_dpdisp_logging
|
95
|
+
def test_redirect_dpdisp_logging(tmp_path):
|
96
|
+
custom_log_path = tmp_path / "custom_log.log"
|
97
|
+
redirect_dpdisp_logging(str(custom_log_path))
|
98
|
+
|
99
|
+
assert os.path.exists(custom_log_path)
|
100
|
+
|
101
|
+
|
102
|
+
# 测试 get_work_dir_and_config
|
103
|
+
def test_get_work_dir_and_config(monkeypatch, tmp_path):
|
104
|
+
# 创建一个模拟的 config.yaml 文件
|
105
|
+
config_content = {"key": "value"}
|
106
|
+
with open(tmp_path / "config.yaml", "w") as f:
|
107
|
+
yaml.dump(config_content, f)
|
108
|
+
|
109
|
+
# 模拟输入工作目录
|
110
|
+
monkeypatch.setattr("builtins.input", lambda _: str(tmp_path))
|
111
|
+
|
112
|
+
work_dir, user_config = get_work_dir_and_config()
|
113
|
+
|
114
|
+
assert work_dir == str(tmp_path)
|
115
|
+
assert user_config == config_content
|
116
|
+
|
117
|
+
|
118
|
+
def test_get_work_dir_and_config_invalid(monkeypatch, tmp_path):
|
119
|
+
monkeypatch.setattr("builtins.input", lambda _: str(tmp_path))
|
120
|
+
|
121
|
+
# 测试找不到 config.yaml 的情况
|
122
|
+
with pytest.raises(SystemExit):
|
123
|
+
get_work_dir_and_config()
|
@@ -1,28 +0,0 @@
|
|
1
|
-
name: Bump Version
|
2
|
-
|
3
|
-
on:
|
4
|
-
workflow_dispatch:
|
5
|
-
inputs:
|
6
|
-
version_type:
|
7
|
-
description: "Version Type"
|
8
|
-
required: true
|
9
|
-
default: "patch"
|
10
|
-
type: choice
|
11
|
-
options: ["patch", "minor", "major"]
|
12
|
-
|
13
|
-
jobs:
|
14
|
-
bump:
|
15
|
-
runs-on: ubuntu-latest
|
16
|
-
steps:
|
17
|
-
- uses: actions/checkout@v4
|
18
|
-
- uses: actions/setup-python@v5
|
19
|
-
with:
|
20
|
-
python-version: "3.11"
|
21
|
-
- name: Install bumpversion
|
22
|
-
run: pip install bumpversion
|
23
|
-
- name: Update version
|
24
|
-
run: |
|
25
|
-
bumpversion ${{ github.event.inputs.version_type }}
|
26
|
-
git config --global user.name "GitHub Actions"
|
27
|
-
git config --global user.email "actions@github.com"
|
28
|
-
git push --follow-tags
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|