Skip to content

Commit 23e0541

Browse files
authored
fix(config): honor dotenv backend selection at runtime (#210)
* fix(config): honor dotenv backend selection at runtime Settings classes now read .env directly through pydantic-settings so backend and related runtime configuration match the repo documentation without requiring callers to load dotenv themselves. A focused regression test reloads the config module from a temporary working directory to prove EVOLVE_BACKEND=postgres is picked up from .env and that the module-level singleton follows the same behavior. Constraint: Keep configuration loading dependency-free and inside existing pydantic settings flow Rejected: Add manual load_dotenv bootstrap in library entrypoints | spreads config side effects across multiple runtimes Confidence: high Scope-risk: narrow Reversibility: clean Directive: If config needs to work outside the repo root, prefer an explicit absolute env file strategy rather than adding more implicit loaders Tested: ./.venv/bin/pytest -v tests/unit/test_client.py; ./.venv/bin/ruff check altk_evolve/config/evolve.py altk_evolve/config/postgres.py altk_evolve/config/filesystem.py altk_evolve/config/milvus.py altk_evolve/config/llm.py altk_evolve/config/phoenix.py tests/unit/test_client.py Not-tested: Full e2e MCP or CLI startup from non-repo working directories * test(client): preserve default config state after dotenv reload The dotenv-backed backend assertion reloads altk_evolve.config.evolve under a temporary working directory. The cleanup now restores the original cwd and clears EVOLVE_BACKEND before reloading so the module singleton is rebuilt against the default repo context instead of the temporary postgres fixture. Constraint: importlib.reload reconstructs evolve_config from the current cwd and environment\nRejected: Only overwrite evolve_config.backend after reload | the module instance is still recreated from tmp_path/.env\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Tests that reload settings modules should restore both cwd and env before cleanup reloads\nTested: uv run pytest -v tests/unit/test_client.py\nNot-tested: Full test suite
1 parent 6f79732 commit 23e0541

7 files changed

Lines changed: 35 additions & 7 deletions

File tree

altk_evolve/config/evolve.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
class EvolveConfig(BaseSettings):
6-
model_config = SettingsConfigDict(env_prefix="EVOLVE_")
6+
model_config = SettingsConfigDict(env_prefix="EVOLVE_", env_file=".env", extra="ignore")
77
backend: Literal["milvus", "filesystem", "postgres"] = "filesystem"
88
namespace_id: str = "evolve"
99
settings: BaseSettings | None = None

altk_evolve/config/filesystem.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
class FilesystemSettings(BaseSettings):
6-
model_config = SettingsConfigDict(env_prefix="EVOLVE_")
6+
model_config = SettingsConfigDict(env_prefix="EVOLVE_", env_file=".env", extra="ignore")
77
data_dir: str = Field(default="evolve_data", description="Directory to store JSON data files")
88

99

altk_evolve/config/llm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def _default_custom_provider() -> str | None:
2121

2222

2323
class LLMSettings(BaseSettings):
24-
model_config = SettingsConfigDict(env_prefix="EVOLVE_")
24+
model_config = SettingsConfigDict(env_prefix="EVOLVE_", env_file=".env", extra="ignore")
2525
tips_model: str = Field(default_factory=_default_model_name)
2626
conflict_resolution_model: str = Field(default_factory=_default_model_name)
2727
fact_extraction_model: str = Field(default_factory=_default_model_name)

altk_evolve/config/milvus.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
class MilvusDBSettings(BaseSettings):
6-
model_config = SettingsConfigDict(env_prefix="EVOLVE_")
6+
model_config = SettingsConfigDict(env_prefix="EVOLVE_", env_file=".env", extra="ignore")
77
uri: str = Field(default="entities.milvus.db")
88
user: str = Field(default="")
99
password: str = Field(default="")
@@ -15,7 +15,7 @@ class MilvusDBSettings(BaseSettings):
1515

1616

1717
class MilvusOtherSettings(BaseSettings):
18-
model_config = SettingsConfigDict(env_prefix="EVOLVE_")
18+
model_config = SettingsConfigDict(env_prefix="EVOLVE_", env_file=".env", extra="ignore")
1919
embedding_model: str = "sentence-transformers/all-MiniLM-L6-v2"
2020

2121

altk_evolve/config/phoenix.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
class PhoenixSettings(BaseSettings):
6-
model_config = SettingsConfigDict(env_prefix="PHOENIX_")
6+
model_config = SettingsConfigDict(env_prefix="PHOENIX_", env_file=".env", extra="ignore")
77
url: str = Field(default="http://localhost:6006", description="Phoenix server URL")
88
project: str = Field(default="default", description="Phoenix project name")
99

altk_evolve/config/postgres.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
class PostgresDBSettings(BaseSettings):
6-
model_config = SettingsConfigDict(env_prefix="EVOLVE_PG_")
6+
model_config = SettingsConfigDict(env_prefix="EVOLVE_PG_", env_file=".env", extra="ignore")
77
embedding_model: str = "sentence-transformers/all-MiniLM-L6-v2"
88
host: str = Field(default="localhost")
99
port: int = Field(default=5432)

tests/unit/test_client.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"""
44

55
import datetime
6+
import importlib
7+
from pathlib import Path
8+
69
import pytest
710

811
from altk_evolve.backend.base import BaseEntityBackend
@@ -20,6 +23,31 @@ def evolve_client() -> EvolveClient:
2023
return evolve_client
2124

2225

26+
@pytest.mark.unit
27+
def test_evolve_config_reads_backend_from_dotenv(tmp_path, monkeypatch):
28+
env_path = tmp_path / ".env"
29+
env_path.write_text("EVOLVE_BACKEND=postgres\n", encoding="utf-8")
30+
31+
original_cwd = Path.cwd()
32+
monkeypatch.chdir(tmp_path)
33+
monkeypatch.delenv("EVOLVE_BACKEND", raising=False)
34+
35+
import altk_evolve.config.evolve as evolve_module
36+
37+
original_backend = evolve_module.evolve_config.backend
38+
reloaded_module = importlib.reload(evolve_module)
39+
40+
try:
41+
assert reloaded_module.EvolveConfig().backend == "postgres"
42+
assert reloaded_module.evolve_config.backend == "postgres"
43+
finally:
44+
monkeypatch.chdir(original_cwd)
45+
monkeypatch.delenv("EVOLVE_BACKEND", raising=False)
46+
reloaded_module.evolve_config.backend = original_backend
47+
importlib.reload(reloaded_module)
48+
reloaded_module.evolve_config.backend = original_backend
49+
50+
2351
@pytest.mark.unit
2452
def test_health_check(evolve_client: EvolveClient, monkeypatch):
2553
# Client should return False derived from API response

0 commit comments

Comments
 (0)