Skip to content

Commit 4fc5461

Browse files
hanselhanselclaude
andcommitted
Fix pyproject.toml section ordering and test compatibility
- Move [project.urls] after dependencies to fix TOML parsing error - Remove License classifier (superseded by license expression per PEP 639) - Fix crawler tests to patch crawl4ai.AsyncWebCrawler (lazy import) - Fix MCP server tests to use FunctionTool.fn (FastMCP 2.x API) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f64402c commit 4fc5461

3 files changed

Lines changed: 17 additions & 18 deletions

File tree

pyproject.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ classifiers = [
1717
"Development Status :: 4 - Beta",
1818
"Environment :: Console",
1919
"Intended Audience :: Developers",
20-
"License :: OSI Approved :: MIT License",
2120
"Programming Language :: Python :: 3",
2221
"Programming Language :: Python :: 3.10",
2322
"Programming Language :: Python :: 3.11",
@@ -27,10 +26,6 @@ classifiers = [
2726
"Typing :: Typed",
2827
]
2928

30-
[project.urls]
31-
Homepage = "https://github.com/hanselhansel/aeo-cli"
32-
Repository = "https://github.com/hanselhansel/aeo-cli"
33-
Issues = "https://github.com/hanselhansel/aeo-cli/issues"
3429
dependencies = [
3530
"typer>=0.9",
3631
"rich>=13.0",
@@ -41,6 +36,11 @@ dependencies = [
4136
"fastmcp>=2.0",
4237
]
4338

39+
[project.urls]
40+
Homepage = "https://github.com/hanselhansel/aeo-cli"
41+
Repository = "https://github.com/hanselhansel/aeo-cli"
42+
Issues = "https://github.com/hanselhansel/aeo-cli/issues"
43+
4444
[project.optional-dependencies]
4545
dev = [
4646
"pytest>=8.0",

tests/test_crawler_errors.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,16 @@
1313
async def test_crawl4ai_import_error():
1414
"""If crawl4ai is not installed, extract_page should return a failed CrawlResult."""
1515
with patch.dict("sys.modules", {"crawl4ai": None}):
16-
with patch("aeo_cli.core.crawler.AsyncWebCrawler", side_effect=ImportError("No module")):
17-
pass
18-
# Simulate import failure by patching the import inside extract_page
19-
with patch("builtins.__import__", side_effect=ImportError("No module named 'crawl4ai'")):
2016
result = await extract_page("https://example.com")
2117

2218
assert result.success is False
2319
assert result.error is not None
24-
assert "crawl4ai" in result.error.lower() or "module" in result.error.lower()
2520

2621

2722
@pytest.mark.asyncio
2823
async def test_crawler_generic_exception():
2924
"""A generic exception during crawl should be captured, not raised."""
30-
with patch("aeo_cli.core.crawler.AsyncWebCrawler") as mock_cls:
25+
with patch("crawl4ai.AsyncWebCrawler") as mock_cls:
3126
mock_crawler = AsyncMock()
3227
mock_crawler.arun.side_effect = RuntimeError("Browser crashed")
3328
mock_cls.return_value.__aenter__ = AsyncMock(return_value=mock_crawler)
@@ -48,7 +43,7 @@ async def test_crawler_returns_failed_result():
4843
mock_result.markdown = ""
4944
mock_result.links = {}
5045

51-
with patch("aeo_cli.core.crawler.AsyncWebCrawler") as mock_cls:
46+
with patch("crawl4ai.AsyncWebCrawler") as mock_cls:
5247
mock_crawler = AsyncMock()
5348
mock_crawler.arun.return_value = mock_result
5449
mock_cls.return_value.__aenter__ = AsyncMock(return_value=mock_crawler)
@@ -71,7 +66,7 @@ async def test_crawler_successful_extraction():
7166
"external": [{"href": "https://other.com"}],
7267
}
7368

74-
with patch("aeo_cli.core.crawler.AsyncWebCrawler") as mock_cls:
69+
with patch("crawl4ai.AsyncWebCrawler") as mock_cls:
7570
mock_crawler = AsyncMock()
7671
mock_crawler.arun.return_value = mock_result
7772
mock_cls.return_value.__aenter__ = AsyncMock(return_value=mock_crawler)

tests/test_mcp_server.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,18 @@
99
from aeo_cli.core.models import (
1010
AuditReport,
1111
ContentReport,
12+
DiscoveryResult,
1213
LlmsTxtReport,
1314
RobotsReport,
1415
SchemaReport,
1516
SiteAuditReport,
16-
DiscoveryResult,
1717
)
1818
from aeo_cli.server import audit
1919

20+
# FastMCP 2.x wraps @mcp.tool functions in a FunctionTool object.
21+
# The underlying async function is accessible via .fn
22+
_audit_fn = audit.fn
23+
2024

2125
def _mock_single_report() -> AuditReport:
2226
return AuditReport(
@@ -49,7 +53,7 @@ async def test_audit_tool_single_page():
4953
with patch("aeo_cli.server.audit_url", new_callable=AsyncMock) as mock_audit:
5054
mock_audit.return_value = _mock_single_report()
5155

52-
result = await audit("https://example.com", single_page=True)
56+
result = await _audit_fn("https://example.com", single_page=True)
5357

5458
mock_audit.assert_called_once_with("https://example.com")
5559
assert result["url"] == "https://example.com"
@@ -64,7 +68,7 @@ async def test_audit_tool_site_audit():
6468
with patch("aeo_cli.server.audit_site", new_callable=AsyncMock) as mock_audit:
6569
mock_audit.return_value = _mock_site_report()
6670

67-
result = await audit("https://example.com")
71+
result = await _audit_fn("https://example.com")
6872

6973
mock_audit.assert_called_once_with("https://example.com", max_pages=10)
7074
assert result["domain"] == "example.com"
@@ -78,7 +82,7 @@ async def test_audit_tool_custom_max_pages():
7882
with patch("aeo_cli.server.audit_site", new_callable=AsyncMock) as mock_audit:
7983
mock_audit.return_value = _mock_site_report()
8084

81-
await audit("https://example.com", max_pages=5)
85+
await _audit_fn("https://example.com", max_pages=5)
8286

8387
mock_audit.assert_called_once_with("https://example.com", max_pages=5)
8488

@@ -89,6 +93,6 @@ async def test_audit_tool_returns_dict():
8993
with patch("aeo_cli.server.audit_url", new_callable=AsyncMock) as mock_audit:
9094
mock_audit.return_value = _mock_single_report()
9195

92-
result = await audit("https://example.com", single_page=True)
96+
result = await _audit_fn("https://example.com", single_page=True)
9397

9498
assert isinstance(result, dict)

0 commit comments

Comments
 (0)