refactor: extract configuration handling to own class
This commit is contained in:
parent
b391286801
commit
3dad2071ff
4 changed files with 84 additions and 4 deletions
|
@ -5,5 +5,10 @@ Models and datastructures
|
||||||
import pydantic
|
import pydantic
|
||||||
|
|
||||||
|
|
||||||
class Configuration(pydantic.BaseModel):
|
class ContainerMetadata(pydantic.BaseModel):
|
||||||
"""Command line application configuration options"""
|
"""Metadata pulled from container status check"""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
status: str
|
||||||
|
image: str
|
||||||
|
started: int
|
||||||
|
|
11
spud/cli.py
11
spud/cli.py
|
@ -10,7 +10,7 @@ import pathlib
|
||||||
import click
|
import click
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
from spud.base import Configuration
|
from spud.config import Configuration
|
||||||
|
|
||||||
DEFAULT_CONFIGURATION_PATH = "~/.config/spud/config.json"
|
DEFAULT_CONFIGURATION_PATH = "~/.config/spud/config.json"
|
||||||
|
|
||||||
|
@ -27,7 +27,14 @@ def cli(context, config):
|
||||||
"""CLI root"""
|
"""CLI root"""
|
||||||
context.ensure_object(dict)
|
context.ensure_object(dict)
|
||||||
config = config if config is not None else DEFAULT_CONFIGURATION_PATH
|
config = config if config is not None else DEFAULT_CONFIGURATION_PATH
|
||||||
context.obj["config_path"] = pathlib.Path(config).expanduser()
|
config_path = pathlib.Path(config).expanduser()
|
||||||
|
|
||||||
|
context.obj["config_path"] = config_path
|
||||||
|
|
||||||
|
if config_path.exists():
|
||||||
|
context.obj["config"] = Configuration.from_file(config_path)
|
||||||
|
else:
|
||||||
|
context.obj["config"] = None
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
|
|
36
spud/config.py
Normal file
36
spud/config.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import json
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
import pydantic
|
||||||
|
|
||||||
|
|
||||||
|
class Configuration(pydantic.BaseModel):
|
||||||
|
"""Command line application configuration options"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_file(cls, path: pathlib.Path) -> "Configuration":
|
||||||
|
"""
|
||||||
|
Generates a Configuration object from the file found at {path}.
|
||||||
|
|
||||||
|
Raises if:
|
||||||
|
- The file does not exist
|
||||||
|
- The file is not valid JSON
|
||||||
|
- The file does not respect the expected schema
|
||||||
|
"""
|
||||||
|
if not path.exists():
|
||||||
|
raise RuntimeError(f"Configuration file not found: {str(path)}.")
|
||||||
|
|
||||||
|
with open(path, "r", encoding="utf8") as config_file:
|
||||||
|
config_data = config_file.read()
|
||||||
|
|
||||||
|
try:
|
||||||
|
parsed_configuration = json.loads(config_data)
|
||||||
|
return cls(**parsed_configuration)
|
||||||
|
except json.decoder.JSONDecodeError as exc:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Configuration file is not valid JSON ({str(path)})."
|
||||||
|
) from exc
|
||||||
|
except pydantic.ValidationError as exc:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Configuration file has wrong schema ({str(path)})."
|
||||||
|
) from exc
|
32
tests/test_config.py
Normal file
32
tests/test_config.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from spud.config import Configuration
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="sample_config")
|
||||||
|
def sample_config_fixture():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_file_creates_configuration_from_file(tmpdir, sample_config):
|
||||||
|
config_file = tmpdir / "config.json"
|
||||||
|
config_file.write(json.dumps(sample_config))
|
||||||
|
|
||||||
|
config = Configuration.from_file(config_file)
|
||||||
|
|
||||||
|
assert config.model_dump() == sample_config
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_file_raises_if_file_not_found(tmpdir):
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
Configuration.from_file(tmpdir / "nonfile.json")
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_file_raises_if_file_not_json(tmpdir):
|
||||||
|
config_file = tmpdir / "config.json"
|
||||||
|
config_file.write("notjson")
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
Configuration.from_file(config_file)
|
Reference in a new issue