chore: ruff auto-fix PLR6201 — tuple → set in membership tests (#23937)

Replace  with  for all literal-tuple
membership tests. Set lookup is O(1) vs O(n) for tuple — consistent
micro-optimization across the codebase.

608 instances fixed via `ruff --fix --unsafe-fixes`, 0 remaining.
133 files, +626/-626 (net zero).
This commit is contained in:
kshitij 2026-05-11 11:13:25 -07:00 committed by GitHub
parent 8c11710314
commit 2ec8d2b42f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
133 changed files with 626 additions and 626 deletions

View file

@ -47,7 +47,7 @@ def _title_case_slug(value: Optional[str]) -> Optional[str]:
def _parse_dt(value: Any) -> Optional[datetime]:
if value in (None, ""):
if value in {None, ""}:
return None
if isinstance(value, (int, float)):
return datetime.fromtimestamp(float(value), tz=timezone.utc)

View file

@ -1537,7 +1537,7 @@ def convert_messages_to_anthropic(
# downgraded to a spurious text block on the last assistant message.
reasoning_content = m.get("reasoning_content")
_already_has_thinking = any(
isinstance(b, dict) and b.get("type") in ("thinking", "redacted_thinking")
isinstance(b, dict) and b.get("type") in {"thinking", "redacted_thinking"}
for b in blocks
)
if isinstance(reasoning_content, str) and not _already_has_thinking:
@ -1688,7 +1688,7 @@ def convert_messages_to_anthropic(
if isinstance(m["content"], list):
m["content"] = [
b for b in m["content"]
if not (isinstance(b, dict) and b.get("type") in ("thinking", "redacted_thinking"))
if not (isinstance(b, dict) and b.get("type") in {"thinking", "redacted_thinking"})
]
prev_blocks = fixed[-1]["content"]
curr_blocks = m["content"]

View file

@ -175,7 +175,7 @@ def _normalize_aux_provider(provider: Optional[str]) -> str:
# Resolve to the user's actual main provider so named custom providers
# and non-aggregator providers (DeepSeek, Alibaba, etc.) work correctly.
main_prov = (_read_main_provider() or "").strip().lower()
if main_prov and main_prov not in ("auto", "main", ""):
if main_prov and main_prov not in {"auto", "main", ""}:
normalized = main_prov
else:
return "custom"
@ -578,7 +578,7 @@ def _convert_content_for_responses(content: Any) -> Any:
if detail:
entry["detail"] = detail
converted.append(entry)
elif ptype in ("input_text", "input_image"):
elif ptype in {"input_text", "input_image"}:
# Already in Responses format — pass through
converted.append(part)
else:
@ -798,7 +798,7 @@ class _CodexCompletionsAdapter:
if item_type == "message":
for part in (_item_get(item, "content") or []):
ptype = _item_get(part, "type")
if ptype in ("output_text", "text"):
if ptype in {"output_text", "text"}:
text_parts.append(_item_get(part, "text", ""))
elif item_type == "function_call":
tool_calls_raw.append(SimpleNamespace(
@ -1960,7 +1960,7 @@ def _is_payment_error(exc: Exception) -> bool:
err_lower = str(exc).lower()
# OpenRouter and other providers include "credits" or "afford" in 402 bodies,
# but sometimes wrap them in 429 or other codes.
if status in (402, 429, None):
if status in {402, 429, None}:
if any(kw in err_lower for kw in ("credits", "insufficient funds",
"can only afford", "billing",
"payment required")):
@ -2157,7 +2157,7 @@ def _pool_cache_hint(
if normalized == "auto":
runtime = _normalize_main_runtime(main_runtime)
normalized = _normalize_aux_provider(runtime.get("provider") or _read_main_provider())
if normalized in ("", "auto", "custom"):
if normalized in {"", "auto", "custom"}:
return ""
entry = _peek_pool_entry(normalized)
if entry is None:
@ -2179,7 +2179,7 @@ def _pool_error_context(exc: Exception) -> Dict[str, Any]:
def _recoverable_pool_provider(resolved_provider: str, client: Any) -> Optional[str]:
"""Infer which provider pool can recover the current auxiliary client."""
normalized = _normalize_aux_provider(resolved_provider)
if normalized not in ("", "auto", "custom"):
if normalized not in {"", "auto", "custom"}:
return normalized
base = str(getattr(client, "base_url", "") or "")
if base_url_host_matches(base, "chatgpt.com"):
@ -2496,7 +2496,7 @@ def _resolve_auto(main_runtime: Optional[Dict[str, Any]] = None) -> Tuple[Option
main_provider = runtime_provider or _read_main_provider()
main_model = runtime_model or _read_main_model()
if (main_provider and main_model
and main_provider not in ("auto", "")):
and main_provider not in {"auto", ""}):
resolved_provider = main_provider
explicit_base_url = None
explicit_api_key = None
@ -3157,7 +3157,7 @@ def resolve_provider_client(
return (_to_async_client(client, final_model, is_vision=is_vision) if async_mode
else (client, final_model))
elif pconfig.auth_type in ("oauth_device_code", "oauth_external"):
elif pconfig.auth_type in {"oauth_device_code", "oauth_external"}:
# OAuth providers — route through their specific try functions
if provider == "nous":
return resolve_provider_client("nous", model, async_mode)
@ -3266,7 +3266,7 @@ def get_available_vision_backends() -> List[str]:
available: List[str] = []
# 1. Active provider — if the user configured a provider, try it first.
main_provider = _read_main_provider()
if main_provider and main_provider not in ("auto", ""):
if main_provider and main_provider not in {"auto", ""}:
if main_provider in _VISION_AUTO_PROVIDER_ORDER:
if _strict_vision_backend_available(main_provider):
available.append(main_provider)
@ -3312,7 +3312,7 @@ def resolve_vision_provider_client(
if resolved_base_url:
provider_for_base_override = (
requested if requested and requested not in ("", "auto") else "custom"
requested if requested and requested not in {"", "auto"} else "custom"
)
client, final_model = resolve_provider_client(
provider_for_base_override,
@ -3340,7 +3340,7 @@ def resolve_vision_provider_client(
# 4. Stop
main_provider = _read_main_provider()
main_model = _read_main_model()
if main_provider and main_provider not in ("auto", ""):
if main_provider and main_provider not in {"auto", ""}:
vision_model = _PROVIDER_VISION_MODELS.get(main_provider, main_model)
if main_provider == "nous":
sync_client, default_model = _resolve_strict_vision_backend(
@ -4146,7 +4146,7 @@ def call_llm(
# credentials were found, fail fast instead of silently routing
# through OpenRouter (which causes confusing 404s).
_explicit = (resolved_provider or "").strip().lower()
if _explicit and _explicit not in ("auto", "openrouter", "custom"):
if _explicit and _explicit not in {"auto", "openrouter", "custom"}:
raise RuntimeError(
f"Provider '{_explicit}' is set in config.yaml but no API key "
f"was found. Set the {_explicit.upper()}_API_KEY environment "
@ -4276,7 +4276,7 @@ def call_llm(
# ── Auth refresh retry ───────────────────────────────────────
if (_is_auth_error(first_err)
and resolved_provider not in ("auto", "", None)
and resolved_provider not in {"auto", "", None}
and not client_is_nous):
if _refresh_provider_credentials(resolved_provider):
logger.info(
@ -4359,7 +4359,7 @@ def call_llm(
# Only try alternative providers when the user didn't explicitly
# configure this task's provider. Explicit provider = hard constraint;
# auto (the default) = best-effort fallback chain. (#7559)
is_auto = resolved_provider in ("auto", "", None)
is_auto = resolved_provider in {"auto", "", None}
if should_fallback and is_auto:
if _is_payment_error(first_err):
reason = "payment error"
@ -4515,7 +4515,7 @@ async def async_call_llm(
)
if client is None:
_explicit = (resolved_provider or "").strip().lower()
if _explicit and _explicit not in ("auto", "openrouter", "custom"):
if _explicit and _explicit not in {"auto", "openrouter", "custom"}:
raise RuntimeError(
f"Provider '{_explicit}' is set in config.yaml but no API key "
f"was found. Set the {_explicit.upper()}_API_KEY environment "
@ -4626,7 +4626,7 @@ async def async_call_llm(
# ── Auth refresh retry (mirrors sync call_llm) ───────────────
if (_is_auth_error(first_err)
and resolved_provider not in ("auto", "", None)
and resolved_provider not in {"auto", "", None}
and not client_is_nous):
if _refresh_provider_credentials(resolved_provider):
logger.info(
@ -4688,7 +4688,7 @@ async def async_call_llm(
or _is_connection_error(first_err)
or _is_rate_limit_error(first_err)
)
is_auto = resolved_provider in ("auto", "", None)
is_auto = resolved_provider in {"auto", "", None}
if should_fallback and is_auto:
if _is_payment_error(first_err):
reason = "payment error"

View file

@ -167,7 +167,7 @@ def _strip_image_parts_from_parts(parts: Any) -> Any:
out.append(part)
continue
ptype = part.get("type")
if ptype in ("image", "image_url", "input_image"):
if ptype in {"image", "image_url", "input_image"}:
had_image = True
out.append({"type": "text", "text": "[screenshot removed to save context]"})
else:
@ -274,8 +274,8 @@ def _summarize_tool_result(tool_name: str, tool_args: str, tool_content: str) ->
mode = args.get("mode", "replace")
return f"[patch] {mode} in {path} ({content_len:,} chars result)"
if tool_name in ("browser_navigate", "browser_click", "browser_snapshot",
"browser_type", "browser_scroll", "browser_vision"):
if tool_name in {"browser_navigate", "browser_click", "browser_snapshot",
"browser_type", "browser_scroll", "browser_vision"}:
url = args.get("url", "")
ref = args.get("ref", "")
detail = f" {url}" if url else (f" ref={ref}" if ref else "")
@ -304,7 +304,7 @@ def _summarize_tool_result(tool_name: str, tool_args: str, tool_content: str) ->
code_preview += "..."
return f"[execute_code] `{code_preview}` ({line_count} lines output)"
if tool_name in ("skill_view", "skills_list", "skill_manage"):
if tool_name in {"skill_view", "skills_list", "skill_manage"}:
name = args.get("name", "?")
return f"[{tool_name}] name={name} ({content_len:,} chars)"
@ -979,13 +979,13 @@ The user has requested that this compaction PRIORITISE preserving all informatio
_status = getattr(e, "status_code", None) or getattr(getattr(e, "response", None), "status_code", None)
_err_str = str(e).lower()
_is_model_not_found = (
_status in (404, 503)
_status in {404, 503}
or "model_not_found" in _err_str
or "does not exist" in _err_str
or "no available channel" in _err_str
)
_is_timeout = (
_status in (408, 429, 502, 504)
_status in {408, 429, 502, 504}
or "timeout" in _err_str
)
# Non-JSON / malformed-body responses from misconfigured providers
@ -1479,7 +1479,7 @@ The user has requested that this compaction PRIORITISE preserving all informatio
first_tail_role = messages[compress_end].get("role", "user") if compress_end < n_messages else "user"
# Pick a role that avoids consecutive same-role with both neighbors.
# Priority: avoid colliding with head (already committed), then tail.
if last_head_role in ("assistant", "tool"):
if last_head_role in {"assistant", "tool"}:
summary_role = "user"
else:
summary_role = "assistant"

View file

@ -149,7 +149,7 @@ class PooledCredential:
}
result: Dict[str, Any] = {}
for field_def in fields(self):
if field_def.name in ("provider", "extra"):
if field_def.name in {"provider", "extra"}:
continue
value = getattr(self, field_def.name)
if value is not None or field_def.name in _ALWAYS_EMIT:

View file

@ -83,7 +83,7 @@ class ClassifiedError:
@property
def is_auth(self) -> bool:
return self.reason in (FailoverReason.auth, FailoverReason.auth_permanent)
return self.reason in {FailoverReason.auth, FailoverReason.auth_permanent}
@ -688,10 +688,10 @@ def _classify_by_status(
result_fn=result_fn,
)
if status_code in (500, 502):
if status_code in {500, 502}:
return result_fn(FailoverReason.server_error, retryable=True)
if status_code in (503, 529):
if status_code in {503, 529}:
return result_fn(FailoverReason.overloaded, retryable=True)
# Other 4xx — non-retryable
@ -810,7 +810,7 @@ def _classify_400(
# Responses API (and some providers) use flat body: {"message": "..."}
if not err_body_msg:
err_body_msg = str(body.get("message") or "").strip().lower()
is_generic = len(err_body_msg) < 30 or err_body_msg in ("error", "")
is_generic = len(err_body_msg) < 30 or err_body_msg in {"error", ""}
# Absolute token/message-count thresholds are only a proxy for smaller
# context windows. Large-context sessions can have many messages while
# still being far below their actual token budget.
@ -841,14 +841,14 @@ def _classify_by_error_code(
"""Classify by structured error codes from the response body."""
code_lower = error_code.lower()
if code_lower in ("resource_exhausted", "throttled", "rate_limit_exceeded"):
if code_lower in {"resource_exhausted", "throttled", "rate_limit_exceeded"}:
return result_fn(
FailoverReason.rate_limit,
retryable=True,
should_rotate_credential=True,
)
if code_lower in ("insufficient_quota", "billing_not_active", "payment_required"):
if code_lower in {"insufficient_quota", "billing_not_active", "payment_required"}:
return result_fn(
FailoverReason.billing,
retryable=False,
@ -856,14 +856,14 @@ def _classify_by_error_code(
should_fallback=True,
)
if code_lower in ("model_not_found", "model_not_available", "invalid_model"):
if code_lower in {"model_not_found", "model_not_available", "invalid_model"}:
return result_fn(
FailoverReason.model_not_found,
retryable=False,
should_fallback=True,
)
if code_lower in ("context_length_exceeded", "max_tokens_exceeded"):
if code_lower in {"context_length_exceeded", "max_tokens_exceeded"}:
return result_fn(
FailoverReason.context_overflow,
retryable=True,

View file

@ -77,7 +77,7 @@ def _coerce_content_to_text(content: Any) -> str:
if p.get("type") == "text" and isinstance(p.get("text"), str):
pieces.append(p["text"])
# Multimodal (image_url, etc.) — stub for now; log and skip
elif p.get("type") in ("image_url", "input_audio"):
elif p.get("type") in {"image_url", "input_audio"}:
logger.debug("Dropping multimodal part (not yet supported): %s", p.get("type"))
return "\n".join(pieces)
return str(content)

View file

@ -76,7 +76,7 @@ def _explicit_aux_vision_override(cfg: Optional[Dict[str, Any]]) -> bool:
base_url = str(vision.get("base_url") or "").strip()
# "auto" / "" / blank = not explicit
if provider in ("", "auto") and not model and not base_url:
if provider in {"", "auto"} and not model and not base_url:
return False
return True
@ -163,7 +163,7 @@ def _sniff_mime_from_bytes(raw: bytes) -> Optional[str]:
if raw.startswith(b"\xff\xd8\xff"):
return "image/jpeg"
# GIF87a / GIF89a
if raw[:6] in (b"GIF87a", b"GIF89a"):
if raw[:6] in {b"GIF87a", b"GIF89a"}:
return "image/gif"
# WEBP: "RIFF" .... "WEBP"
if len(raw) >= 12 and raw[:4] == b"RIFF" and raw[8:12] == b"WEBP":
@ -172,9 +172,9 @@ def _sniff_mime_from_bytes(raw: bytes) -> Optional[str]:
if raw.startswith(b"BM"):
return "image/bmp"
# HEIC/HEIF: ftypheic / ftypheix / ftypmif1 / ftypmsf1 etc.
if len(raw) >= 12 and raw[4:8] == b"ftyp" and raw[8:12] in (
if len(raw) >= 12 and raw[4:8] == b"ftyp" and raw[8:12] in {
b"heic", b"heix", b"hevc", b"hevx", b"mif1", b"msf1", b"heim", b"heis",
):
}:
return "image/heic"
return None

View file

@ -470,11 +470,11 @@ class MemoryManager:
accepted = [
p for p in params
if p.kind in (
if p.kind in {
inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.POSITIONAL_OR_KEYWORD,
inspect.Parameter.KEYWORD_ONLY,
)
}
]
if len(accepted) >= 4:
return "positional"

View file

@ -571,7 +571,7 @@ def _extract_pricing(payload: Dict[str, Any]) -> Dict[str, Any]:
pricing: Dict[str, Any] = {}
for target, aliases in alias_map.items():
for alias in aliases:
if alias in normalized and normalized[alias] not in (None, ""):
if alias in normalized and normalized[alias] not in {None, ""}:
pricing[target] = normalized[alias]
break
if pricing:
@ -1423,7 +1423,7 @@ def get_model_context_length(
# (e.g. claude-opus-4.6 is 1M on Anthropic but 128K on GitHub Copilot).
# If provider is generic (openrouter/custom/empty), try to infer from URL.
effective_provider = provider
if not effective_provider or effective_provider in ("openrouter", "custom"):
if not effective_provider or effective_provider in {"openrouter", "custom"}:
if base_url:
inferred = _infer_provider_from_url(base_url)
if inferred:
@ -1433,7 +1433,7 @@ def get_model_context_length(
# This catches account-specific models (e.g. claude-opus-4.6-1m) that
# don't exist in models.dev. For models that ARE in models.dev, this
# returns the provider-enforced limit which is what users can actually use.
if effective_provider in ("copilot", "copilot-acp", "github-copilot"):
if effective_provider in {"copilot", "copilot-acp", "github-copilot"}:
try:
from hermes_cli.models import get_copilot_model_context
ctx = get_copilot_model_context(model, api_key=api_key)
@ -1533,7 +1533,7 @@ def _count_image_tokens(msg: Dict[str, Any], cost_per_image: int) -> int:
if not isinstance(part, dict):
continue
ptype = part.get("type")
if ptype in ("image", "image_url", "input_image"):
if ptype in {"image", "image_url", "input_image"}:
count += 1
stashed = msg.get("_anthropic_content_blocks") if isinstance(msg, dict) else None
if isinstance(stashed, list):
@ -1545,7 +1545,7 @@ def _count_image_tokens(msg: Dict[str, Any], cost_per_image: int) -> int:
inner = content.get("content")
if isinstance(inner, list):
for part in inner:
if isinstance(part, dict) and part.get("type") in ("image", "image_url"):
if isinstance(part, dict) and part.get("type") in {"image", "image_url"}:
count += 1
return count * cost_per_image
@ -1567,7 +1567,7 @@ def _estimate_message_chars(msg: Dict[str, Any]) -> int:
cleaned = []
for part in v:
if isinstance(part, dict):
if part.get("type") in ("image", "image_url", "input_image"):
if part.get("type") in {"image", "image_url", "input_image"}:
cleaned.append({"type": part.get("type"), "image": "[stripped]"})
else:
cleaned.append(part)

View file

@ -122,7 +122,7 @@ def _repair_schema(node: Any, is_schema: bool = True) -> Any:
# empty, drop it entirely.
if "enum" in repaired and isinstance(repaired["enum"], list):
node_type = repaired.get("type")
if node_type in ("string", "integer", "number", "boolean"):
if node_type in {"string", "integer", "number", "boolean"}:
cleaned = [v for v in repaired["enum"]
if v is not None and v != ""]
if cleaned:
@ -135,7 +135,7 @@ def _repair_schema(node: Any, is_schema: bool = True) -> Any:
def _fill_missing_type(node: Dict[str, Any]) -> Dict[str, Any]:
"""Infer a reasonable ``type`` if this schema node has none."""
if "type" in node and node["type"] not in (None, ""):
if "type" in node and node["type"] not in {None, ""}:
return node
# Heuristic: presence of ``properties`` → object, ``items`` → array, ``enum``

View file

@ -64,7 +64,7 @@ _SENSITIVE_BODY_KEYS = frozenset({
# cli.py) or `HERMES_REDACT_SECRETS=false` in ~/.hermes/.env. An opt-out
# warning is logged at gateway and CLI startup so operators see the
# downgrade — see `_log_redaction_status()` in gateway/run.py and cli.py.
_REDACT_ENABLED = os.getenv("HERMES_REDACT_SECRETS", "true").lower() in ("1", "true", "yes", "on")
_REDACT_ENABLED = os.getenv("HERMES_REDACT_SECRETS", "true").lower() in {"1", "true", "yes", "on"}
# Known API key prefixes -- match the prefix + contiguous token chars
_PREFIX_PATTERNS = [

View file

@ -312,7 +312,7 @@ def _parse_single_entry(
)
matcher = None
if matcher is not None and event not in ("pre_tool_call", "post_tool_call"):
if matcher is not None and event not in {"pre_tool_call", "post_tool_call"}:
logger.warning(
"hooks.%s[%d].matcher=%r will be ignored at runtime — the "
"matcher field is only honored for pre_tool_call / "
@ -423,7 +423,7 @@ def _make_callback(spec: ShellHookSpec) -> Callable[..., Optional[Dict[str, Any]
def _callback(**kwargs: Any) -> Optional[Dict[str, Any]]:
# Matcher gate — only meaningful for tool-scoped events.
if spec.event in ("pre_tool_call", "post_tool_call"):
if spec.event in {"pre_tool_call", "post_tool_call"}:
if not spec.matches_tool(kwargs.get("tool_name")):
return None
@ -658,7 +658,7 @@ def _prompt_and_record(
print() # keep the terminal tidy after ^C
return False
if answer in ("y", "yes"):
if answer in {"y", "yes"}:
_record_approval(event, command)
return True
@ -752,13 +752,13 @@ def _resolve_effective_accept(
if accept_hooks_arg:
return True
env = os.environ.get("HERMES_ACCEPT_HOOKS", "").strip().lower()
if env in ("1", "true", "yes", "on"):
if env in {"1", "true", "yes", "on"}:
return True
cfg_val = cfg.get("hooks_auto_accept", False)
if isinstance(cfg_val, bool):
return cfg_val
if isinstance(cfg_val, str):
return cfg_val.strip().lower() in ("1", "true", "yes", "on")
return cfg_val.strip().lower() in {"1", "true", "yes", "on"}
return False

View file

@ -261,7 +261,7 @@ def scan_skill_commands() -> Dict[str, Dict[str, Any]]:
for scan_dir in dirs_to_scan:
for skill_md in iter_skill_index_files(scan_dir, "SKILL.md"):
if any(part in ('.git', '.github', '.hub', '.archive') for part in skill_md.parts):
if any(part in {'.git', '.github', '.hub', '.archive'} for part in skill_md.parts):
continue
try:
content = skill_md.read_text(encoding='utf-8')

View file

@ -279,7 +279,7 @@ class ChatCompletionsTransport(ProviderTransport):
_kimi_effort = "medium"
if reasoning_config and isinstance(reasoning_config, dict):
_e = (reasoning_config.get("effort") or "").strip().lower()
if _e in ("low", "medium", "high"):
if _e in {"low", "medium", "high"}:
_kimi_effort = _e
api_kwargs["reasoning_effort"] = _kimi_effort
@ -294,7 +294,7 @@ class ChatCompletionsTransport(ProviderTransport):
_tokenhub_effort = "high"
if reasoning_config and isinstance(reasoning_config, dict):
_e = (reasoning_config.get("effort") or "").strip().lower()
if _e in ("low", "medium", "high"):
if _e in {"low", "medium", "high"}:
_tokenhub_effort = _e
api_kwargs["reasoning_effort"] = _tokenhub_effort