Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions src/vectrify/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,20 @@ def determine_provider_and_model(args) -> tuple[str, str]:
elif os.getenv("GEMINI_API_KEY"):
provider = "gemini"
else:
print("CRITICAL: No API key found.", file=sys.stderr)
print(
"Error: no LLM API key found. Set one of OPENAI_API_KEY, "
"ANTHROPIC_API_KEY, or GEMINI_API_KEY in your environment.",
file=sys.stderr,
)
sys.exit(1)
else:
env_var = f"{provider.upper()}_API_KEY"
if not os.getenv(env_var):
print(f"CRITICAL: {env_var} not set.", file=sys.stderr)
print(
f"Error: --provider {provider} was selected but {env_var} is "
f"not set. Export {env_var} or pick a provider whose key is set.",
file=sys.stderr,
)
sys.exit(1)

if not model:
Expand Down Expand Up @@ -115,8 +123,11 @@ def main():
except KeyboardInterrupt:
print("\nSearch interrupted by user. Exiting safely...", file=sys.stderr)
sys.exit(130)
except FileNotFoundError:
print(f"Error: input image not found: {args.image}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"FATAL: {e}", file=sys.stderr)
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)


Expand Down
56 changes: 56 additions & 0 deletions src/vectrify/tests/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import argparse

import pytest

from vectrify.main import determine_provider_and_model

_KEYS = ("OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY")


@pytest.fixture
def clear_keys(monkeypatch):
for key in _KEYS:
monkeypatch.delenv(key, raising=False)


def _args(**kwargs):
defaults = {"provider": "auto", "model": None}
defaults.update(kwargs)
return argparse.Namespace(**defaults)


@pytest.mark.usefixtures("clear_keys")
def test_auto_no_key_errors_and_names_env_vars(capsys):
with pytest.raises(SystemExit) as exc:
determine_provider_and_model(_args())
assert exc.value.code == 1
err = capsys.readouterr().err
assert all(name in err for name in _KEYS)
assert err.startswith("Error:")


@pytest.mark.usefixtures("clear_keys")
def test_explicit_provider_missing_key_names_var(capsys):
with pytest.raises(SystemExit) as exc:
determine_provider_and_model(_args(provider="anthropic"))
assert exc.value.code == 1
err = capsys.readouterr().err
assert "ANTHROPIC_API_KEY" in err
assert err.startswith("Error:")


@pytest.mark.usefixtures("clear_keys")
def test_auto_selects_provider_by_priority(monkeypatch):
monkeypatch.setenv("ANTHROPIC_API_KEY", "x")
monkeypatch.setenv("GEMINI_API_KEY", "y")
provider, model = determine_provider_and_model(_args())
assert provider == "anthropic"
assert model == "claude-4-6-sonnet"


@pytest.mark.usefixtures("clear_keys")
def test_explicit_model_is_preserved(monkeypatch):
monkeypatch.setenv("OPENAI_API_KEY", "x")
provider, model = determine_provider_and_model(_args(model="custom-model"))
assert provider == "openai"
assert model == "custom-model"
Loading