-
Notifications
You must be signed in to change notification settings - Fork 93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Yaml config sets #2876
base: main
Are you sure you want to change the base?
Yaml config sets #2876
Changes from all commits
72bdfb3
17e1fc4
36cddc6
82322a2
b3e83fe
4cc6546
917c666
8fea4db
6ebdbdb
3613a09
5c86415
b6ffec8
237f73b
40d71d6
2682982
68b5064
3f525e5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import pathlib | ||
|
||
from packaging.requirements import Requirement | ||
from pydantic import BaseModel, ConfigDict, field_validator | ||
|
||
from _nebari._version import __version__ | ||
from _nebari.utils import yaml | ||
|
||
|
||
class ConfigSetMetadata(BaseModel): | ||
model_config: ConfigDict = ConfigDict(extra="allow", arbitrary_types_allowed=True) | ||
name: str # for use with guided init | ||
description: str = None | ||
nebari_version: str | Requirement | ||
|
||
@field_validator("nebari_version") | ||
@classmethod | ||
def validate_version_requirement(cls, version_req): | ||
if isinstance(version_req, str): | ||
version_req = Requirement(f"nebari{version_req}") | ||
version_req.specifier.prereleases = True | ||
|
||
return version_req | ||
|
||
def check_version(self, version): | ||
if version not in self.nebari_version.specifier: | ||
raise ValueError( | ||
f"Current Nebari version {__version__} is not compatible with " | ||
f'required version {self.nebari_version.specifier} for "{self.name}" config set.' | ||
) | ||
|
||
|
||
class ConfigSet(BaseModel): | ||
metadata: ConfigSetMetadata | ||
config: dict | ||
|
||
|
||
def read_config_set(config_set_filepath: str): | ||
"""Read a config set from a config file.""" | ||
|
||
filename = pathlib.Path(config_set_filepath) | ||
|
||
with filename.open() as f: | ||
config_set_yaml = yaml.load(f) | ||
|
||
config_set = ConfigSet(**config_set_yaml) | ||
|
||
# validation | ||
config_set.metadata.check_version(__version__) | ||
|
||
return config_set |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
from unittest.mock import patch | ||
|
||
import pytest | ||
from packaging.requirements import Requirement | ||
|
||
from _nebari.config_set import ConfigSetMetadata, read_config_set | ||
|
||
test_version = "2024.12.2" | ||
|
||
|
||
def test_valid_version_requirement(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we parameterize this test with a few different version strings to ensure it works in all the allowed formats? ideally including pre-release versions. |
||
metadata = ConfigSetMetadata( | ||
name="test-config", nebari_version=">=2024.12.0,<2025.0.0" | ||
) | ||
assert metadata.nebari_version.specifier.contains(test_version) | ||
|
||
|
||
def test_invalid_version_requirement(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be parameterized too to validate multiple invalid types |
||
with pytest.raises(ValueError) as exc_info: | ||
csm = ConfigSetMetadata(name="test-config", nebari_version=">=2025.0.0") | ||
csm.check_version(test_version) | ||
assert "Current Nebari version" in str(exc_info.value) | ||
|
||
|
||
def test_valid_version_requirement_with_requirement_object(): | ||
requirement = Requirement("nebari>=2024.12.0") | ||
metadata = ConfigSetMetadata(name="test-config", nebari_version=requirement) | ||
assert metadata.nebari_version.specifier.contains(test_version) | ||
|
||
|
||
def test_invalid_version_requirement_with_requirement_object(): | ||
requirement = Requirement("nebari>=2025.0.0") | ||
with pytest.raises(ValueError) as exc_info: | ||
csm = ConfigSetMetadata(name="test-config", nebari_version=requirement) | ||
csm.check_version(test_version) | ||
assert "Current Nebari version" in str(exc_info.value) | ||
|
||
|
||
def test_read_config_set_valid(tmp_path): | ||
config_set_yaml = """ | ||
metadata: | ||
name: test-config | ||
nebari_version: ">=2024.12.0" | ||
config: | ||
key: value | ||
""" | ||
config_set_filepath = tmp_path / "config_set.yaml" | ||
config_set_filepath.write_text(config_set_yaml) | ||
with patch("_nebari.config_set.__version__", "2024.12.2"): | ||
config_set = read_config_set(str(config_set_filepath)) | ||
assert config_set.metadata.name == "test-config" | ||
assert config_set.config["key"] == "value" | ||
|
||
|
||
def test_read_config_set_invalid_version(tmp_path): | ||
config_set_yaml = """ | ||
metadata: | ||
name: test-config | ||
nebari_version: ">=2025.0.0" | ||
config: | ||
key: value | ||
""" | ||
config_set_filepath = tmp_path / "config_set.yaml" | ||
config_set_filepath.write_text(config_set_yaml) | ||
|
||
with patch("_nebari.config_set.__version__", "2024.12.2"): | ||
with pytest.raises(ValueError) as exc_info: | ||
read_config_set(str(config_set_filepath)) | ||
assert "Current Nebari version" in str(exc_info.value) | ||
|
||
|
||
if __name__ == "__main__": | ||
pytest.main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
none
is allowed here, shouldn't the type beOptional[str] = None
?