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:
kshitij 2026-05-17 02:29:41 -07:00 committed by GitHub
parent ad00777f04
commit 5fba236644
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
119 changed files with 244 additions and 244 deletions

View file

@ -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", "")

View file

@ -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"]

View file

@ -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)
)

View file

@ -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."""

View file

@ -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)

View file

@ -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:

View file

@ -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:

View file

@ -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)

View file

@ -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

View file

@ -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}"

View file

@ -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",

View file

@ -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

View file

@ -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

View file

@ -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"}

View file

@ -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:

View file

@ -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

View file

@ -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"]

View file

@ -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"

View file

@ -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

View file

@ -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", {})

View file

@ -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:

View file

@ -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 = {}

View file

@ -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

View file

@ -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()

View file

@ -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()]

View file

@ -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:

View file

@ -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():

View file

@ -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.

View file

@ -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

View file

@ -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"

View file

@ -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):

View file

@ -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"}

View file

@ -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"}

View file

@ -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}"

View file

@ -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")
# =============================================================================

View file

@ -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():

View file

@ -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."""

View file

@ -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 ──────────────────────────────────────────────

View file

@ -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

View file

@ -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)

View file

@ -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", (

View file

@ -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:

View file

@ -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.")

View file

@ -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"
)

View file

@ -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"

View file

@ -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."""

View file

@ -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"}
# ---------------------------------------------------------------------------

View file

@ -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