Skip to content

Commit 14bfe2c

Browse files
authored
Merge pull request #572 from simvue-io/feature/simvue-pyproject-toml
Allow non-authentication configurations to be read as key `tool.simvue` from `pyproject.toml`
2 parents 53d6047 + 423de7c commit 14bfe2c

File tree

2 files changed

+70
-9
lines changed

2 files changed

+70
-9
lines changed

simvue/config/user.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,38 @@ class SimvueConfiguration(pydantic.BaseModel):
4242
run: DefaultRunSpecifications = DefaultRunSpecifications()
4343
offline: OfflineSpecifications = OfflineSpecifications()
4444

45+
@classmethod
46+
def _load_pyproject_configs(cls) -> typing.Optional[dict]:
47+
"""Recover any Simvue non-authentication configurations from pyproject.toml"""
48+
_pyproject_toml = sv_util.find_first_instance_of_file(
49+
file_names=["pyproject.toml"], check_user_space=False
50+
)
51+
52+
if not _pyproject_toml:
53+
return
54+
55+
_project_data = toml.load(_pyproject_toml)
56+
57+
if not (_simvue_setup := _project_data.get("tool", {}).get("simvue")):
58+
return
59+
60+
# Do not allow reading of authentication credentials within a project file
61+
_server_credentials = _simvue_setup.get("server", {})
62+
_offline_credentials = _simvue_setup.get("offline", {})
63+
64+
if any(
65+
[
66+
_server_credentials.get("token"),
67+
_server_credentials.get("url"),
68+
_offline_credentials.get("cache"),
69+
]
70+
):
71+
raise RuntimeError(
72+
"Provision of Simvue URL, Token or offline directory in pyproject.toml is not allowed."
73+
)
74+
75+
return _simvue_setup
76+
4577
@classmethod
4678
@sv_util.prettify_pydantic
4779
def fetch(
@@ -67,13 +99,13 @@ def fetch(
6799
object containing configurations
68100
69101
"""
70-
_config_dict: dict[str, dict[str, str]] = {}
102+
_config_dict: dict[str, dict[str, str]] = cls._load_pyproject_configs() or {}
71103

72104
try:
73105
logger.info(f"Using config file '{cls.config_file()}'")
74106

75107
# NOTE: Legacy INI support has been removed
76-
_config_dict = toml.load(cls.config_file())
108+
_config_dict |= toml.load(cls.config_file())
77109

78110
except FileNotFoundError:
79111
if not server_token or not server_url:

tests/refactor/test_config.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
ids=("use_env", "no_env")
1515
)
1616
@pytest.mark.parametrize(
17-
"use_file", (None, "basic", "extended"),
18-
ids=("no_file", "basic_file", "extended_file")
17+
"use_file", (None, "basic", "extended", "pyproject.toml"),
18+
ids=("no_file", "basic_file", "extended_file", "pyproject_toml")
1919
)
2020
@pytest.mark.parametrize(
2121
"use_args", (True, False),
@@ -35,8 +35,11 @@ def test_config_setup(
3535
_other_url: str = "http://simvue.example.com/"
3636
_arg_url: str = "http://simvue.example.io/"
3737
_description: str = "test case for runs"
38+
_description_ppt: str = "test case for runs using pyproject.toml"
3839
_folder: str = "/test-case"
40+
_folder_ppt: str = "/test-case-ppt"
3941
_tags: list[str] = ["tag-test", "other-tag"]
42+
_tags_ppt: list[str] = ["tag-test-ppt", "other-tag-ppt"]
4043

4144
# Deactivate the server checks for this test
4245
monkeypatch.setenv("SIMVUE_NO_SERVER_CHECK", "True")
@@ -49,10 +52,24 @@ def test_config_setup(
4952

5053
with tempfile.TemporaryDirectory() as temp_d:
5154
_config_file = None
55+
_ppt_file = None
5256
if use_file:
57+
if use_file == "pyproject.toml":
58+
_lines_ppt: str = f"""
59+
[tool.poetry]
60+
name = "simvue_testing"
61+
version = "0.1.0"
62+
description = "A dummy test project"
63+
64+
[tool.simvue.run]
65+
description = "{_description_ppt}"
66+
folder = "{_folder_ppt}"
67+
tags = {_tags_ppt}
68+
"""
69+
with open((_ppt_file := pathlib.Path(temp_d).joinpath("pyproject.toml")), "w") as out_f:
70+
out_f.write(_lines_ppt)
5371
with open(_config_file := pathlib.Path(temp_d).joinpath("simvue.toml"), "w") as out_f:
54-
if use_file:
55-
_lines: str = f"""
72+
_lines: str = f"""
5673
[server]
5774
url = "{_url}"
5875
token = "{_token}"
@@ -72,7 +89,15 @@ def test_config_setup(
7289
SimvueConfiguration.config_file.cache_clear()
7390

7491
mocker.patch("simvue.config.parameters.get_expiry", lambda *_, **__: 1e10)
75-
mocker.patch("simvue.config.user.sv_util.find_first_instance_of_file", lambda *_, **__: _config_file)
92+
93+
94+
def _mocked_find(file_names: list[str], *_, ppt_file=_ppt_file, conf_file=_config_file, **__) -> str:
95+
if "pyproject.toml" in file_names:
96+
return ppt_file
97+
else:
98+
return conf_file
99+
100+
mocker.patch("simvue.config.user.sv_util.find_first_instance_of_file", _mocked_find)
76101

77102
import simvue.config.user
78103

@@ -88,7 +113,7 @@ def test_config_setup(
88113
else:
89114
_config = simvue.config.user.SimvueConfiguration.fetch()
90115

91-
if use_file:
116+
if use_file and use_file != "pyproject.toml":
92117
assert _config.config_file() == _config_file
93118

94119
if use_env:
@@ -97,7 +122,7 @@ def test_config_setup(
97122
elif use_args:
98123
assert _config.server.url == _arg_url
99124
assert _config.server.token == _arg_token
100-
elif use_file:
125+
elif use_file and use_file != "pyproject.toml":
101126
assert _config.server.url == _url
102127
assert _config.server.token == _token
103128
assert _config.offline.cache == temp_d
@@ -106,6 +131,10 @@ def test_config_setup(
106131
assert _config.run.description == _description
107132
assert _config.run.folder == _folder
108133
assert _config.run.tags == _tags
134+
elif use_file == "pyproject.toml":
135+
assert _config.run.description == _description_ppt
136+
assert _config.run.folder == _folder_ppt
137+
assert _config.run.tags == _tags_ppt
109138
elif use_file:
110139
assert _config.run.folder == "/"
111140
assert not _config.run.description

0 commit comments

Comments
 (0)