Files
agarzon-ComfyUI-Imagent/tests/test_client.py
T
Alexander Garzon 6d3d2fca46 feat: initial public release of ComfyUI-Imagent
BYOK OpenAI gpt-image generation and editing nodes for ComfyUI — calls go
directly to the OpenAI API with your own key (no proxy, no credit markup).

- Two nodes: "Imagent: OpenAI Image" (text-to-image) and "Imagent: OpenAI
  Image Edit" (edit / inpaint / multi-reference compose).
- Models gpt-image-2 / gpt-image-1.5 / gpt-image-1 with a per-model dynamic UI
  (comfy_api DynamicCombo): size, background, custom WxH, and input_fidelity
  are revealed only for the models that support them.
- Edit node accepts an auto-growing set of reference images (up to 16) plus an
  optional inpaint mask; generate supports batches up to 8.
- API key via OPENAI_API_KEY or a local config.json.

Requires ComfyUI >= 0.23.0.
2026-06-08 09:39:21 -04:00

73 lines
2.7 KiB
Python

import json
import imagent.client as client
def test_env_var_takes_precedence(monkeypatch, tmp_path):
monkeypatch.setenv("OPENAI_API_KEY", "sk-from-env")
monkeypatch.setattr(client, "_CONFIG_PATH", tmp_path / "config.json")
(tmp_path / "config.json").write_text(json.dumps({"OPENAI_API_KEY": "sk-from-file"}))
assert client.resolve_api_key() == "sk-from-env"
def test_config_file_fallback(monkeypatch, tmp_path):
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
cfg = tmp_path / "config.json"
cfg.write_text(json.dumps({"OPENAI_API_KEY": "sk-from-file"}))
monkeypatch.setattr(client, "_CONFIG_PATH", cfg)
assert client.resolve_api_key() == "sk-from-file"
def test_missing_key_returns_none(monkeypatch, tmp_path):
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
monkeypatch.setattr(client, "_CONFIG_PATH", tmp_path / "nope.json")
assert client.resolve_api_key() is None
def test_placeholder_key_is_ignored(monkeypatch, tmp_path):
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
cfg = tmp_path / "config.json"
cfg.write_text(json.dumps({"OPENAI_API_KEY": "sk-..."}))
monkeypatch.setattr(client, "_CONFIG_PATH", cfg)
assert client.resolve_api_key() is None
def test_model_catalog_defaults():
assert client.DEFAULT_MODEL == "gpt-image-2"
assert set(client.MODELS) == {"gpt-image-1", "gpt-image-1.5", "gpt-image-2"}
assert "gpt-image-1-mini" not in client.MODELS
assert "gpt-image-2-2026-04-21" not in client.MODELS
assert all("dall-e" not in m for m in client.MODELS)
def test_friendly_error_maps_403_and_429():
assert "verif" in client.friendly_error(Exception("Error code: 403 - org not verified")).lower()
assert "rate" in client.friendly_error(Exception("Error code: 429 - too many requests")).lower()
def test_malformed_config_returns_none(monkeypatch, tmp_path, caplog):
import logging
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
cfg = tmp_path / "config.json"
cfg.write_text("{bad json")
monkeypatch.setattr(client, "_CONFIG_PATH", cfg)
with caplog.at_level(logging.WARNING, logger="imagent"):
assert client.resolve_api_key() is None
assert "could not read" in caplog.text
def test_env_placeholder_is_ignored(monkeypatch, tmp_path):
monkeypatch.setenv("OPENAI_API_KEY", "your_openai_api_key_here")
monkeypatch.setattr(client, "_CONFIG_PATH", tmp_path / "nope.json")
assert client.resolve_api_key() is None
def test_friendly_error_uses_status_code():
class FakeAPIError(Exception):
status_code = 403
class FakeRateError(Exception):
status_code = 429
assert "verif" in client.friendly_error(FakeAPIError("denied")).lower()
assert "rate" in client.friendly_error(FakeRateError("slow down")).lower()