fix: improve ccproxy OAuth install hint (#55)
Co-authored-by: Dinos Papakostas <dinospk1999@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,40 @@ def is_ccproxy_available() -> bool:
|
||||
return _ccproxy_exe() is not None
|
||||
|
||||
|
||||
def _is_editable_install() -> bool:
|
||||
"""Return True if EvoScientist was installed in editable/development mode.
|
||||
|
||||
Checks all matching distributions because a stale ``.egg-info`` in the
|
||||
project root can shadow the real ``dist-info`` in site-packages.
|
||||
"""
|
||||
try:
|
||||
import json
|
||||
import importlib.metadata as _meta
|
||||
|
||||
for dist in _meta.distributions():
|
||||
name = dist.metadata.get("Name", "")
|
||||
if name.lower() != "evoscientist":
|
||||
continue
|
||||
direct_url = dist.read_text("direct_url.json")
|
||||
if direct_url is not None:
|
||||
data = json.loads(direct_url)
|
||||
if data.get("dir_info", {}).get("editable", False) is True:
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def _oauth_install_hint() -> str:
|
||||
"""Return the appropriate install command depending on install method."""
|
||||
if _is_editable_install():
|
||||
return (
|
||||
"uv sync --extra oauth "
|
||||
"or pip install -e '.[oauth]'"
|
||||
)
|
||||
return "pip install 'evoscientist[oauth]'"
|
||||
|
||||
|
||||
def _summarize_auth_output(raw: str) -> str:
|
||||
"""Extract key fields from ccproxy auth status output into a one-line summary.
|
||||
|
||||
@@ -356,7 +390,7 @@ def maybe_start_ccproxy(config: EvoScientistConfig) -> subprocess.Popen | None:
|
||||
if not is_ccproxy_available():
|
||||
raise RuntimeError(
|
||||
"ccproxy is required for OAuth mode but not found. "
|
||||
"Install it with: pip install 'evoscientist[oauth]'"
|
||||
f"Install it with: {_oauth_install_hint()}"
|
||||
)
|
||||
|
||||
# Check auth for each provider that uses OAuth
|
||||
|
||||
@@ -334,13 +334,30 @@ class TestMaybeStartCcproxy:
|
||||
mock_anthropic_env.assert_called_once()
|
||||
mock_codex_env.assert_called_once()
|
||||
|
||||
@patch("EvoScientist.ccproxy_manager._is_editable_install", return_value=True)
|
||||
@patch("EvoScientist.ccproxy_manager.is_ccproxy_available", return_value=False)
|
||||
def test_openai_oauth_raises_no_binary(self, mock_avail):
|
||||
def test_openai_oauth_raises_no_binary_editable(self, mock_avail, mock_edit):
|
||||
config = MagicMock()
|
||||
config.anthropic_auth_mode = "api_key"
|
||||
config.openai_auth_mode = "oauth"
|
||||
with pytest.raises(RuntimeError, match="not found"):
|
||||
with pytest.raises(RuntimeError) as exc_info:
|
||||
maybe_start_ccproxy(config)
|
||||
msg = str(exc_info.value)
|
||||
assert "ccproxy is required for OAuth mode but not found" in msg
|
||||
assert "uv sync --extra oauth" in msg
|
||||
assert "pip install -e '.[oauth]'" in msg
|
||||
|
||||
@patch("EvoScientist.ccproxy_manager._is_editable_install", return_value=False)
|
||||
@patch("EvoScientist.ccproxy_manager.is_ccproxy_available", return_value=False)
|
||||
def test_openai_oauth_raises_no_binary_pip(self, mock_avail, mock_edit):
|
||||
config = MagicMock()
|
||||
config.anthropic_auth_mode = "api_key"
|
||||
config.openai_auth_mode = "oauth"
|
||||
with pytest.raises(RuntimeError) as exc_info:
|
||||
maybe_start_ccproxy(config)
|
||||
msg = str(exc_info.value)
|
||||
assert "ccproxy is required for OAuth mode but not found" in msg
|
||||
assert "pip install 'evoscientist[oauth]'" in msg
|
||||
|
||||
@patch(
|
||||
"EvoScientist.ccproxy_manager.check_ccproxy_auth",
|
||||
|
||||
Reference in New Issue
Block a user