From 9b8b15414f1588826bb293f3f13612e3630f478c Mon Sep 17 00:00:00 2001 From: shokollm <270575765+shokollm@users.noreply.github.com> Date: Thu, 2 Apr 2026 20:16:41 +0000 Subject: [PATCH] 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 --- config.py | 37 +++++++++++++++++++++ tests/test_config.py | 76 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 config.py create mode 100644 tests/test_config.py diff --git a/config.py b/config.py new file mode 100644 index 0000000..4f17f66 --- /dev/null +++ b/config.py @@ -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() diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..b7a2111 --- /dev/null +++ b/tests/test_config.py @@ -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()