mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-07 08:02:23 +00:00
chore: ruff auto-fix PLR6201 resweep — tuple → set in membership tests (#27355)
Six days after #23937 (608 fixes) the codebase had accumulated 241 new PLR6201 violations. Same mechanical `x in (...)` → `x in {...}` fix, same zero-risk profile: set lookup is O(1) vs O(n) for tuple and the two are semantically equivalent for hashable scalar membership tests. All 241 instances fixed via `ruff check --select PLR6201 --fix --unsafe-fixes`, zero remaining. Every changed value is a hashable scalar (str/int/None/enum/signal); no risk of unhashable runtime errors. No behavior change. Test plan: - 119 files changed, +244/-244 (net zero) — exactly one-line edits - `ruff check` clean afterward - Compile checks pass on the largest touched files (cli.py, run_agent.py, gateway/run.py, gateway/platforms/discord.py, model_tools.py) - Subset broad test run on tests/gateway/ tests/hermes_cli/ tests/agent/ tests/tools/: 18187 passed, 59 pre-existing failures (verified against origin/main with the same shape — identical failure count, identical category — all xdist test-order flakes unrelated to this change) Follows the same template as PR #23937 ([tracker: #23972](https://github.com/NousResearch/hermes-agent/issues/23972)).
This commit is contained in:
parent
ad00777f04
commit
5fba236644
119 changed files with 244 additions and 244 deletions
|
|
@ -91,7 +91,7 @@ def main():
|
|||
if msg.get("method") == "workspace/didChangeWatchedFiles":
|
||||
continue
|
||||
|
||||
if msg.get("method") in ("textDocument/didOpen", "textDocument/didChange"):
|
||||
if msg.get("method") in {"textDocument/didOpen", "textDocument/didChange"}:
|
||||
params = msg.get("params") or {}
|
||||
td = params.get("textDocument") or {}
|
||||
uri = td.get("uri", "")
|
||||
|
|
|
|||
|
|
@ -87,10 +87,10 @@ def test_install_npm_works_without_extras(tmp_path, monkeypatch):
|
|||
cmd = captured["cmd"]
|
||||
assert "pyright" in cmd
|
||||
# Should not blow up when extra_pkgs is omitted/None
|
||||
install_targets = [c for c in cmd if not c.startswith("-") and c not in (
|
||||
install_targets = [c for c in cmd if not c.startswith("-") and c not in {
|
||||
"install", "--prefix", str(install_mod.hermes_lsp_bin_dir().parent),
|
||||
"/usr/bin/npm",
|
||||
)]
|
||||
}]
|
||||
assert install_targets == ["pyright"]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1658,7 +1658,7 @@ class TestThinkingBlockSignatureManagement:
|
|||
_, result = convert_messages_to_anthropic(messages)
|
||||
assistant = next(m for m in result if m["role"] == "assistant")
|
||||
for block in assistant["content"]:
|
||||
if block.get("type") in ("thinking", "redacted_thinking"):
|
||||
if block.get("type") in {"thinking", "redacted_thinking"}:
|
||||
assert "cache_control" not in block
|
||||
|
||||
def test_thinking_stripped_from_merged_consecutive_assistants(self):
|
||||
|
|
@ -1748,7 +1748,7 @@ class TestThinkingBlockSignatureManagement:
|
|||
# First two: no thinking blocks
|
||||
for a in assistants[:2]:
|
||||
assert not any(
|
||||
b.get("type") in ("thinking", "redacted_thinking")
|
||||
b.get("type") in {"thinking", "redacted_thinking"}
|
||||
for b in a["content"]
|
||||
if isinstance(b, dict)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ class TestResolveVisionMainFirst:
|
|||
provider, client, model = resolve_vision_provider_client()
|
||||
|
||||
assert client is fallback_client
|
||||
assert provider in ("openrouter", "nous")
|
||||
assert provider in {"openrouter", "nous"}
|
||||
|
||||
def test_explicit_provider_override_still_wins(self):
|
||||
"""Explicit config override bypasses main-first policy."""
|
||||
|
|
|
|||
|
|
@ -1046,7 +1046,7 @@ class TestCompressWithClient:
|
|||
for i in range(1, len(result)):
|
||||
r1 = result[i - 1].get("role")
|
||||
r2 = result[i].get("role")
|
||||
if r1 in ("user", "assistant") and r2 in ("user", "assistant"):
|
||||
if r1 in {"user", "assistant"} and r2 in {"user", "assistant"}:
|
||||
assert r1 != r2, f"consecutive {r1} at indices {i-1},{i}"
|
||||
|
||||
def test_double_collision_merges_summary_into_tail(self):
|
||||
|
|
@ -1087,7 +1087,7 @@ class TestCompressWithClient:
|
|||
for i in range(1, len(result)):
|
||||
r1 = result[i - 1].get("role")
|
||||
r2 = result[i].get("role")
|
||||
if r1 in ("user", "assistant") and r2 in ("user", "assistant"):
|
||||
if r1 in {"user", "assistant"} and r2 in {"user", "assistant"}:
|
||||
assert r1 != r2, f"consecutive {r1} at indices {i-1},{i}"
|
||||
|
||||
# The summary text should be merged into the first tail message
|
||||
|
|
@ -1164,7 +1164,7 @@ class TestCompressWithClient:
|
|||
for i in range(1, len(result)):
|
||||
r1 = result[i - 1].get("role")
|
||||
r2 = result[i].get("role")
|
||||
if r1 in ("user", "assistant") and r2 in ("user", "assistant"):
|
||||
if r1 in {"user", "assistant"} and r2 in {"user", "assistant"}:
|
||||
assert r1 != r2, f"consecutive {r1} at indices {i-1},{i}"
|
||||
|
||||
# The summary should be merged into the first tail message (assistant at index 5)
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ class TestDeepSeekAnthropicPreservesThinking:
|
|||
if not isinstance(m.get("content"), list):
|
||||
continue
|
||||
for b in m["content"]:
|
||||
if isinstance(b, dict) and b.get("type") in ("thinking", "redacted_thinking"):
|
||||
if isinstance(b, dict) and b.get("type") in {"thinking", "redacted_thinking"}:
|
||||
assert "cache_control" not in b
|
||||
|
||||
def test_openai_compat_deepseek_base_is_not_matched(self) -> None:
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class TestVerboseAndToolProgress:
|
|||
def test_tool_progress_mode_is_string(self):
|
||||
cli = _make_cli()
|
||||
assert isinstance(cli.tool_progress_mode, str)
|
||||
assert cli.tool_progress_mode in ("off", "new", "all", "verbose")
|
||||
assert cli.tool_progress_mode in {"off", "new", "all", "verbose"}
|
||||
|
||||
|
||||
class TestBusyInputMode:
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class TestHandleReasoningCommand(unittest.TestCase):
|
|||
stub = self._make_cli(show_reasoning=False)
|
||||
# Simulate /reasoning show
|
||||
arg = "show"
|
||||
if arg in ("show", "on"):
|
||||
if arg in {"show", "on"}:
|
||||
stub.show_reasoning = True
|
||||
stub.agent.reasoning_callback = lambda x: None
|
||||
self.assertTrue(stub.show_reasoning)
|
||||
|
|
@ -79,7 +79,7 @@ class TestHandleReasoningCommand(unittest.TestCase):
|
|||
stub = self._make_cli(show_reasoning=True)
|
||||
# Simulate /reasoning hide
|
||||
arg = "hide"
|
||||
if arg in ("hide", "off"):
|
||||
if arg in {"hide", "off"}:
|
||||
stub.show_reasoning = False
|
||||
stub.agent.reasoning_callback = None
|
||||
self.assertFalse(stub.show_reasoning)
|
||||
|
|
@ -88,14 +88,14 @@ class TestHandleReasoningCommand(unittest.TestCase):
|
|||
def test_on_enables_display(self):
|
||||
stub = self._make_cli(show_reasoning=False)
|
||||
arg = "on"
|
||||
if arg in ("show", "on"):
|
||||
if arg in {"show", "on"}:
|
||||
stub.show_reasoning = True
|
||||
self.assertTrue(stub.show_reasoning)
|
||||
|
||||
def test_off_disables_display(self):
|
||||
stub = self._make_cli(show_reasoning=True)
|
||||
arg = "off"
|
||||
if arg in ("hide", "off"):
|
||||
if arg in {"hide", "off"}:
|
||||
stub.show_reasoning = False
|
||||
self.assertFalse(stub.show_reasoning)
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ def test_create_job_no_agent_stores_field(hermes_env):
|
|||
assert job["no_agent"] is True
|
||||
assert job["script"] == "watchdog.sh"
|
||||
# Prompt can be empty/None for no_agent jobs.
|
||||
assert job["prompt"] in (None, "")
|
||||
assert job["prompt"] in {None, ""}
|
||||
|
||||
|
||||
def test_create_job_default_is_not_no_agent(hermes_env):
|
||||
|
|
@ -148,7 +148,7 @@ def test_cronjob_tool_update_toggles_no_agent(hermes_env):
|
|||
|
||||
off = json.loads(cronjob(action="update", job_id=job_id, no_agent=False, prompt="run"))
|
||||
assert off["success"] is True
|
||||
assert off["job"].get("no_agent") in (False, None)
|
||||
assert off["job"].get("no_agent") in {False, None}
|
||||
|
||||
on = json.loads(cronjob(action="update", job_id=job_id, no_agent=True))
|
||||
assert on["success"] is True
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ def _scan_for_plugin_adapter_antipattern(source: str) -> list[str]:
|
|||
and isinstance(func.value.value, ast.Name)
|
||||
and func.value.value.id == "sys"
|
||||
and func.value.attr == "path"
|
||||
and func.attr in ("insert", "append", "extend")
|
||||
and func.attr in {"insert", "append", "extend"}
|
||||
):
|
||||
target_name = f"sys.path.{func.attr}"
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ def _would_warn():
|
|||
"MATRIX_ALLOWED_USERS", "DINGTALK_ALLOWED_USERS", "FEISHU_ALLOWED_USERS", "WECOM_ALLOWED_USERS",
|
||||
"GATEWAY_ALLOWED_USERS")
|
||||
)
|
||||
_allow_all = os.getenv("GATEWAY_ALLOW_ALL_USERS", "").lower() in ("true", "1", "yes") or any(
|
||||
os.getenv(v, "").lower() in ("true", "1", "yes")
|
||||
_allow_all = os.getenv("GATEWAY_ALLOW_ALL_USERS", "").lower() in {"true", "1", "yes"} or any(
|
||||
os.getenv(v, "").lower() in {"true", "1", "yes"}
|
||||
for v in ("TELEGRAM_ALLOW_ALL_USERS", "DISCORD_ALLOW_ALL_USERS",
|
||||
"WHATSAPP_ALLOW_ALL_USERS", "SLACK_ALLOW_ALL_USERS",
|
||||
"SIGNAL_ALLOW_ALL_USERS", "EMAIL_ALLOW_ALL_USERS",
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ def _simulate_config_bridge(cfg: dict, initial_env: dict | None = None):
|
|||
val = terminal_cfg[cfg_key]
|
||||
# Skip cwd placeholder values — don't overwrite already-resolved
|
||||
# TERMINAL_CWD. Mirrors the fix in gateway/run.py.
|
||||
if cfg_key == "cwd" and str(val) in (".", "auto", "cwd"):
|
||||
if cfg_key == "cwd" and str(val) in {".", "auto", "cwd"}:
|
||||
continue
|
||||
# Expand shell tilde so subprocess.Popen never receives a literal
|
||||
# "~/" which the kernel rejects.
|
||||
|
|
@ -70,7 +70,7 @@ def _simulate_config_bridge(cfg: dict, initial_env: dict | None = None):
|
|||
|
||||
# --- Replicate lines 144-147: MESSAGING_CWD fallback ---
|
||||
configured_cwd = env.get("TERMINAL_CWD", "")
|
||||
if not configured_cwd or configured_cwd in (".", "auto", "cwd"):
|
||||
if not configured_cwd or configured_cwd in {".", "auto", "cwd"}:
|
||||
messaging_cwd = env.get("MESSAGING_CWD") or "/root" # Path.home() for root
|
||||
env["TERMINAL_CWD"] = messaging_cwd
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class TestDiscordSystemMessageFilter(unittest.TestCase):
|
|||
return False
|
||||
|
||||
# System message filter (the fix being tested)
|
||||
if message.type not in (discord.MessageType.default, discord.MessageType.reply):
|
||||
if message.type not in {discord.MessageType.default, discord.MessageType.reply}:
|
||||
return False
|
||||
|
||||
return True # message accepted
|
||||
|
|
|
|||
|
|
@ -76,12 +76,12 @@ def test_checker_returns_true_when_configured(platform, checker, monkeypatch):
|
|||
elif platform == Platform.SMS:
|
||||
monkeypatch.setenv("TWILIO_ACCOUNT_SID", "ACtest")
|
||||
mock_config.extra = {}
|
||||
elif platform in (
|
||||
elif platform in {
|
||||
Platform.API_SERVER,
|
||||
Platform.WEBHOOK,
|
||||
Platform.MSGRAPH_WEBHOOK,
|
||||
Platform.WHATSAPP,
|
||||
):
|
||||
}:
|
||||
mock_config.extra = {}
|
||||
elif platform == Platform.FEISHU:
|
||||
mock_config.extra = {"app_id": "app"}
|
||||
|
|
|
|||
|
|
@ -1076,7 +1076,7 @@ class TestBuildApprovalKeyboard:
|
|||
parsed = parse_approval_button_data(btn.action.data)
|
||||
assert parsed is not None
|
||||
assert parsed[0] == session_key
|
||||
assert parsed[1] in ("allow-once", "allow-always", "deny")
|
||||
assert parsed[1] in {"allow-once", "allow-always", "deny"}
|
||||
|
||||
|
||||
class TestBuildUpdatePromptKeyboard:
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ def _build_agent_history(history: list) -> list:
|
|||
agent_history: list = []
|
||||
for msg in history:
|
||||
role = msg.get("role")
|
||||
if not role or role in ("session_meta", "system"):
|
||||
if not role or role in {"session_meta", "system"}:
|
||||
continue
|
||||
has_tool_calls = "tool_calls" in msg
|
||||
has_tool_call_id = "tool_call_id" in msg
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ async def test_finalize_before_reset(mock_invoke_hook):
|
|||
await runner._handle_reset_command(_make_event("/new"))
|
||||
|
||||
calls = [c for c in mock_invoke_hook.call_args_list
|
||||
if c[0][0] in ("on_session_finalize", "on_session_reset")]
|
||||
if c[0][0] in {"on_session_finalize", "on_session_reset"}]
|
||||
hook_names = [c[0][0] for c in calls]
|
||||
assert hook_names == ["on_session_finalize", "on_session_reset"]
|
||||
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ fallback_providers:
|
|||
monkeypatch.setattr(gateway_run, "_hermes_home", tmp_path)
|
||||
|
||||
def fake_resolve_runtime_provider(*, requested=None, explicit_base_url=None, explicit_api_key=None):
|
||||
if requested in (None, "", "openai-codex"):
|
||||
if requested in {None, "", "openai-codex"}:
|
||||
from hermes_cli.auth import AuthError
|
||||
raise AuthError("No Codex credentials stored. Run `hermes auth` to authenticate.")
|
||||
assert requested == "openrouter"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ def _filter_history(history: list) -> list:
|
|||
role = msg.get("role")
|
||||
if not role:
|
||||
continue
|
||||
if role in ("session_meta",):
|
||||
if role in {"session_meta",}:
|
||||
continue
|
||||
if role == "system":
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -555,7 +555,7 @@ class TestLoginNousSkipKeepsCurrent:
|
|||
auth_path = hermes_home / "auth.json"
|
||||
auth_after = json.loads(auth_path.read_text())
|
||||
# active_provider should NOT be set to "nous" after Skip
|
||||
assert auth_after.get("active_provider") in (None, "")
|
||||
assert auth_after.get("active_provider") in {None, ""}
|
||||
# But Nous creds are still saved
|
||||
assert "nous" in auth_after.get("providers", {})
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ class TestCmdUpdateBranchFallback:
|
|||
if call.args
|
||||
and call.args[0][0] == "/usr/bin/npm"
|
||||
and call.args[0][1] == "ci"
|
||||
and call.kwargs.get("cwd") in (PROJECT_ROOT, PROJECT_ROOT / "ui-tui")
|
||||
and call.kwargs.get("cwd") in {PROJECT_ROOT, PROJECT_ROOT / "ui-tui"}
|
||||
]
|
||||
assert len(repo_and_tui_calls) == 2
|
||||
for call in repo_and_tui_calls:
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class TestApply:
|
|||
assert "Cannot enable" in r.message
|
||||
assert "npm i -g @openai/codex" in r.message
|
||||
# Config NOT mutated on failure
|
||||
assert cfg.get("model", {}).get("openai_runtime") in (None, "")
|
||||
assert cfg.get("model", {}).get("openai_runtime") in {None, ""}
|
||||
|
||||
def test_enable_succeeds_when_codex_present(self):
|
||||
cfg = {}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class TestInstallCuaDriverUpgrade:
|
|||
with patch("platform.system", return_value="Darwin"), \
|
||||
patch.object(tools_config.shutil, "which",
|
||||
side_effect=lambda n: "/usr/local/bin/" + n
|
||||
if n in ("cua-driver", "curl") else None), \
|
||||
if n in {"cua-driver", "curl"} else None), \
|
||||
patch.object(tools_config, "_run_cua_driver_installer",
|
||||
return_value=True) as runner, \
|
||||
patch("subprocess.run"):
|
||||
|
|
@ -82,7 +82,7 @@ class TestInstallCuaDriverUpgrade:
|
|||
with patch("platform.system", return_value="Darwin"), \
|
||||
patch.object(tools_config.shutil, "which",
|
||||
side_effect=lambda n: "/usr/local/bin/" + n
|
||||
if n in ("cua-driver", "curl") else None), \
|
||||
if n in {"cua-driver", "curl"} else None), \
|
||||
patch.object(tools_config, "_run_cua_driver_installer") as runner, \
|
||||
patch("subprocess.run"):
|
||||
assert tools_config.install_cua_driver(upgrade=False) is True
|
||||
|
|
|
|||
|
|
@ -1046,7 +1046,7 @@ def test_enforce_max_runtime_integrates_with_dispatch(kanban_home, monkeypatch):
|
|||
task = kb.get_task(conn, tid)
|
||||
# After timeout, task is back in 'ready' and will be re-spawned
|
||||
# by the same pass. That's the intended behaviour.
|
||||
assert task.status in ("ready", "running")
|
||||
assert task.status in {"ready", "running"}
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ def _run_memory_reset(target="all", yes=False, monkeypatch=None, confirm_input="
|
|||
|
||||
mem_dir = get_hermes_home() / "memories"
|
||||
files_to_reset = []
|
||||
if target in ("all", "memory"):
|
||||
if target in {"all", "memory"}:
|
||||
files_to_reset.append(("MEMORY.md", "agent notes"))
|
||||
if target in ("all", "user"):
|
||||
if target in {"all", "user"}:
|
||||
files_to_reset.append(("USER.md", "user profile"))
|
||||
|
||||
existing = [(f, desc) for f, desc in files_to_reset if (mem_dir / f).exists()]
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ class TestDetectProviderForModel:
|
|||
result = detect_provider_for_model("deepseek-chat", "openai-codex")
|
||||
assert result is not None
|
||||
# Provider is deepseek (direct) or openrouter (fallback) depending on creds
|
||||
assert result[0] in ("deepseek", "openrouter")
|
||||
assert result[0] in {"deepseek", "openrouter"}
|
||||
|
||||
def test_current_provider_model_returns_none(self):
|
||||
"""Models belonging to the current provider should not trigger a switch."""
|
||||
|
|
@ -302,7 +302,7 @@ class TestDetectProviderForModel:
|
|||
with patch("hermes_cli.models.fetch_openrouter_models", return_value=LIVE_OPENROUTER_MODELS):
|
||||
result = detect_provider_for_model("claude-opus-4-6", "openai-codex")
|
||||
assert result is not None
|
||||
assert result[0] not in ("nous",) # nous has claude models but shouldn't be suggested
|
||||
assert result[0] not in {"nous",} # nous has claude models but shouldn't be suggested
|
||||
|
||||
|
||||
class TestIsNousFreeTier:
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ def test_opencode_go_appears_when_api_key_set():
|
|||
# opencode-go can appear as "built-in" (from PROVIDER_TO_MODELS_DEV when
|
||||
# models.dev is reachable) or "hermes" (from HERMES_OVERLAYS fallback when
|
||||
# the API is unavailable, e.g. in CI).
|
||||
assert opencode_go["source"] in ("built-in", "hermes")
|
||||
assert opencode_go["source"] in {"built-in", "hermes"}
|
||||
|
||||
|
||||
def test_opencode_go_not_appears_when_no_creds():
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ class TestKillStaleDashboardPosix:
|
|||
sent.append((pid, sig))
|
||||
# Simulate stubborn process: probe (sig 0) always succeeds,
|
||||
# SIGTERM does nothing, SIGKILL is where it "dies".
|
||||
if sig in (_signal.SIGTERM, 0, _signal.SIGKILL):
|
||||
if sig in {_signal.SIGTERM, 0, _signal.SIGKILL}:
|
||||
return
|
||||
# Any other signal — also fine.
|
||||
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ class TestWebServerEndpoints:
|
|||
resp = self.client.get("/api/auth/session-token")
|
||||
# The endpoint is gone — the catch-all SPA route serves index.html
|
||||
# or the middleware returns 401 for unauthenticated /api/ paths.
|
||||
assert resp.status_code in (200, 404)
|
||||
assert resp.status_code in {200, 404}
|
||||
# Either way, it must NOT return the token as JSON
|
||||
try:
|
||||
data = resp.json()
|
||||
|
|
@ -333,7 +333,7 @@ class TestWebServerEndpoints:
|
|||
# %2e%2e = ..
|
||||
resp = self.client.get("/%2e%2e/%2e%2e/etc/passwd")
|
||||
# Should return 200 with index.html (SPA fallback), not the actual file
|
||||
assert resp.status_code in (200, 404)
|
||||
assert resp.status_code in {200, 404}
|
||||
if resp.status_code == 200:
|
||||
# Should be the SPA fallback, not the system file
|
||||
assert "root:" not in resp.text
|
||||
|
|
@ -341,7 +341,7 @@ class TestWebServerEndpoints:
|
|||
def test_path_traversal_dotdot_blocked(self):
|
||||
"""Direct .. path traversal via encoded sequences."""
|
||||
resp = self.client.get("/%2e%2e/hermes_cli/web_server.py")
|
||||
assert resp.status_code in (200, 404)
|
||||
assert resp.status_code in {200, 404}
|
||||
if resp.status_code == 200:
|
||||
assert "FastAPI" not in resp.text # Should not serve the actual source
|
||||
|
||||
|
|
@ -535,7 +535,7 @@ class TestConfigRoundTrip:
|
|||
if val is None:
|
||||
continue # not set in user config — fine
|
||||
expected = entry["type"]
|
||||
if expected in ("string", "select") and not isinstance(val, str):
|
||||
if expected in {"string", "select"} and not isinstance(val, str):
|
||||
mismatches.append(f"{key}: expected str, got {type(val).__name__}")
|
||||
elif expected == "number" and not isinstance(val, (int, float)):
|
||||
mismatches.append(f"{key}: expected number, got {type(val).__name__}")
|
||||
|
|
@ -1032,7 +1032,7 @@ class TestNewEndpoints:
|
|||
"""GET /api/auth/session-token no longer exists."""
|
||||
resp = self.client.get("/api/auth/session-token")
|
||||
# Should not return a JSON token object
|
||||
assert resp.status_code in (200, 404)
|
||||
assert resp.status_code in {200, 404}
|
||||
try:
|
||||
data = resp.json()
|
||||
assert "token" not in data
|
||||
|
|
|
|||
|
|
@ -1570,7 +1570,7 @@ class TestDialecticLifecycleSmoke:
|
|||
self._await_thread(provider)
|
||||
assert mgr.dialectic_query.call_count == 2, "turn 4 cadence fire"
|
||||
_, kwargs = mgr.dialectic_query.call_args
|
||||
assert kwargs.get("reasoning_level") in ("medium", "high"), \
|
||||
assert kwargs.get("reasoning_level") in {"medium", "high"}, \
|
||||
f"long query must bump reasoning level above 'low'; got {kwargs.get('reasoning_level')}"
|
||||
assert provider._last_dialectic_turn == 4, "cadence tracker advances on success"
|
||||
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ def test_evaluate_all_force_runs_synchronously(plugin_api):
|
|||
|
||||
# Synchronous — snapshot is fresh on return.
|
||||
assert result["scan_meta"].get("sessions_total") == 25
|
||||
assert result["scan_meta"]["mode"] in ("full", "incremental")
|
||||
assert result["scan_meta"]["mode"] in {"full", "incremental"}
|
||||
|
||||
|
||||
def test_start_background_scan_is_idempotent_while_running(plugin_api):
|
||||
|
|
|
|||
|
|
@ -110,4 +110,4 @@ def test_xai_no_operation_kwarg():
|
|||
result = XAIVideoGenProvider().generate("x", operation="generate")
|
||||
assert result["success"] is False
|
||||
# auth_required, NOT some signature error
|
||||
assert result["error_type"] in ("auth_required", "api_error")
|
||||
assert result["error_type"] in {"auth_required", "api_error"}
|
||||
|
|
|
|||
|
|
@ -106,9 +106,9 @@ class TestContinuationLogicBranching:
|
|||
def test_all_three_api_modes_hit_continuation_branch(self, api_mode):
|
||||
# The guard in run_agent.py is:
|
||||
# if self.api_mode in ("chat_completions", "bedrock_converse", "anthropic_messages"):
|
||||
assert api_mode in ("chat_completions", "bedrock_converse", "anthropic_messages")
|
||||
assert api_mode in {"chat_completions", "bedrock_converse", "anthropic_messages"}
|
||||
|
||||
def test_codex_responses_still_excluded(self):
|
||||
# codex_responses has its own truncation path (not continuation-based)
|
||||
# and should NOT be routed through the shared block.
|
||||
assert "codex_responses" not in ("chat_completions", "bedrock_converse", "anthropic_messages")
|
||||
assert "codex_responses" not in {"chat_completions", "bedrock_converse", "anthropic_messages"}
|
||||
|
|
|
|||
|
|
@ -846,7 +846,7 @@ def test_skill_installs_cleanly_under_skills_guard():
|
|||
# the script never writes to that file
|
||||
#
|
||||
# Accept "caution" or "safe" — just not "dangerous" from a *real* threat.
|
||||
assert result.verdict in ("safe", "caution", "dangerous"), f"Unexpected verdict: {result.verdict}"
|
||||
assert result.verdict in {"safe", "caution", "dangerous"}, f"Unexpected verdict: {result.verdict}"
|
||||
KNOWN_FALSE_POSITIVES = {"agent_config_mod", "python_os_environ", "hermes_config_mod"}
|
||||
for f in result.findings:
|
||||
assert f.pattern_id in KNOWN_FALSE_POSITIVES, f"Unexpected finding: {f}"
|
||||
|
|
|
|||
|
|
@ -902,7 +902,7 @@ def _(home, kb):
|
|||
pass
|
||||
# Empty body → accept (legitimate: just title says it all)
|
||||
tid = kb.create_task(conn, title="empty body ok", body="", assignee="w")
|
||||
assert kb.get_task(conn, tid).body in ("", None)
|
||||
assert kb.get_task(conn, tid).body in {"", None}
|
||||
# Empty summary on complete → accept
|
||||
kb.claim_task(conn, tid)
|
||||
kb.complete_task(conn, tid, summary="")
|
||||
|
|
@ -994,7 +994,7 @@ def _(home, kb):
|
|||
|
||||
# Empty title
|
||||
r = client.post("/api/plugins/kanban/tasks", json={"title": ""})
|
||||
assert r.status_code in (400, 422), f"empty title should 4xx, got {r.status_code}"
|
||||
assert r.status_code in {400, 422}, f"empty title should 4xx, got {r.status_code}"
|
||||
|
||||
# Title only
|
||||
r = client.post("/api/plugins/kanban/tasks", json={"title": "x"})
|
||||
|
|
@ -1019,7 +1019,7 @@ def _(home, kb):
|
|||
r = client.post("/api/plugins/kanban/tasks", json={
|
||||
"title": "fine", "nonexistent_field": "whatever",
|
||||
})
|
||||
assert r.status_code in (200, 422)
|
||||
assert r.status_code in {200, 422}
|
||||
|
||||
# Priority as non-int
|
||||
r = client.post("/api/plugins/kanban/tasks", json={"title": "prio", "priority": "high"})
|
||||
|
|
@ -1028,7 +1028,7 @@ def _(home, kb):
|
|||
# PATCH with empty body (no changes requested)
|
||||
r = client.patch(f"/api/plugins/kanban/tasks/{tid}", json={})
|
||||
# Accept either success-no-op or 400
|
||||
assert r.status_code in (200, 400)
|
||||
assert r.status_code in {200, 400}
|
||||
print(" dashboard REST handles weird inputs correctly")
|
||||
|
||||
# =============================================================================
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ def test_kill_own_subtree_passes_through():
|
|||
finally:
|
||||
p.wait(timeout=2)
|
||||
# SIGTERM = 15; subprocess returncode is -15 on POSIX.
|
||||
assert p.returncode in (-signal.SIGTERM, 128 + int(signal.SIGTERM))
|
||||
assert p.returncode in {-signal.SIGTERM, 128 + int(signal.SIGTERM)}
|
||||
|
||||
|
||||
def test_subprocess_pkill_with_unrelated_pattern_passes_through():
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class TestHermesTimeNow:
|
|||
assert result.tzinfo is not None
|
||||
# Offset is -5h or -4h depending on DST
|
||||
offset_hours = result.utcoffset().total_seconds() / 3600
|
||||
assert offset_hours in (-5, -4)
|
||||
assert offset_hours in {-5, -4}
|
||||
|
||||
def test_invalid_timezone_falls_back(self, caplog):
|
||||
"""Invalid timezone logs warning and falls back to server-local."""
|
||||
|
|
|
|||
|
|
@ -3718,7 +3718,7 @@ def test_prompt_submit_preserves_empty_response_without_error(monkeypatch):
|
|||
assert payload.get("status") == "complete"
|
||||
# Text stays empty — we did NOT fabricate an "Error:" string
|
||||
text = payload.get("text", "")
|
||||
assert text in ("", None), f"expected empty text, got {text!r}"
|
||||
assert text in {"", None}, f"expected empty text, got {text!r}"
|
||||
|
||||
|
||||
# ── session.most_recent ──────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -68,10 +68,10 @@ class TestDiscoverHomebrewNodeDirs:
|
|||
if p == "/opt/homebrew/opt":
|
||||
return True
|
||||
# node@20/bin and node@24/bin exist
|
||||
if p in (
|
||||
if p in {
|
||||
"/opt/homebrew/opt/node@20/bin",
|
||||
"/opt/homebrew/opt/node@24/bin",
|
||||
):
|
||||
}:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
@ -171,10 +171,10 @@ class TestFindAgentBrowser:
|
|||
real_isdir = os.path.isdir
|
||||
|
||||
def selective_isdir(path):
|
||||
if path in (
|
||||
if path in {
|
||||
"/data/data/com.termux/files/usr/bin",
|
||||
"/data/data/com.termux/files/usr/sbin",
|
||||
):
|
||||
}:
|
||||
return True
|
||||
return real_isdir(path)
|
||||
|
||||
|
|
@ -486,10 +486,10 @@ class TestRunBrowserCommandPathConstruction:
|
|||
real_isdir = os.path.isdir
|
||||
|
||||
def selective_isdir(path):
|
||||
if path in (
|
||||
if path in {
|
||||
"/data/data/com.termux/files/usr/bin",
|
||||
"/data/data/com.termux/files/usr/sbin",
|
||||
):
|
||||
}:
|
||||
return True
|
||||
if path.startswith(str(tmp_path)):
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class TestResolveChildPython(unittest.TestCase):
|
|||
def test_project_with_no_venv_falls_back(self):
|
||||
"""Project mode without VIRTUAL_ENV or CONDA_PREFIX → sys.executable."""
|
||||
env = {k: v for k, v in os.environ.items()
|
||||
if k not in ("VIRTUAL_ENV", "CONDA_PREFIX")}
|
||||
if k not in {"VIRTUAL_ENV", "CONDA_PREFIX"}}
|
||||
with patch.dict(os.environ, env, clear=True):
|
||||
self.assertEqual(_resolve_child_python("project"), sys.executable)
|
||||
|
||||
|
|
|
|||
|
|
@ -633,7 +633,7 @@ class TestToolsetInclusion:
|
|||
def test_discord_tools_not_in_other_toolsets(self):
|
||||
from toolsets import TOOLSETS
|
||||
for name, ts in TOOLSETS.items():
|
||||
if name in ("hermes-discord", "hermes-gateway", "discord", "discord_admin"):
|
||||
if name in {"hermes-discord", "hermes-gateway", "discord", "discord_admin"}:
|
||||
continue
|
||||
tools = ts.get("tools", [])
|
||||
assert "discord" not in tools or name == "discord", (
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ def _new_filter_matches(path: Path) -> bool:
|
|||
|
||||
Returns True when the path SHOULD be filtered out.
|
||||
"""
|
||||
return any(part in ('.git', '.github', '.hub') for part in path.parts)
|
||||
return any(part in {'.git', '.github', '.hub'} for part in path.parts)
|
||||
|
||||
|
||||
class TestOldFilterBrokenOnWindows:
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ def _restore_tool_and_agent_modules():
|
|||
original_modules = {
|
||||
name: module
|
||||
for name, module in sys.modules.items()
|
||||
if name in ("tools", "agent", "hermes_cli")
|
||||
if name in {"tools", "agent", "hermes_cli"}
|
||||
or name.startswith("tools.")
|
||||
or name.startswith("agent.")
|
||||
or name.startswith("hermes_cli.")
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class TestCancelledErrorPropagation:
|
|||
return "clean_return"
|
||||
|
||||
outcome = asyncio.run(drive())
|
||||
assert outcome in ("cancelled_cleanly", "clean_return"), (
|
||||
assert outcome in {"cancelled_cleanly", "clean_return"}, (
|
||||
f"MCPServerTask.run wedged on cancel (outcome={outcome}) — "
|
||||
f"#9930 regression"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class TestFindSingularityExecutable:
|
|||
def test_prefers_apptainer(self):
|
||||
"""When both are available, apptainer should be preferred."""
|
||||
def which_both(name):
|
||||
return f"/usr/bin/{name}" if name in ("apptainer", "singularity") else None
|
||||
return f"/usr/bin/{name}" if name in {"apptainer", "singularity"} else None
|
||||
|
||||
with patch("shutil.which", side_effect=which_both):
|
||||
assert _find_singularity_executable() == "apptainer"
|
||||
|
|
|
|||
|
|
@ -547,7 +547,7 @@ class TestSkillManageDispatcher:
|
|||
# No provenance marker on a foreground create — record either missing
|
||||
# entirely (telemetry best-effort) or present with created_by unset.
|
||||
rec = usage.get("test-skill") or {}
|
||||
assert rec.get("created_by") in (None, "", False)
|
||||
assert rec.get("created_by") in {None, "", False}
|
||||
|
||||
def test_create_from_background_review_marks_agent_created(self, tmp_path):
|
||||
"""Background-review fork creates ARE marked as agent-created."""
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class TestTrustLevelFor:
|
|||
src = self._source()
|
||||
result = src.trust_level_for("owner/repo")
|
||||
# No path part — still resolves repo correctly
|
||||
assert result in ("trusted", "community")
|
||||
assert result in {"trusted", "community"}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ def _reload_entry_with_env(env_overrides: dict) -> None:
|
|||
_src_root = os.environ.get("HERMES_PYTHON_SRC_ROOT", "")
|
||||
if _src_root and _src_root not in sys.path:
|
||||
sys.path.insert(0, _src_root)
|
||||
sys.path = [p for p in sys.path if p not in ("", ".")]
|
||||
sys.path = [p for p in sys.path if p not in {"", "."}]
|
||||
return sys.path[:]
|
||||
finally:
|
||||
sys.path = original_path
|
||||
|
|
@ -45,7 +45,7 @@ def test_empty_string_and_dot_removed_from_sys_path():
|
|||
assert "." in sys.path
|
||||
|
||||
# Run the entry.py fixup logic directly
|
||||
sys.path = [p for p in sys.path if p not in ("", ".")]
|
||||
sys.path = [p for p in sys.path if p not in {"", "."}]
|
||||
|
||||
assert "" not in sys.path
|
||||
assert "." not in sys.path
|
||||
|
|
@ -61,7 +61,7 @@ def test_hermes_src_root_inserted_at_front():
|
|||
_src_root = os.environ.get("HERMES_PYTHON_SRC_ROOT", "")
|
||||
if _src_root and _src_root not in sys.path:
|
||||
sys.path.insert(0, _src_root)
|
||||
sys.path = [p for p in sys.path if p not in ("", ".")]
|
||||
sys.path = [p for p in sys.path if p not in {"", "."}]
|
||||
|
||||
assert sys.path[0] == fake_root
|
||||
finally:
|
||||
|
|
@ -79,7 +79,7 @@ def test_src_root_not_duplicated_if_already_present():
|
|||
_src_root = os.environ.get("HERMES_PYTHON_SRC_ROOT", "")
|
||||
if _src_root and _src_root not in sys.path:
|
||||
sys.path.insert(0, _src_root)
|
||||
sys.path = [p for p in sys.path if p not in ("", ".")]
|
||||
sys.path = [p for p in sys.path if p not in {"", "."}]
|
||||
|
||||
assert sys.path.count(fake_root) == count_before
|
||||
finally:
|
||||
|
|
@ -95,7 +95,7 @@ def test_no_src_root_env_does_not_crash():
|
|||
_src_root = os.environ.get("HERMES_PYTHON_SRC_ROOT", "")
|
||||
if _src_root and _src_root not in sys.path:
|
||||
sys.path.insert(0, _src_root)
|
||||
sys.path = [p for p in sys.path if p not in ("", ".")]
|
||||
sys.path = [p for p in sys.path if p not in {"", "."}]
|
||||
# No exception raised
|
||||
finally:
|
||||
sys.path = original
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue