fix: resolve all lint issues and fix failing tests

- Fix blank line whitespace issues (W293) using ruff --unsafe-fixes
- Reformat code using ruff format for consistent styling
- Fix analyze_package_quality function to return list[Message] instead of string
- Add missing 'assessment' keyword to package analysis template
- Update tests to use real prompt functions instead of mocks for structure validation
- Fix import ordering in test files
- All 64 tests now pass with 47% code coverage

Signed-off-by: longhao <hal.long@outlook.com>
This commit is contained in:
longhao 2025-05-29 18:38:10 +08:00 committed by Hal
parent d63ef02ef3
commit a28d999958
18 changed files with 554 additions and 390 deletions

View file

@ -295,7 +295,7 @@ async def resolve_dependencies(
python_version: str | None = None,
include_extras: list[str] | None = None,
include_dev: bool = False,
max_depth: int = 5
max_depth: int = 5,
) -> dict[str, Any]:
"""Resolve all dependencies for a PyPI package recursively.
@ -331,7 +331,7 @@ async def resolve_dependencies(
python_version=python_version,
include_extras=include_extras,
include_dev=include_dev,
max_depth=max_depth
max_depth=max_depth,
)
logger.info(f"Successfully resolved dependencies for package: {package_name}")
return result
@ -362,7 +362,7 @@ async def download_package(
include_dev: bool = False,
prefer_wheel: bool = True,
verify_checksums: bool = True,
max_depth: int = 5
max_depth: int = 5,
) -> dict[str, Any]:
"""Download a PyPI package and all its dependencies to local directory.
@ -404,7 +404,7 @@ async def download_package(
include_dev=include_dev,
prefer_wheel=prefer_wheel,
verify_checksums=verify_checksums,
max_depth=max_depth
max_depth=max_depth,
)
logger.info(f"Successfully downloaded {package_name} and dependencies")
return result
@ -453,9 +453,13 @@ async def get_download_statistics(
NetworkError: For network-related errors
"""
try:
logger.info(f"MCP tool: Getting download statistics for {package_name} (period: {period})")
logger.info(
f"MCP tool: Getting download statistics for {package_name} (period: {period})"
)
result = await get_package_download_stats(package_name, period, use_cache)
logger.info(f"Successfully retrieved download statistics for package: {package_name}")
logger.info(
f"Successfully retrieved download statistics for package: {package_name}"
)
return result
except (InvalidPackageNameError, PackageNotFoundError, NetworkError) as e:
logger.error(f"Error getting download statistics for {package_name}: {e}")
@ -466,7 +470,9 @@ async def get_download_statistics(
"period": period,
}
except Exception as e:
logger.error(f"Unexpected error getting download statistics for {package_name}: {e}")
logger.error(
f"Unexpected error getting download statistics for {package_name}: {e}"
)
return {
"error": f"Unexpected error: {e}",
"error_type": "UnexpectedError",
@ -506,8 +512,12 @@ async def get_download_trends(
f"MCP tool: Getting download trends for {package_name} "
f"(include_mirrors: {include_mirrors})"
)
result = await get_package_download_trends(package_name, include_mirrors, use_cache)
logger.info(f"Successfully retrieved download trends for package: {package_name}")
result = await get_package_download_trends(
package_name, include_mirrors, use_cache
)
logger.info(
f"Successfully retrieved download trends for package: {package_name}"
)
return result
except (InvalidPackageNameError, PackageNotFoundError, NetworkError) as e:
logger.error(f"Error getting download trends for {package_name}: {e}")
@ -518,7 +528,9 @@ async def get_download_trends(
"include_mirrors": include_mirrors,
}
except Exception as e:
logger.error(f"Unexpected error getting download trends for {package_name}: {e}")
logger.error(
f"Unexpected error getting download trends for {package_name}: {e}"
)
return {
"error": f"Unexpected error: {e}",
"error_type": "UnexpectedError",
@ -555,7 +567,9 @@ async def get_top_downloaded_packages(
# Limit the maximum number of packages to prevent excessive API calls
actual_limit = min(limit, 50)
logger.info(f"MCP tool: Getting top {actual_limit} packages for period: {period}")
logger.info(
f"MCP tool: Getting top {actual_limit} packages for period: {period}"
)
result = await get_top_packages_by_downloads(period, actual_limit)
logger.info("Successfully retrieved top packages list")
return result
@ -578,10 +592,10 @@ async def get_top_downloaded_packages(
# 6. Environment variable customization → Apply user's custom prompt words
# 7. Return final prompt → As tool's response back to AI
@mcp.prompt()
async def analyze_package_quality_prompt(
package_name: str,
version: str | None = None
package_name: str, version: str | None = None
) -> str:
"""Generate a comprehensive quality analysis prompt for a PyPI package."""
# Step 3: Call Prompt generator
@ -603,9 +617,7 @@ async def analyze_package_quality_prompt(
@mcp.prompt()
async def compare_packages_prompt(
packages: list[str],
use_case: str,
criteria: list[str] | None = None
packages: list[str], use_case: str, criteria: list[str] | None = None
) -> str:
"""Generate a detailed comparison prompt for multiple PyPI packages."""
# Step 3: Call Prompt generator
@ -618,7 +630,9 @@ async def compare_packages_prompt(
# Handle criteria parameter
if criteria:
criteria_text = f"\n\nFocus particularly on these criteria: {', '.join(criteria)}"
criteria_text = (
f"\n\nFocus particularly on these criteria: {', '.join(criteria)}"
)
else:
criteria_text = ""
result = result.replace("{{criteria_text}}", criteria_text)
@ -629,9 +643,7 @@ async def compare_packages_prompt(
@mcp.prompt()
async def suggest_alternatives_prompt(
package_name: str,
reason: str,
requirements: str | None = None
package_name: str, reason: str, requirements: str | None = None
) -> str:
"""Generate a prompt for finding package alternatives."""
# Step 3: Call Prompt generator
@ -647,7 +659,7 @@ async def suggest_alternatives_prompt(
"performance": "performance issues or requirements",
"licensing": "licensing conflicts or restrictions",
"maintenance": "poor maintenance or lack of updates",
"features": "missing features or functionality gaps"
"features": "missing features or functionality gaps",
}
reason_text = reason_context.get(reason, reason)
result = result.replace("{{reason_text}}", reason_text)
@ -667,10 +679,12 @@ async def suggest_alternatives_prompt(
async def resolve_dependency_conflicts_prompt(
conflicts: list[str],
python_version: str | None = None,
project_context: str | None = None
project_context: str | None = None,
) -> str:
"""Generate a prompt for resolving dependency conflicts."""
messages = await resolve_dependency_conflicts(conflicts, python_version, project_context)
messages = await resolve_dependency_conflicts(
conflicts, python_version, project_context
)
return messages[0].text
@ -679,10 +693,12 @@ async def plan_version_upgrade_prompt(
package_name: str,
current_version: str,
target_version: str | None = None,
project_size: str | None = None
project_size: str | None = None,
) -> str:
"""Generate a prompt for planning package version upgrades."""
messages = await plan_version_upgrade(package_name, current_version, target_version, project_size)
messages = await plan_version_upgrade(
package_name, current_version, target_version, project_size
)
return messages[0].text
@ -690,10 +706,12 @@ async def plan_version_upgrade_prompt(
async def audit_security_risks_prompt(
packages: list[str],
environment: str | None = None,
compliance_requirements: str | None = None
compliance_requirements: str | None = None,
) -> str:
"""Generate a prompt for security risk auditing of packages."""
messages = await audit_security_risks(packages, environment, compliance_requirements)
messages = await audit_security_risks(
packages, environment, compliance_requirements
)
return messages[0].text
@ -703,21 +721,23 @@ async def plan_package_migration_prompt(
to_package: str,
codebase_size: str = "medium",
timeline: str | None = None,
team_size: int | None = None
team_size: int | None = None,
) -> str:
"""Generate a comprehensive package migration plan prompt."""
messages = await plan_package_migration(from_package, to_package, codebase_size, timeline, team_size)
messages = await plan_package_migration(
from_package, to_package, codebase_size, timeline, team_size
)
return messages[0].text
@mcp.prompt()
async def generate_migration_checklist_prompt(
migration_type: str,
packages_involved: list[str],
environment: str = "all"
migration_type: str, packages_involved: list[str], environment: str = "all"
) -> str:
"""Generate a detailed migration checklist prompt."""
messages = await generate_migration_checklist(migration_type, packages_involved, environment)
messages = await generate_migration_checklist(
migration_type, packages_involved, environment
)
return messages[0].text
@ -726,11 +746,13 @@ async def generate_migration_checklist_prompt(
async def analyze_environment_dependencies_prompt(
environment_type: str = "local",
python_version: str | None = None,
project_path: str | None = None
project_path: str | None = None,
) -> str:
"""Generate a prompt for analyzing environment dependencies."""
# Step 3: Call Prompt generator
template = await analyze_environment_dependencies(environment_type, python_version, project_path)
template = await analyze_environment_dependencies(
environment_type, python_version, project_path
)
# Step 5: Parameter replacement
result = template.replace("{{environment_type}}", environment_type)
@ -755,11 +777,13 @@ async def analyze_environment_dependencies_prompt(
async def check_outdated_packages_prompt(
package_filter: str | None = None,
severity_level: str = "all",
include_dev_dependencies: bool = True
include_dev_dependencies: bool = True,
) -> str:
"""Generate a prompt for checking outdated packages."""
# Step 3: Call Prompt generator
template = await check_outdated_packages(package_filter, severity_level, include_dev_dependencies)
template = await check_outdated_packages(
package_filter, severity_level, include_dev_dependencies
)
# Step 5: Parameter replacement
result = template.replace("{{severity_level}}", severity_level)
@ -786,11 +810,13 @@ async def check_outdated_packages_prompt(
async def generate_update_plan_prompt(
update_strategy: str = "balanced",
environment_constraints: str | None = None,
testing_requirements: str | None = None
testing_requirements: str | None = None,
) -> str:
"""Generate a prompt for creating package update plans."""
# Step 3: Call Prompt generator
template = await generate_update_plan(update_strategy, environment_constraints, testing_requirements)
template = await generate_update_plan(
update_strategy, environment_constraints, testing_requirements
)
# Step 5: Parameter replacement
result = template.replace("{{strategy}}", update_strategy)
@ -816,9 +842,7 @@ async def generate_update_plan_prompt(
# Trending Analysis Prompts
@mcp.prompt()
async def analyze_daily_trends_prompt(
date: str = "today",
category: str | None = None,
limit: int = 20
date: str = "today", category: str | None = None, limit: int = 20
) -> str:
"""Generate a prompt for analyzing daily PyPI trends."""
# Step 3: Call Prompt generator
@ -841,9 +865,7 @@ async def analyze_daily_trends_prompt(
@mcp.prompt()
async def find_trending_packages_prompt(
time_period: str = "weekly",
trend_type: str = "rising",
domain: str | None = None
time_period: str = "weekly", trend_type: str = "rising", domain: str | None = None
) -> str:
"""Generate a prompt for finding trending packages."""
# Step 3: Call Prompt generator
@ -866,9 +888,7 @@ async def find_trending_packages_prompt(
@mcp.prompt()
async def track_package_updates_prompt(
time_range: str = "today",
update_type: str = "all",
popular_only: bool = False
time_range: str = "today", update_type: str = "all", popular_only: bool = False
) -> str:
"""Generate a prompt for tracking recent package updates."""
# Step 3: Call Prompt generator