70 lines
2.4 KiB
Python
70 lines
2.4 KiB
Python
"""Configuration from a dotenv file, including the archived CLI's variable names.
|
|
|
|
An operator who already has a ``photo_analyzer.env`` should not have to rewrite it
|
|
to run the application it was replaced by. The file is standing configuration; the
|
|
shell is what you meant this time, so the shell always wins.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
from photo_pipeline.config import Config, load_env_file, parse_env_file
|
|
|
|
SAMPLE = """
|
|
# The archived CLI's shape, comments and all.
|
|
LLM_API_KEY=not-real
|
|
LLM_BASE_URL="https://example.invalid/v1beta/openai/"
|
|
LLM_MODEL='gemini-2.5-flash'
|
|
LIBRARY=/tmp/pictures
|
|
|
|
MAX_WORKERS=4
|
|
# commented=ignored
|
|
malformed line without an equals sign
|
|
"""
|
|
|
|
|
|
def test_the_file_is_parsed_and_never_executed():
|
|
values = parse_env_file(SAMPLE)
|
|
|
|
assert values["LLM_BASE_URL"] == "https://example.invalid/v1beta/openai/" # quotes stripped
|
|
assert values["LLM_MODEL"] == "gemini-2.5-flash"
|
|
assert values["MAX_WORKERS"] == "4"
|
|
assert "commented" not in values and "malformed line without an equals sign" not in values
|
|
|
|
|
|
def test_the_archived_cli_names_still_configure_the_application():
|
|
values = parse_env_file(SAMPLE)
|
|
|
|
assert values["OPENAI_API_KEY"] == "not-real"
|
|
assert values["OPENAI_BASE_URL"] == "https://example.invalid/v1beta/openai/"
|
|
assert values["PHOTO_PIPELINE_LIBRARY_ROOTS"] == "/tmp/pictures"
|
|
|
|
|
|
def test_an_explicit_shell_variable_beats_the_file(tmp_path, monkeypatch):
|
|
path = tmp_path / "photo_analyzer.env"
|
|
path.write_text(SAMPLE)
|
|
monkeypatch.setenv("OPENAI_API_KEY", "from-the-shell")
|
|
monkeypatch.delenv("PHOTO_PIPELINE_LIBRARY_ROOTS", raising=False)
|
|
|
|
applied = load_env_file(path)
|
|
|
|
assert "OPENAI_API_KEY" not in applied, "the file overrode an exported value"
|
|
assert os.environ["OPENAI_API_KEY"] == "from-the-shell"
|
|
assert os.environ["PHOTO_PIPELINE_LIBRARY_ROOTS"] == "/tmp/pictures"
|
|
assert Config.from_env().library_roots[0].name == "pictures"
|
|
|
|
|
|
def test_the_file_is_found_through_its_variable(tmp_path, monkeypatch):
|
|
path = tmp_path / "custom.env"
|
|
path.write_text("PHOTO_PIPELINE_PORT=9123\n")
|
|
monkeypatch.delenv("PHOTO_PIPELINE_PORT", raising=False)
|
|
monkeypatch.setenv("PHOTO_PIPELINE_ENV_FILE", str(path))
|
|
monkeypatch.chdir(tmp_path) # no ./.env here, so only the variable can find it
|
|
|
|
assert Config.from_env().port == 9123
|
|
|
|
|
|
def test_a_missing_file_is_not_an_error(tmp_path):
|
|
assert load_env_file(tmp_path / "nothing-here.env") == {}
|