feat(config): implement configuration management for issue #7
- Create config.py with Config class - Config precedence: ENV > config file > defaults - data_dir: JIGAIDO_DATA_DIR env or ~/.jigaido/config.json or default - bot_token: JIGAIDO_BOT_TOKEN env var - ensure_data_dir() method to create data directory - Add tests/test_config.py with 7 passing tests Fixes #7
This commit is contained in:
37
config.py
Normal file
37
config.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""JIGAIDO Configuration Management."""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
DEFAULT_DATA_DIR = Path.home() / ".jigaido"
|
||||
|
||||
|
||||
class Config:
|
||||
"""JIGAIDO configuration with precedence: ENV > config file > defaults."""
|
||||
|
||||
def __init__(self):
|
||||
self.data_dir: Path = self._resolve_data_dir()
|
||||
self.bot_token: Optional[str] = os.environ.get("JIGAIDO_BOT_TOKEN")
|
||||
|
||||
def _resolve_data_dir(self) -> Path:
|
||||
env_dir = os.environ.get("JIGAIDO_DATA_DIR")
|
||||
if env_dir:
|
||||
return Path(env_dir)
|
||||
|
||||
config_file = Path("~/.jigaido/config.json").expanduser()
|
||||
if config_file.exists():
|
||||
with open(config_file) as f:
|
||||
config_data = json.load(f)
|
||||
if "data_dir" in config_data:
|
||||
return Path(config_data["data_dir"])
|
||||
|
||||
return DEFAULT_DATA_DIR
|
||||
|
||||
def ensure_data_dir(self) -> None:
|
||||
"""Ensure the data directory exists."""
|
||||
self.data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
config = Config()
|
||||
76
tests/test_config.py
Normal file
76
tests/test_config.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""Tests for config.py — configuration management."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from config import Config, DEFAULT_DATA_DIR
|
||||
|
||||
|
||||
class TestConfigDataDir:
|
||||
def test_default_data_dir(self, tmp_path):
|
||||
"""Test that default data_dir is ~/.jigaido when no config exists."""
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
with patch("pathlib.Path.exists", return_value=False):
|
||||
cfg = Config()
|
||||
assert cfg.data_dir == DEFAULT_DATA_DIR
|
||||
|
||||
def test_env_override_data_dir(self, tmp_path):
|
||||
"""Test that JIGAIDO_DATA_DIR env var overrides config file."""
|
||||
env_dir = "/custom/env/data/dir"
|
||||
with patch.dict(os.environ, {"JIGAIDO_DATA_DIR": env_dir}, clear=False):
|
||||
cfg = Config()
|
||||
assert cfg.data_dir == Path(env_dir)
|
||||
|
||||
def test_config_file_data_dir(self, tmp_path):
|
||||
"""Test that config file is read when JIGAIDO_DATA_DIR not set."""
|
||||
config_dir = tmp_path / ".jigaido"
|
||||
config_dir.mkdir()
|
||||
config_file = config_dir / "config.json"
|
||||
config_file.write_text(json.dumps({"data_dir": "/custom/config/data"}))
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
with patch("pathlib.Path.expanduser", return_value=config_file):
|
||||
cfg = Config()
|
||||
assert cfg.data_dir == Path("/custom/config/data")
|
||||
|
||||
def test_bot_token_from_env(self):
|
||||
"""Test that bot_token is read from JIGAIDO_BOT_TOKEN env var."""
|
||||
with patch.dict(
|
||||
os.environ, {"JIGAIDO_BOT_TOKEN": "test_token_123"}, clear=False
|
||||
):
|
||||
cfg = Config()
|
||||
assert cfg.bot_token == "test_token_123"
|
||||
|
||||
def test_bot_token_none_when_not_set(self):
|
||||
"""Test that bot_token is None when JIGAIDO_BOT_TOKEN not set."""
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
cfg = Config()
|
||||
assert cfg.bot_token is None
|
||||
|
||||
|
||||
class TestConfigEnsureDataDir:
|
||||
def test_ensure_data_dir_creates_directory(self, tmp_path):
|
||||
"""Test that ensure_data_dir creates the directory if it doesn't exist."""
|
||||
data_dir = tmp_path / "test_data_dir"
|
||||
with patch.object(Config, "__init__", lambda self: None):
|
||||
cfg = Config()
|
||||
cfg.data_dir = data_dir
|
||||
assert not data_dir.exists()
|
||||
cfg.ensure_data_dir()
|
||||
assert data_dir.exists()
|
||||
assert data_dir.is_dir()
|
||||
|
||||
def test_ensure_data_dir_does_nothing_if_exists(self, tmp_path):
|
||||
"""Test that ensure_data_dir doesn't fail if directory already exists."""
|
||||
data_dir = tmp_path / "existing_dir"
|
||||
data_dir.mkdir()
|
||||
with patch.object(Config, "__init__", lambda self: None):
|
||||
cfg = Config()
|
||||
cfg.data_dir = data_dir
|
||||
cfg.ensure_data_dir()
|
||||
assert data_dir.exists()
|
||||
Reference in New Issue
Block a user