fix: Fix remaining 61 ruff linting errors (SIM102, SIM117)

Fixed all remaining linting errors from the 310 total:
- SIM102: Combined nested if statements (31 errors)
  - adaptors/openai.py
  - config_extractor.py
  - codebase_scraper.py
  - doc_scraper.py
  - github_fetcher.py
  - pattern_recognizer.py
  - pdf_scraper.py
  - test_example_extractor.py

- SIM117: Combined multiple with statements (24 errors)
  - tests/test_async_scraping.py (2 errors)
  - tests/test_github_scraper.py (2 errors)
  - tests/test_guide_enhancer.py (20 errors)

- Fixed test fixture parameter (mock_config in test_c3_integration.py)

All 700+ tests passing.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
yusyus
2026-01-17 23:25:12 +03:00
parent 596b219599
commit 81dd5bbfbc
29 changed files with 720 additions and 360 deletions

View File

@@ -179,11 +179,10 @@ class TestAsyncRouting(unittest.TestCase):
# Mock scrape_all_async to verify it does NOT get called
with patch.object(
converter, "scrape_all_async", new_callable=AsyncMock
) as mock_async:
with patch.object(converter, "_try_llms_txt", return_value=False):
converter.scrape_all()
# Verify async version was NOT called
mock_async.assert_not_called()
) as mock_async, patch.object(converter, "_try_llms_txt", return_value=False):
converter.scrape_all()
# Verify async version was NOT called
mock_async.assert_not_called()
finally:
os.chdir(self.original_cwd)
@@ -317,12 +316,11 @@ class TestAsyncLlmsTxtIntegration(unittest.TestCase):
converter = DocToSkillConverter(config, dry_run=False)
# Mock _try_llms_txt to return True (llms.txt found)
with patch.object(converter, "_try_llms_txt", return_value=True):
with patch.object(converter, "save_summary"):
converter.scrape_all()
# If llms.txt succeeded, async scraping should be skipped
# Verify by checking that pages were not scraped
self.assertEqual(len(converter.visited_urls), 0)
with patch.object(converter, "_try_llms_txt", return_value=True), patch.object(converter, "save_summary"):
converter.scrape_all()
# If llms.txt succeeded, async scraping should be skipped
# Verify by checking that pages were not scraped
self.assertEqual(len(converter.visited_urls), 0)
finally:
os.chdir(original_cwd)

View File

@@ -136,7 +136,7 @@ class TestC3Integration:
},
}
def test_codebase_analysis_enabled_by_default(self, _mock_config, temp_dir):
def test_codebase_analysis_enabled_by_default(self, mock_config, temp_dir): # noqa: ARG002
"""Test that enable_codebase_analysis defaults to True."""
# Config with GitHub source but no explicit enable_codebase_analysis
config_without_flag = {
@@ -155,7 +155,7 @@ class TestC3Integration:
# Verify default is True
github_source = scraper.config["sources"][0]
assert github_source.get("enable_codebase_analysis", True) == True
assert github_source.get("enable_codebase_analysis", True)
def test_skip_codebase_analysis_flag(self, mock_config, temp_dir):
"""Test --skip-codebase-analysis CLI flag disables analysis."""

View File

@@ -72,20 +72,18 @@ class TestGitHubScraperInitialization(unittest.TestCase):
"""Test initialization with token from environment variable"""
config = {"repo": "facebook/react", "name": "react", "github_token": None}
with patch.dict(os.environ, {"GITHUB_TOKEN": "env_token_456"}):
with patch("skill_seekers.cli.github_scraper.Github") as mock_github:
_scraper = self.GitHubScraper(config)
mock_github.assert_called_once_with("env_token_456")
with patch.dict(os.environ, {"GITHUB_TOKEN": "env_token_456"}), patch("skill_seekers.cli.github_scraper.Github") as mock_github:
_scraper = self.GitHubScraper(config)
mock_github.assert_called_once_with("env_token_456")
def test_init_without_token(self):
"""Test initialization without authentication"""
config = {"repo": "facebook/react", "name": "react", "github_token": None}
with patch("skill_seekers.cli.github_scraper.Github") as mock_github:
with patch.dict(os.environ, {}, clear=True):
scraper = self.GitHubScraper(config)
# Should create unauthenticated client
self.assertIsNotNone(scraper.github)
with patch("skill_seekers.cli.github_scraper.Github"), patch.dict(os.environ, {}, clear=True):
scraper = self.GitHubScraper(config)
# Should create unauthenticated client
self.assertIsNotNone(scraper.github)
def test_token_priority_env_over_config(self):
"""Test that GITHUB_TOKEN env var takes priority over config"""

View File

@@ -28,15 +28,13 @@ class TestGuideEnhancerModeDetection:
def test_auto_mode_with_api_key(self):
"""Test auto mode detects API when key present and library available"""
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="auto")
# Will be 'api' if library available, otherwise 'local' or 'none'
assert enhancer.mode in ["api", "local", "none"]
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}), patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True), patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="auto")
# Will be 'api' if library available, otherwise 'local' or 'none'
assert enhancer.mode in ["api", "local", "none"]
def test_auto_mode_without_api_key(self):
"""Test auto mode falls back to LOCAL when no API key"""
@@ -101,31 +99,29 @@ class TestGuideEnhancerStepDescriptions:
}
)
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}), patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True), patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock() # Mock the client
enhancer.client = Mock() # Mock the client
steps = [
{
"description": "scraper.scrape(url)",
"code": "result = scraper.scrape(url)",
}
]
result = enhancer.enhance_step_descriptions(steps)
steps = [
{
"description": "scraper.scrape(url)",
"code": "result = scraper.scrape(url)",
}
]
result = enhancer.enhance_step_descriptions(steps)
assert len(result) == 1
assert isinstance(result[0], StepEnhancement)
assert result[0].step_index == 0
assert "Initialize" in result[0].explanation
assert len(result[0].variations) == 1
assert len(result) == 1
assert isinstance(result[0], StepEnhancement)
assert result[0].step_index == 0
assert "Initialize" in result[0].explanation
assert len(result[0].variations) == 1
def test_enhance_step_descriptions_malformed_json(self):
"""Test handling of malformed JSON response"""
@@ -167,31 +163,29 @@ class TestGuideEnhancerTroubleshooting:
}
)
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}), patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True), patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
enhancer.client = Mock()
guide_data = {
"title": "Test Guide",
"steps": [{"description": "import requests", "code": "import requests"}],
"language": "python",
}
result = enhancer.enhance_troubleshooting(guide_data)
guide_data = {
"title": "Test Guide",
"steps": [{"description": "import requests", "code": "import requests"}],
"language": "python",
}
result = enhancer.enhance_troubleshooting(guide_data)
assert len(result) == 1
assert isinstance(result[0], TroubleshootingItem)
assert "ImportError" in result[0].problem
assert len(result[0].symptoms) == 2
assert len(result[0].diagnostic_steps) == 2
assert "pip install" in result[0].solution
assert len(result) == 1
assert isinstance(result[0], TroubleshootingItem)
assert "ImportError" in result[0].problem
assert len(result[0].symptoms) == 2
assert len(result[0].diagnostic_steps) == 2
assert "pip install" in result[0].solution
class TestGuideEnhancerPrerequisites:
@@ -230,26 +224,24 @@ class TestGuideEnhancerPrerequisites:
}
)
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}), patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True), patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
enhancer.client = Mock()
prereqs = ["requests", "beautifulsoup4"]
result = enhancer.enhance_prerequisites(prereqs)
prereqs = ["requests", "beautifulsoup4"]
result = enhancer.enhance_prerequisites(prereqs)
assert len(result) == 2
assert isinstance(result[0], PrerequisiteItem)
assert result[0].name == "requests"
assert "HTTP client" in result[0].why
assert "pip install" in result[0].setup
assert len(result) == 2
assert isinstance(result[0], PrerequisiteItem)
assert result[0].name == "requests"
assert "HTTP client" in result[0].why
assert "pip install" in result[0].setup
class TestGuideEnhancerNextSteps:
@@ -275,24 +267,22 @@ class TestGuideEnhancerNextSteps:
}
)
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}), patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True), patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
enhancer.client = Mock()
guide_data = {"title": "How to Scrape Docs", "description": "Basic scraping"}
result = enhancer.enhance_next_steps(guide_data)
guide_data = {"title": "How to Scrape Docs", "description": "Basic scraping"}
result = enhancer.enhance_next_steps(guide_data)
assert len(result) == 3
assert "async" in result[0].lower()
assert "error" in result[1].lower()
assert len(result) == 3
assert "async" in result[0].lower()
assert "error" in result[1].lower()
class TestGuideEnhancerUseCases:
@@ -317,27 +307,25 @@ class TestGuideEnhancerUseCases:
}
)
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}), patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True), patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
enhancer.client = Mock()
guide_data = {
"title": "How to Scrape Docs",
"description": "Documentation scraping",
}
result = enhancer.enhance_use_cases(guide_data)
guide_data = {
"title": "How to Scrape Docs",
"description": "Documentation scraping",
}
result = enhancer.enhance_use_cases(guide_data)
assert len(result) == 2
assert "automate" in result[0].lower()
assert "knowledge base" in result[1].lower()
assert len(result) == 2
assert "automate" in result[0].lower()
assert "knowledge base" in result[1].lower()
class TestGuideEnhancerFullWorkflow:
@@ -393,37 +381,35 @@ class TestGuideEnhancerFullWorkflow:
}
)
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}), patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True), patch(
"skill_seekers.cli.guide_enhancer.anthropic", create=True
) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
enhancer.client = Mock()
guide_data = {
"title": "How to Scrape Documentation",
"steps": [
{"description": "Import libraries", "code": "import requests"},
{"description": "Create scraper", "code": "scraper = Scraper()"},
],
"language": "python",
"prerequisites": ["requests"],
"description": "Basic scraping guide",
}
guide_data = {
"title": "How to Scrape Documentation",
"steps": [
{"description": "Import libraries", "code": "import requests"},
{"description": "Create scraper", "code": "scraper = Scraper()"},
],
"language": "python",
"prerequisites": ["requests"],
"description": "Basic scraping guide",
}
result = enhancer.enhance_guide(guide_data)
result = enhancer.enhance_guide(guide_data)
# Check enhancements were applied
assert "step_enhancements" in result
assert "troubleshooting_detailed" in result
assert "prerequisites_detailed" in result
assert "next_steps_detailed" in result
assert "use_cases" in result
# Check enhancements were applied
assert "step_enhancements" in result
assert "troubleshooting_detailed" in result
assert "prerequisites_detailed" in result
assert "next_steps_detailed" in result
assert "use_cases" in result
def test_enhance_guide_error_fallback(self):
"""Test graceful fallback on enhancement error"""

View File

@@ -431,16 +431,15 @@ class TestInstallAgentCLI:
with patch(
"skill_seekers.cli.install_agent.get_agent_path", side_effect=mock_get_agent_path
), patch(
"sys.argv",
["install_agent.py", str(self.skill_dir), "--agent", "claude", "--dry-run"],
):
with patch(
"sys.argv",
["install_agent.py", str(self.skill_dir), "--agent", "claude", "--dry-run"],
):
exit_code = main()
exit_code = main()
assert exit_code == 0
# Directory should NOT be created
assert not (Path(agent_tmpdir) / ".claude" / "skills" / "test-skill").exists()
assert exit_code == 0
# Directory should NOT be created
assert not (Path(agent_tmpdir) / ".claude" / "skills" / "test-skill").exists()
def test_cli_integration(self):
"""Test end-to-end CLI execution."""
@@ -451,18 +450,17 @@ class TestInstallAgentCLI:
with patch(
"skill_seekers.cli.install_agent.get_agent_path", side_effect=mock_get_agent_path
), patch(
"sys.argv",
["install_agent.py", str(self.skill_dir), "--agent", "claude", "--force"],
):
with patch(
"sys.argv",
["install_agent.py", str(self.skill_dir), "--agent", "claude", "--force"],
):
exit_code = main()
exit_code = main()
assert exit_code == 0
# Directory should be created
target = Path(agent_tmpdir) / ".claude" / "skills" / "test-skill"
assert target.exists()
assert (target / "SKILL.md").exists()
assert exit_code == 0
# Directory should be created
target = Path(agent_tmpdir) / ".claude" / "skills" / "test-skill"
assert target.exists()
assert (target / "SKILL.md").exists()
def test_cli_install_to_all(self):
"""Test CLI with --agent all."""
@@ -473,19 +471,18 @@ class TestInstallAgentCLI:
with patch(
"skill_seekers.cli.install_agent.get_agent_path", side_effect=mock_get_agent_path
), patch(
"sys.argv",
["install_agent.py", str(self.skill_dir), "--agent", "all", "--force"],
):
with patch(
"sys.argv",
["install_agent.py", str(self.skill_dir), "--agent", "all", "--force"],
):
exit_code = main()
exit_code = main()
assert exit_code == 0
assert exit_code == 0
# All agent directories should be created
for agent in get_available_agents():
target = Path(agent_tmpdir) / f".{agent}" / "skills" / "test-skill"
assert target.exists(), f"Directory not created for {agent}"
# All agent directories should be created
for agent in get_available_agents():
target = Path(agent_tmpdir) / f".{agent}" / "skills" / "test-skill"
assert target.exists(), f"Directory not created for {agent}"
if __name__ == "__main__":

View File

@@ -8,6 +8,7 @@ Tests verify complete fixes for:
3. Custom API endpoint support (ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN)
"""
import contextlib
import os
import shutil
import subprocess
@@ -169,11 +170,8 @@ class TestIssue219Problem2CLIFlags(unittest.TestCase):
mock_github_main.return_value = 0
# Call main dispatcher
with patch("sys.exit"):
try:
main.main()
except SystemExit:
pass
with patch("sys.exit"), contextlib.suppress(SystemExit):
main.main()
# VERIFY: github_scraper.main was called
mock_github_main.assert_called_once()

View File

@@ -69,7 +69,7 @@ class TestFastMCPHTTP:
app = mcp.sse_app()
with TestClient(app) as client:
with TestClient(app):
# SSE endpoint should exist (even if we can't fully test it without MCP client)
# Just verify the route is registered
routes = [route.path for route in app.routes if hasattr(route, "path")]

View File

@@ -57,7 +57,7 @@ def test_detect_unified_format():
try:
validator = ConfigValidator(config_path)
assert validator.is_unified == False
assert not validator.is_unified
finally:
os.unlink(config_path)
@@ -115,7 +115,7 @@ def test_needs_api_merge():
}
validator = ConfigValidator(config_no_merge)
assert validator.needs_api_merge() == False
assert not validator.needs_api_merge()
def test_backward_compatibility():