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
|
||||
|
||||
|
||||
class Configuration(pydantic.BaseModel):
|
||||
"""Command line application configuration options"""
|
||||
class ContainerMetadata(pydantic.BaseModel):
|
||||
"""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 uvicorn
|
||||
|
||||
from spud.base import Configuration
|
||||
from spud.config import Configuration
|
||||
|
||||
DEFAULT_CONFIGURATION_PATH = "~/.config/spud/config.json"
|
||||
|
||||
|
@ -27,7 +27,14 @@ def cli(context, config):
|
|||
"""CLI root"""
|
||||
context.ensure_object(dict)
|
||||
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()
|
||||
|
|
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