chore: prune unused imports and duplicate import redefinitions

Remove unused imports (F401) and duplicate/shadowed import
redefinitions (F811) across the codebase using ruff's safe
autofixes. No behavioral changes -- imports only.

- ~1400 safe autofixes applied across 644 files (net -1072 lines)
- __init__.py re-exports preserved (excluded from F401 removal so
  public re-export surfaces stay intact)
- Re-exports that are imported or monkeypatched by tests but look
  unused in their defining module are kept with explicit # noqa:
  F401 (gateway/run.py load_dotenv; run_agent re-exports from
  agent.message_sanitization, agent.context_compressor,
  agent.retry_utils, agent.prompt_builder, agent.process_bootstrap,
  agent.codex_responses_adapter)
- Unsafe F841 (unused-variable) fixes deliberately skipped -- those
  can change behavior when the RHS has side effects
- ruff lints remain disabled in pyproject.toml (only PLW1514 is
  selected); this is a one-time cleanup, not a config change

Verification:
- python -m compileall: clean
- pytest --collect-only: all 27161 tests collect (zero import errors)
- core entry points import clean (run_agent, model_tools, cli,
  toolsets, hermes_state, batch_runner, gateway)
- static scan: every name any test imports directly from an edited
  module still resolves
This commit is contained in:
kshitijk4poor 2026-05-29 02:04:58 +05:30 committed by Teknium
parent a4d8f0f62a
commit 66827f8947
644 changed files with 254 additions and 1326 deletions

View file

@ -6,11 +6,8 @@ Claude Code credentials are available. The fast-path silently proceeds to
model selection with a broken token instead of offering re-auth.
"""
import json
import pytest
from unittest.mock import patch, MagicMock
from hermes_cli.config import load_env, save_env_value
from hermes_cli.config import save_env_value
class TestStaleOAuthTokenDetection:

View file

@ -6,7 +6,6 @@ import pytest
from hermes_cli.auth import (
PROVIDER_REGISTRY,
ProviderConfig,
resolve_provider,
get_api_key_provider_status,
resolve_api_key_provider_credentials,

View file

@ -15,7 +15,6 @@ import os
import sys
from pathlib import Path
import pytest
def _run_apply_profile_override(

View file

@ -14,7 +14,6 @@ so the subparser only sets the attribute when the user explicitly provides it.
import argparse
import os
import sys
from unittest.mock import patch
import pytest

View file

@ -1,7 +1,6 @@
"""Tests for utils.atomic_json_write — crash-safe JSON file writes."""
import json
import os
from pathlib import Path
from unittest.mock import patch

View file

@ -1,6 +1,5 @@
"""Tests for utils.atomic_yaml_write — crash-safe YAML file writes."""
from pathlib import Path
from unittest.mock import patch
import pytest

View file

@ -7,7 +7,6 @@ from pathlib import Path
from types import SimpleNamespace
import pytest
import yaml
from hermes_cli.auth import (
AuthError,
@ -17,8 +16,6 @@ from hermes_cli.auth import (
_save_codex_tokens,
_import_codex_cli_tokens,
_login_openai_codex,
get_codex_auth_status,
get_provider_auth_state,
refresh_codex_oauth_pure,
resolve_codex_runtime_credentials,
resolve_provider,

View file

@ -11,7 +11,6 @@ import io
import contextlib
import socket
import pytest
from hermes_cli import auth as auth_mod

View file

@ -1,7 +1,6 @@
"""Tests for is_provider_explicitly_configured()."""
import json
import os
import pytest

View file

@ -6,7 +6,6 @@ resolve_qwen_runtime_credentials, get_qwen_auth_status.
"""
import json
import os
import stat
import time
from pathlib import Path

View file

@ -24,7 +24,6 @@ from __future__ import annotations
import sys
from types import SimpleNamespace
from typing import cast
from unittest.mock import MagicMock, patch
import pytest

View file

@ -1029,7 +1029,6 @@ class TestProfileRestoration:
args = Namespace(zipfile=str(zip_path), force=True)
# Simulate profiles module not being available
import hermes_cli.backup as backup_mod
original_import = __builtins__.__import__ if hasattr(__builtins__, '__import__') else __import__
def fake_import(name, *a, **kw):

View file

@ -2,7 +2,6 @@
from unittest.mock import patch
import pytest
_MOCK_SKILLS = [

View file

@ -16,12 +16,10 @@ Covers the three paths changed by fix/bedrock-provider-model-ids-live-discovery:
All Bedrock API calls are mocked no real AWS credentials needed.
"""
import os
from contextlib import contextmanager
from types import ModuleType
from unittest.mock import MagicMock, patch
import pytest
# ---------------------------------------------------------------------------
@ -95,7 +93,7 @@ class TestProviderModelIdsBedrock:
def test_falls_back_to_static_list_when_discovery_empty(self, monkeypatch):
"""When discover_bedrock_models() returns [], fall back to curated static list."""
from hermes_cli.models import _PROVIDER_MODELS, provider_model_ids
from hermes_cli.models import provider_model_ids
with patch("agent.bedrock_adapter.discover_bedrock_models", return_value=[]), \
patch("agent.bedrock_adapter.resolve_bedrock_region", return_value="eu-central-1"):

View file

@ -1,8 +1,6 @@
"""Tests for hermes_cli/bundles.py — the `hermes bundles` CLI subcommand."""
import argparse
import sys
from pathlib import Path
import pytest

View file

@ -2,7 +2,6 @@
from __future__ import annotations
from unittest.mock import patch
from hermes_cli.config import load_config, save_config, save_env_value, get_env_value

View file

@ -1,6 +1,5 @@
"""Tests for _coalesce_session_name_args — multi-word session name merging."""
import pytest
from hermes_cli.main import _coalesce_session_name_args

View file

@ -13,11 +13,8 @@ existing Codex CLI tokens via `hermes auth openai-codex`. The old
import base64
import json
import os
import sys
import time
from pathlib import Path
from unittest.mock import patch
import pytest

View file

@ -2,14 +2,12 @@
from __future__ import annotations
from pathlib import Path
import pytest
from hermes_cli.codex_runtime_plugin_migration import (
MIGRATION_MARKER,
MIGRATION_END_MARKER,
MigrationReport,
_build_hermes_tools_mcp_entry,
_format_toml_value,
_looks_like_test_tempdir,

View file

@ -1003,7 +1003,7 @@ class TestTelegramMenuCommands:
def test_excludes_telegram_disabled_skills(self, tmp_path, monkeypatch):
"""Skills disabled for telegram should not appear in the menu."""
from unittest.mock import patch, MagicMock
from unittest.mock import patch
# Set up a config with a telegram-specific disabled list
config_file = tmp_path / "config.yaml"

View file

@ -2,7 +2,7 @@
import os
from pathlib import Path
from unittest.mock import patch, MagicMock
from unittest.mock import patch
import pytest
import yaml

View file

@ -1,9 +1,7 @@
"""Tests for ${ENV_VAR} substitution in config.yaml values."""
import os
import pytest
from hermes_cli.config import _expand_env_vars, load_config
from unittest.mock import patch as mock_patch
class TestExpandEnvVars:

View file

@ -1,6 +1,5 @@
"""Tests for config.yaml structure validation (validate_config_structure)."""
import pytest
from hermes_cli.config import validate_config_structure, ConfigIssue

View file

@ -1,8 +1,7 @@
"""Tests for hermes_cli.copilot_auth — Copilot token validation and resolution."""
import os
import pytest
from unittest.mock import patch, MagicMock
from unittest.mock import patch
class TestTokenValidation:

View file

@ -12,12 +12,8 @@ Covers:
from __future__ import annotations
import io
from contextlib import redirect_stdout, redirect_stderr
from types import SimpleNamespace
from unittest.mock import patch
import pytest
def _ns(**kwargs):

View file

@ -12,9 +12,8 @@ clamps with ``min(8, curses.COLORS - 1)``.
import curses
import re
from pathlib import Path
from unittest.mock import patch, MagicMock, call
from unittest.mock import patch, MagicMock
import pytest
# Path to the source files under test

View file

@ -6,8 +6,7 @@ immediately when provider_info had a saved ``model`` field, making it
impossible to switch models on multi-model endpoints.
"""
import os
from unittest.mock import patch, MagicMock, call
from unittest.mock import patch
import pytest

View file

@ -1,7 +1,6 @@
"""Tests for the dashboard-auth cookie helpers."""
from __future__ import annotations
import pytest
from fastapi import FastAPI
from fastapi.responses import Response
from fastapi.testclient import TestClient

View file

@ -177,7 +177,7 @@ class TestOAuthRedirectUriRespectsPrefix:
# The stub IDP's redirect_url echoes the redirect_uri back. The
# real IDP would consume it and later use it to redirect the
# user, so the byte-exact value MUST include the prefix.
from urllib.parse import urlparse, parse_qs, unquote
from urllib.parse import urlparse
# Stub returns ``{redirect_uri}?code=stub_code&state=...`` — so
# we read up to the first ``?``.
redirect_uri = location.split("?", 1)[0]

View file

@ -14,7 +14,6 @@ pre-existing regression unrelated to dashboard-auth.
from __future__ import annotations
from types import SimpleNamespace
from unittest.mock import patch
import pytest
@ -29,7 +28,6 @@ from fastapi.testclient import TestClient
from hermes_cli import web_server
from hermes_cli.dashboard_auth import clear_providers, register_provider
from hermes_cli.dashboard_auth.ws_tickets import (
TicketInvalid,
_reset_for_tests,
consume_ticket,
mint_ticket,

View file

@ -15,7 +15,7 @@ from unittest.mock import patch, MagicMock
import pytest
from hermes_cli.main import cmd_dashboard, _report_dashboard_status
from hermes_cli.main import cmd_dashboard
def _ns(**kw):

View file

@ -1,10 +1,8 @@
"""Tests for ``hermes debug`` CLI command and debug utilities."""
import os
import sys
import urllib.error
from pathlib import Path
from unittest.mock import MagicMock, patch, call
from unittest.mock import MagicMock, patch
import pytest
@ -337,7 +335,6 @@ class TestCaptureLogSnapshotRedaction:
redaction feature ships silently broken for users who opted out of
runtime redaction (e.g. developers working on the redactor itself).
"""
import os
# Force the runtime flag off so we're exercising the force=True path,
# not the default-on path.

View file

@ -1,4 +1,3 @@
from pathlib import Path
from unittest.mock import patch

View file

@ -1,7 +1,5 @@
"""Tests for warn_deprecated_cwd_env_vars() migration warning."""
import os
import pytest
class TestDeprecatedCwdWarning:

View file

@ -792,7 +792,7 @@ class TestGitHubTokenCheck:
monkeypatch.setenv("HERMES_HOME", str(home))
monkeypatch.setenv("PATH", "/nonexistent") # gh not found
from hermes_cli.doctor import run_doctor, _DHH
from hermes_cli.doctor import run_doctor
import io, contextlib
buf = io.StringIO()

View file

@ -1,6 +1,5 @@
"""Tests for the Command Installation check in hermes doctor."""
import os
import sys
import types
from argparse import Namespace

View file

@ -1,7 +1,6 @@
import importlib
import os
import sys
from pathlib import Path
from hermes_cli.env_loader import load_hermes_dotenv

View file

@ -1,7 +1,6 @@
"""Tests for `hermes fallback` — chain reading, add/remove/clear, legacy migration."""
from __future__ import annotations
import io
import types
from pathlib import Path
from unittest.mock import patch

View file

@ -2,7 +2,6 @@
import sys
from types import ModuleType, SimpleNamespace
from unittest.mock import patch, call
import pytest

View file

@ -12,7 +12,6 @@ Currently:
Windows path that works.
"""
import sys
class TestMatrixHiddenOnWindows:

View file

@ -7,7 +7,6 @@ host systemd/launchd/windows code path.
"""
from __future__ import annotations
from typing import Any
import pytest

View file

@ -1321,7 +1321,6 @@ class TestSystemServiceIdentityRootHandling:
def test_auto_detected_root_is_rejected(self, monkeypatch):
"""When root is auto-detected (not explicitly requested), raise."""
import grp
monkeypatch.delenv("SUDO_USER", raising=False)
monkeypatch.setenv("USER", "root")
@ -1343,7 +1342,6 @@ class TestSystemServiceIdentityRootHandling:
def test_non_root_user_passes_through(self, monkeypatch):
"""Normal non-root user works as before."""
import grp
monkeypatch.delenv("SUDO_USER", raising=False)
monkeypatch.setenv("USER", "nobody")

View file

@ -1,4 +1,3 @@
from pathlib import Path
from unittest.mock import patch

View file

@ -1,8 +1,6 @@
"""Tests for WSL detection and WSL-aware gateway behavior."""
import io
import subprocess
import sys
from types import SimpleNamespace
from unittest.mock import patch, MagicMock, mock_open

View file

@ -1,6 +1,5 @@
"""Tests for Google AI Studio (Gemini) provider integration."""
import os
import pytest
from unittest.mock import patch, MagicMock

View file

@ -525,7 +525,6 @@ class TestGoalStateSubgoalsBackcompat:
def test_old_state_meta_row_loads_without_subgoals(self):
"""A goal serialized BEFORE the subgoals field existed must
round-trip with an empty list, not crash."""
import json
from hermes_cli.goals import GoalState
legacy = json.dumps({
@ -647,7 +646,7 @@ class TestJudgeGoalWithSubgoals:
We don't actually call the model — we patch the aux client to
capture the prompt that would be sent.
"""
from unittest.mock import patch, MagicMock
from unittest.mock import patch
from hermes_cli import goals
captured = {}

View file

@ -4,7 +4,6 @@ from __future__ import annotations
import io
import json
import sys
from contextlib import redirect_stdout
from pathlib import Path
from types import SimpleNamespace

View file

@ -21,7 +21,6 @@ from __future__ import annotations
from unittest.mock import patch
import pytest
from hermes_cli.inventory import (
ConfigContext,

View file

@ -18,7 +18,6 @@ import threading
import time
from pathlib import Path
from types import SimpleNamespace
from typing import Optional
import pytest

View file

@ -2566,7 +2566,6 @@ def test_resolve_hermes_argv_module_actually_runs():
Run it as a real subprocess to catch that regression.
"""
import subprocess
import sys
import hermes_cli.kanban_db as kb
import shutil
import unittest.mock as mock
@ -3145,7 +3144,6 @@ def test_detect_stale_skips_recently_started_task(kanban_home, monkeypatch):
def test_detect_stale_skips_when_timeout_zero(kanban_home, monkeypatch):
"""stale_timeout_seconds=0 disables stale detection entirely."""
import hermes_cli.kanban_db as _kb
with kb.connect() as conn:
t = kb.create_task(conn, title="disabled", assignee="worker")
@ -3628,7 +3626,7 @@ def test_write_txn_preserves_original_exception_when_rollback_fails(kanban_home)
)
def test_write_txn_healthy_commit_no_exception(tmp_path):
"""Normal commit does not trigger the torn-extend check."""
from hermes_cli.kanban_db import connect, write_txn, create_task
from hermes_cli.kanban_db import connect, write_txn
db = tmp_path / "test.db"
conn = connect(db_path=db)
# Should not raise
@ -3645,7 +3643,6 @@ def test_write_txn_healthy_commit_no_exception(tmp_path):
def test_write_txn_raises_on_truncated_file(tmp_path):
"""A mocked smaller file size triggers the torn-extend check."""
from hermes_cli.kanban_db import connect, write_txn
import hermes_cli.kanban_db as kanban_db_module
db = tmp_path / "test.db"
conn = connect(db_path=db)
# Get actual page size so we can fake a smaller file
@ -3705,7 +3702,7 @@ def test_connect_sets_wal_autocheckpoint_100(tmp_path):
def test_write_txn_check_reads_correct_header_fields(tmp_path):
"""Synthetic DB file with mismatched header page_count triggers the check."""
import struct
from hermes_cli.kanban_db import connect, write_txn, _check_file_length_invariant
from hermes_cli.kanban_db import connect, _check_file_length_invariant
db = tmp_path / "synthetic.db"
conn = connect(db_path=db)
page_size = conn.execute("PRAGMA page_size").fetchone()[0]

View file

@ -7,14 +7,12 @@ and the assignee-fallback logic.
from __future__ import annotations
import argparse
import json as jsonlib
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest
from hermes_cli import kanban as kanban_cli
from hermes_cli import kanban_db as kb
from hermes_cli import kanban_decompose as decomp

View file

@ -298,7 +298,6 @@ def test_dispatcher_tick_does_not_call_init_db(kanban_home, monkeypatch):
"""
import hermes_cli.kanban_db as kb
from gateway.run import GatewayRunner
from unittest.mock import patch
runner = object.__new__(GatewayRunner)

View file

@ -1,4 +1,3 @@
import json
from hermes_cli import kanban_db as kb
from hermes_cli.kanban_swarm import (

View file

@ -1,10 +1,7 @@
"""Tests for hermes_cli.logs — log viewing and filtering."""
import os
from datetime import datetime, timedelta
from pathlib import Path
import pytest
from hermes_cli.logs import (
LOG_FILES,

View file

@ -7,7 +7,6 @@ launch an MCP is mocked.
from __future__ import annotations
import os
from pathlib import Path
from unittest.mock import patch
@ -207,7 +206,7 @@ class TestManifestParsing:
class TestInstall:
def test_install_simple_stdio_writes_config(self, catalog_dir):
_write_manifest(catalog_dir, "demo", _basic_manifest())
from hermes_cli.mcp_catalog import install_entry, get_entry
from hermes_cli.mcp_catalog import install_entry
from hermes_cli.config import load_config
install_entry(_entry("demo"), enable=True)
@ -240,7 +239,7 @@ class TestInstall:
fake_clone.mkdir()
from hermes_cli import mcp_catalog
from hermes_cli.mcp_catalog import install_entry, get_entry
from hermes_cli.mcp_catalog import install_entry
from hermes_cli.config import load_config
with patch.object(mcp_catalog, "_do_git_install", return_value=fake_clone):
@ -263,7 +262,7 @@ class TestInstall:
monkeypatch.setattr(mcp_catalog, "_prompt_input", lambda *a, **kw: "secret-val")
from hermes_cli.mcp_catalog import install_entry, get_entry
from hermes_cli.mcp_catalog import install_entry
from hermes_cli.config import get_env_value, load_config
install_entry(_entry("demo"), enable=True)
@ -278,7 +277,7 @@ class TestInstall:
)
_write_manifest(catalog_dir, "demo", body)
from hermes_cli.mcp_catalog import install_entry, get_entry
from hermes_cli.mcp_catalog import install_entry
from hermes_cli.config import load_config
install_entry(_entry("demo"), enable=True)
@ -297,7 +296,7 @@ class TestInstall:
_write_manifest(catalog_dir, "demo", body)
from hermes_cli import mcp_catalog
from hermes_cli.mcp_catalog import install_entry, get_entry, CatalogError
from hermes_cli.mcp_catalog import install_entry, CatalogError
# User hits enter — empty input, no default
monkeypatch.setattr(mcp_catalog, "_prompt_input", lambda *a, **kw: "")
@ -314,7 +313,7 @@ class TestInstall:
class TestUninstall:
def test_uninstall_removes_server_block(self, catalog_dir):
_write_manifest(catalog_dir, "demo", _basic_manifest())
from hermes_cli.mcp_catalog import install_entry, get_entry, uninstall_entry
from hermes_cli.mcp_catalog import install_entry, uninstall_entry
from hermes_cli.config import load_config
install_entry(_entry("demo"), enable=True)

View file

@ -6,12 +6,7 @@ any actual MCP servers or API keys.
"""
import argparse
import json
import os
import types
from pathlib import Path
from typing import Any, Dict, List
from unittest.mock import MagicMock, patch, PropertyMock
import pytest

View file

@ -10,7 +10,6 @@ run silently.
from __future__ import annotations
from copy import deepcopy
from hermes_cli.config import DEFAULT_CONFIG

View file

@ -1,7 +1,6 @@
"""Tests for MCP tools interactive configuration in hermes_cli.tools_config."""
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
from unittest.mock import patch
from hermes_cli.tools_config import _configure_mcp_tools_interactive

View file

@ -8,10 +8,7 @@ Covers:
- Profile-scoped reset (uses HERMES_HOME)
"""
import os
import pytest
from argparse import Namespace
from pathlib import Path
@pytest.fixture
@ -39,7 +36,7 @@ def _run_memory_reset(target="all", yes=False, monkeypatch=None, confirm_input="
Simulates what happens when `hermes memory reset` is run.
"""
from hermes_constants import get_hermes_home, display_hermes_home
from hermes_constants import get_hermes_home
mem_dir = get_hermes_home() / "memories"
files_to_reset = []

View file

@ -8,7 +8,6 @@ import pytest
from hermes_cli.model_normalize import (
normalize_model_for_provider,
_DOT_TO_HYPHEN_PROVIDERS,
_AGGREGATOR_PROVIDERS,
_normalize_for_deepseek,
detect_vendor,
)

View file

@ -6,7 +6,6 @@ isinstance(model, dict)) to silently fail — leaving the provider unset and
falling back to auto-detection.
"""
import os
from unittest.mock import patch, MagicMock
import pytest
@ -194,7 +193,6 @@ class TestProviderPersistsAfterModelSave:
# Patch fetch_api_models so the named custom flow returns one model;
# patch simple_term_menu to force the input() fallback; patch input to
# auto-select the first model from the fallback prompt.
from unittest.mock import MagicMock
fake_menu_module = MagicMock()
fake_menu_module.TerminalMenu.side_effect = OSError("no tty in test")
with patch("hermes_cli.auth._save_model_choice"), \

View file

@ -17,10 +17,8 @@ Merging is what lets new models (e.g. ``mimo-v2.5-pro`` on opencode-go)
appear in ``/model`` without a Hermes release.
"""
import os
from unittest.mock import patch
import pytest
from hermes_cli.models import (
_MODELS_DEV_PREFERRED,

View file

@ -6,10 +6,7 @@ httpx tries to encode the Authorization header as ASCII.
"""
import os
import sys
import tempfile
import pytest
from hermes_cli.config import _check_non_ascii_credential

View file

@ -22,7 +22,6 @@ These tests verify:
from __future__ import annotations
import logging
import pytest
from hermes_cli.auth import (
DEFAULT_NOUS_INFERENCE_URL,

View file

@ -10,8 +10,6 @@ Covers:
"""
import os
import pytest
from unittest.mock import patch, MagicMock
# ---------------------------------------------------------------------------

View file

@ -1,6 +1,5 @@
"""Tests for Ollama Cloud provider integration."""
import os
import pytest
from unittest.mock import patch, MagicMock

View file

@ -7,11 +7,9 @@ resolution in list_authenticated_providers() Section 2 must bridge this gap.
Covers: #5223, #6492
"""
import json
import os
from unittest.mock import patch
import pytest
from hermes_cli.model_switch import list_authenticated_providers

View file

@ -1,4 +1,3 @@
from pathlib import Path
from unittest.mock import patch

View file

@ -8,13 +8,9 @@ Covers:
- Honcho register_cli() builds correct argparse tree
"""
import argparse
import os
import sys
from pathlib import Path
from unittest.mock import MagicMock
import pytest
from hermes_cli.plugins import (
PluginContext,

View file

@ -14,7 +14,7 @@ from typing import Any, Dict
import pytest
import yaml
from hermes_cli.plugins import PluginManager, PluginManifest
from hermes_cli.plugins import PluginManager
# ── Helpers ────────────────────────────────────────────────────────────────

View file

@ -1,7 +1,6 @@
"""Tests for the Hermes plugin system (hermes_cli.plugins)."""
import logging
import os
import sys
import types
from pathlib import Path
@ -13,17 +12,13 @@ import yaml
from hermes_cli.plugins import (
ENTRY_POINTS_GROUP,
VALID_HOOKS,
LoadedPlugin,
PluginContext,
PluginManager,
PluginManifest,
get_plugin_manager,
get_plugin_command_handler,
get_plugin_commands,
get_pre_tool_call_block_message,
resolve_plugin_command_result,
discover_plugins,
invoke_hook,
)
@ -1309,7 +1304,6 @@ class TestPluginCommandResultResolution:
monkeypatch.setattr("hermes_cli.plugins.asyncio.get_running_loop", lambda: _Loop())
monkeypatch.setattr("hermes_cli.plugins._PLUGIN_COMMAND_AWAIT_TIMEOUT_SECS", 0.1)
import pytest
with pytest.raises(TimeoutError):
resolve_plugin_command_result(_slow_handler())

View file

@ -3,8 +3,6 @@
from __future__ import annotations
import logging
import os
import types
from pathlib import Path
from unittest.mock import MagicMock, patch
@ -19,7 +17,6 @@ from hermes_cli.plugins_cmd import (
_resolve_git_executable,
_resolve_git_url,
_sanitize_plugin_name,
plugins_command,
)
@ -259,7 +256,6 @@ class TestCmdInstall:
def test_install_requires_identifier(self):
from hermes_cli.plugins_cmd import cmd_install
import argparse
with pytest.raises(SystemExit):
cmd_install("")
@ -544,7 +540,6 @@ class TestCopyExampleFiles:
"""Test example file copying."""
def test_copies_example_files(self, tmp_path):
from hermes_cli.plugins_cmd import _copy_example_files
from unittest.mock import MagicMock
console = MagicMock()
@ -560,7 +555,6 @@ class TestCopyExampleFiles:
console.print.assert_called()
def test_skips_existing_files(self, tmp_path):
from hermes_cli.plugins_cmd import _copy_example_files
from unittest.mock import MagicMock
console = MagicMock()
@ -577,7 +571,6 @@ class TestCopyExampleFiles:
assert real_file.read_text() == "existing: true"
def test_handles_copy_error_gracefully(self, tmp_path):
from hermes_cli.plugins_cmd import _copy_example_files
from unittest.mock import MagicMock, patch
console = MagicMock()

View file

@ -10,7 +10,6 @@ mocking git would just test the mock.
from __future__ import annotations
import os
from pathlib import Path
import pytest

View file

@ -6,7 +6,6 @@ profiles; leaking credentials in the archive is a security issue.
"""
import tarfile
from pathlib import Path
from hermes_cli.profiles import export_profile, _DEFAULT_EXPORT_EXCLUDE_ROOT

View file

@ -7,7 +7,6 @@ and shell completion generation.
import json
import io
import os
import tarfile
from pathlib import Path
from unittest.mock import patch, MagicMock

View file

@ -31,7 +31,6 @@ These tests pin each layer of the new defence:
from __future__ import annotations
import json
import os
import sys
from pathlib import Path
from unittest.mock import patch

View file

@ -5,9 +5,7 @@ accepted as base_url, and unknown keys go unreported.
"""
import logging
from unittest.mock import patch
import pytest
from hermes_cli.config import _normalize_custom_provider_entry

View file

@ -4,7 +4,6 @@ from __future__ import annotations
import asyncio
import json
import os
import threading
from pathlib import Path
from typing import Any, Dict

View file

@ -1,7 +1,4 @@
import pytest
import sys
from unittest.mock import patch
from pathlib import Path
import hermes_cli.model_switch as ms
from hermes_cli.model_switch import DirectAlias

View file

@ -10,7 +10,6 @@ import json
from pathlib import Path
from unittest.mock import patch
import pytest
from hermes_cli import security_audit as sa

View file

@ -9,7 +9,6 @@ from __future__ import annotations
import io
import json
from pathlib import Path
import pytest

View file

@ -361,7 +361,6 @@ def test_get_service_manager_returns_s6_instance(
) -> None:
"""The s6 backend ships in Phase 3 — the factory must return an
S6ServiceManager when running inside a container."""
from hermes_cli.service_manager import S6ServiceManager
monkeypatch.setattr(
"hermes_cli.service_manager.detect_service_manager", lambda: "s6",
)
@ -406,7 +405,6 @@ def fake_subprocess_run(monkeypatch: pytest.MonkeyPatch):
def test_s6_manager_kind_and_supports_registration() -> None:
from hermes_cli.service_manager import S6ServiceManager
mgr = S6ServiceManager()
assert mgr.kind == "s6"
assert mgr.supports_runtime_registration() is True
@ -524,7 +522,6 @@ def test_seed_supervise_skeleton_is_idempotent(tmp_path) -> None:
def test_s6_register_creates_service_dir_and_triggers_scan(
s6_scandir, fake_subprocess_run,
) -> None:
from hermes_cli.service_manager import S6ServiceManager
mgr = S6ServiceManager(scandir=s6_scandir)
mgr.register_profile_gateway("coder")
@ -576,7 +573,6 @@ def test_s6_register_creates_service_dir_and_triggers_scan(
def test_s6_register_extra_env_is_quoted(s6_scandir, fake_subprocess_run) -> None:
from hermes_cli.service_manager import S6ServiceManager
mgr = S6ServiceManager(scandir=s6_scandir)
mgr.register_profile_gateway(
"x", extra_env={"FOO": "bar baz", "QUOTED": "a'b"},
@ -588,7 +584,6 @@ def test_s6_register_extra_env_is_quoted(s6_scandir, fake_subprocess_run) -> Non
def test_render_run_script_resets_home_before_exec() -> None:
from hermes_cli.service_manager import S6ServiceManager
run_text = S6ServiceManager._render_run_script("coder", {})
@ -597,14 +592,12 @@ def test_render_run_script_resets_home_before_exec() -> None:
def test_s6_register_rejects_invalid_profile_name(s6_scandir) -> None:
from hermes_cli.service_manager import S6ServiceManager
mgr = S6ServiceManager(scandir=s6_scandir)
with pytest.raises(ValueError):
mgr.register_profile_gateway("Bad/Name")
def test_s6_register_rejects_duplicate(s6_scandir, fake_subprocess_run) -> None:
from hermes_cli.service_manager import S6ServiceManager
mgr = S6ServiceManager(scandir=s6_scandir)
(s6_scandir / "gateway-coder").mkdir(parents=True)
with pytest.raises(ValueError, match="already registered"):
@ -617,7 +610,6 @@ def test_s6_register_rolls_back_on_svscanctl_failure(
"""If s6-svscanctl fails the service dir must be cleaned up so the
next register call doesn't see a stale duplicate."""
import subprocess as _sp
from hermes_cli.service_manager import S6ServiceManager
def _fail_scanctl(cmd, **kw):
# Manager calls s6-svscanctl by absolute path; match on basename.
@ -635,7 +627,6 @@ def test_s6_register_rolls_back_on_svscanctl_failure(
def test_s6_unregister_removes_service_dir(
s6_scandir, fake_subprocess_run,
) -> None:
from hermes_cli.service_manager import S6ServiceManager
svc_dir = s6_scandir / "gateway-coder"
svc_dir.mkdir(parents=True)
(svc_dir / "type").write_text("longrun\n")
@ -655,13 +646,11 @@ def test_s6_unregister_removes_service_dir(
def test_s6_unregister_absent_profile_is_noop(s6_scandir) -> None:
from hermes_cli.service_manager import S6ServiceManager
# Should NOT raise even though "ghost" doesn't exist
S6ServiceManager(scandir=s6_scandir).unregister_profile_gateway("ghost")
def test_s6_list_profile_gateways(s6_scandir) -> None:
from hermes_cli.service_manager import S6ServiceManager
# Three gateway profiles + one unrelated service + one hidden dir
(s6_scandir / "gateway-coder").mkdir()
(s6_scandir / "gateway-assistant").mkdir()
@ -674,7 +663,6 @@ def test_s6_list_profile_gateways(s6_scandir) -> None:
def test_s6_list_profile_gateways_empty_when_scandir_missing(tmp_path) -> None:
from hermes_cli.service_manager import S6ServiceManager
missing = tmp_path / "does-not-exist"
assert S6ServiceManager(scandir=missing).list_profile_gateways() == []
@ -682,7 +670,6 @@ def test_s6_list_profile_gateways_empty_when_scandir_missing(tmp_path) -> None:
def test_s6_lifecycle_dispatches_to_s6_svc(
s6_scandir, fake_subprocess_run,
) -> None:
from hermes_cli.service_manager import S6ServiceManager
mgr = S6ServiceManager(scandir=s6_scandir)
# _run_svc now verifies the slot exists before invoking s6-svc, so
# we have to pre-seed the dir. In real use the slot is created by
@ -710,7 +697,6 @@ def test_lifecycle_raises_gateway_not_registered_for_missing_slot(
opaque CalledProcessError stacktrace."""
from hermes_cli.service_manager import (
GatewayNotRegisteredError,
S6ServiceManager,
)
mgr = S6ServiceManager(scandir=s6_scandir)
@ -740,7 +726,6 @@ def test_all_lifecycle_methods_check_for_missing_slot(
"""start/stop/restart all check for missing slots the same way."""
from hermes_cli.service_manager import (
GatewayNotRegisteredError,
S6ServiceManager,
)
mgr = S6ServiceManager(scandir=s6_scandir)
@ -755,7 +740,6 @@ def test_gateway_not_registered_unprefixed_service_name(s6_scandir) -> None:
accidentally strip user-provided text."""
from hermes_cli.service_manager import (
GatewayNotRegisteredError,
S6ServiceManager,
)
mgr = S6ServiceManager(scandir=s6_scandir)
@ -772,7 +756,7 @@ def test_lifecycle_raises_s6_command_error_on_subprocess_failure(
CalledProcessError into a named S6CommandError carrying the
return code and stderr."""
import subprocess as _sp
from hermes_cli.service_manager import S6CommandError, S6ServiceManager
from hermes_cli.service_manager import S6CommandError
# Pre-create the slot so we reach the s6-svc call.
(s6_scandir / "gateway-coder").mkdir()
@ -801,7 +785,6 @@ def test_s6_is_running_parses_svstat(
s6_scandir, monkeypatch: pytest.MonkeyPatch,
) -> None:
import subprocess as _sp
from hermes_cli.service_manager import S6ServiceManager
def _svstat(cmd, **kw):
if cmd[0].endswith("/s6-svstat"):

View file

@ -6,11 +6,9 @@ Covers:
- Argument parser registration
"""
import os
import time
from unittest.mock import MagicMock, patch, call
from unittest.mock import MagicMock, patch
import pytest
from hermes_cli.main import _session_browse_picker
@ -249,7 +247,6 @@ class TestCursesBrowse:
def _run_with_keys(self, sessions, key_sequence):
"""Simulate running the curses picker with a given key sequence."""
import curses
# Build a mock stdscr that returns keys from the sequence
mock_stdscr = MagicMock()
@ -305,7 +302,6 @@ class TestCursesBrowse:
def test_type_to_filter_then_enter(self):
"""Typing characters filters the list, Enter selects from filtered."""
import curses
sessions = [
{"id": "s1", "source": "cli", "title": "Alpha project", "preview": "", "last_active": time.time()},
{"id": "s2", "source": "cli", "title": "Beta project", "preview": "", "last_active": time.time()},
@ -325,7 +321,6 @@ class TestCursesBrowse:
def test_backspace_removes_filter_char(self):
"""Backspace removes the last character from the filter."""
import curses
sessions = [
{"id": "s1", "source": "cli", "title": "Alpha", "preview": "", "last_active": time.time()},
{"id": "s2", "source": "cli", "title": "Beta", "preview": "", "last_active": time.time()},
@ -337,7 +332,6 @@ class TestCursesBrowse:
def test_escape_clears_filter_first(self):
"""First Esc clears the search text, second Esc exits."""
import curses
sessions = _make_sessions(3)
# Type "ab" then Esc (clears filter) then Enter (selects first)
keys = [ord('a'), ord('b'), 27, 10]
@ -391,11 +385,9 @@ class TestSessionBrowseArgparse:
def test_browse_subcommand_exists(self):
"""hermes sessions browse should be parseable."""
from hermes_cli.main import main as _main_entry
# We can't run main(), but we can import and test the parser setup
# by checking that argparse doesn't error on "sessions browse"
import argparse
# Re-create the parser portion
# Instead, let's just verify the import works and the function exists
from hermes_cli.main import _session_browse_picker

View file

@ -3,7 +3,6 @@ from __future__ import annotations
import json
import pytest
from hermes_cli.session_recap import build_recap

View file

@ -2,8 +2,7 @@
import argparse
import os
from pathlib import Path
from unittest.mock import patch, call
from unittest.mock import patch
import pytest

View file

@ -1,12 +1,8 @@
"""Tests for setup.py configuration flows."""
import json
import os
import sys
import types
import pytest
from hermes_cli.auth import get_active_provider
from hermes_cli.config import load_config, save_config
from hermes_cli import setup as setup_mod
from hermes_cli.setup import setup_model_provider

View file

@ -6,7 +6,6 @@ interactive setup menus.
"""
import os
import pytest
from gateway.platform_registry import PlatformEntry, platform_registry

View file

@ -1,7 +1,6 @@
"""Test that setup.py has shutil available for Matrix E2EE auto-install."""
import ast
import pytest
def _parse_setup_imports():

View file

@ -1,7 +1,7 @@
"""Tests for non-interactive setup and first-run headless behavior."""
from argparse import Namespace
from unittest.mock import MagicMock, patch
from unittest.mock import patch
import pytest
from hermes_cli.config import DEFAULT_CONFIG, load_config, save_config

View file

@ -5,7 +5,6 @@ serving a stale cache (models.dev only, no live API probe) for up to an hour.
from __future__ import annotations
from unittest.mock import patch
def test_setup_ollama_cloud_passes_force_refresh(monkeypatch):

View file

@ -1,6 +1,5 @@
"""Tests for hermes_cli/skills_config.py and skills_tool disabled filtering."""
import pytest
from unittest.mock import patch, MagicMock
from unittest.mock import patch
# ---------------------------------------------------------------------------

View file

@ -8,7 +8,6 @@ Based on PR #1595 by 333Alden333 (salvaged).
"""
import sys
from types import SimpleNamespace
def test_cli_skills_install_yes_sets_skip_confirm(monkeypatch):

View file

@ -10,9 +10,8 @@ Based on PR #1595 by 333Alden333 (salvaged).
Updated for PR #3586 (cache-aware install/uninstall).
"""
from unittest.mock import patch, MagicMock
from unittest.mock import patch
import pytest
class TestHandleSkillsSlashInstallFlags:

View file

@ -17,7 +17,6 @@ def test_no_duplicate_skills_subparser():
# Force fresh import of the module where parser is constructed
# If there are duplicate 'skills' subparsers, this import will raise
# argparse.ArgumentError at module load time
import importlib
import sys
# Remove cached module if present

View file

@ -1,10 +1,6 @@
"""Tests for hermes_cli.skin_engine — the data-driven skin/theme system."""
import json
import os
import pytest
from pathlib import Path
from unittest.mock import patch
@pytest.fixture(autouse=True)
@ -185,7 +181,7 @@ class TestSkinManagement:
class TestUserSkins:
def test_load_user_skin_from_yaml(self, tmp_path, monkeypatch):
from hermes_cli.skin_engine import load_skin, _skins_dir
from hermes_cli.skin_engine import load_skin
# Create a user skin YAML
skins_dir = tmp_path / "skins"
skins_dir.mkdir()

View file

@ -13,7 +13,6 @@ import argparse
import io
import sys
import pytest
def _build_parser():

View file

@ -13,7 +13,6 @@ to prevent a hard crash.
from __future__ import annotations
import errno
import os
from unittest.mock import MagicMock
import pytest

View file

@ -10,7 +10,6 @@ from hermes_cli.auth import (
resolve_provider,
get_api_key_provider_status,
resolve_api_key_provider_credentials,
AuthError,
)

View file

@ -1,6 +1,5 @@
"""Tests for hermes_cli/tips.py — random tip display at session start."""
import pytest
from hermes_cli.tips import TIPS, get_random_tip

View file

@ -1,6 +1,5 @@
"""Tests for tool token estimation and curses_ui status_fn support."""
from unittest.mock import patch
import pytest
@ -20,7 +19,7 @@ _needs_tiktoken = pytest.mark.skipif(not _has_tiktoken, reason="tiktoken not ins
@_needs_tiktoken
def test_estimate_tool_tokens_returns_positive_counts():
"""_estimate_tool_tokens should return a non-empty dict with positive values."""
from hermes_cli.tools_config import _estimate_tool_tokens, _tool_token_cache
from hermes_cli.tools_config import _estimate_tool_tokens
# Clear cache to force fresh computation
import hermes_cli.tools_config as tc

Some files were not shown because too many files have changed in this diff Show more