style: fix code formatting and linting issues

- Fix whitespace in docstrings and blank lines
- Remove unused variables in tests
- Rename unused loop variables to follow conventions
- All ruff checks now pass

Signed-off-by: Hal <hal.long@outlook.com>
This commit is contained in:
longhao 2025-05-27 18:58:25 +08:00 committed by Hal
parent 6b14ff6da5
commit f2b92ff0ee
6 changed files with 196 additions and 205 deletions

View File

@ -28,13 +28,13 @@ async def analyze_pyside2_dependencies():
) )
print(f"✅ Successfully resolved dependencies for {result['package_name']}") print(f"✅ Successfully resolved dependencies for {result['package_name']}")
print(f"📊 Summary:") print("📊 Summary:")
summary = result['summary'] summary = result['summary']
print(f" - Total packages: {summary['total_packages']}") print(f" - Total packages: {summary['total_packages']}")
print(f" - Runtime dependencies: {summary['total_runtime_dependencies']}") print(f" - Runtime dependencies: {summary['total_runtime_dependencies']}")
print(f" - Max depth: {summary['max_depth']}") print(f" - Max depth: {summary['max_depth']}")
print(f"\n📦 Package list:") print("\n📦 Package list:")
for i, pkg in enumerate(summary['package_list'][:10], 1): # Show first 10 for i, pkg in enumerate(summary['package_list'][:10], 1): # Show first 10
print(f" {i}. {pkg}") print(f" {i}. {pkg}")
@ -66,8 +66,8 @@ async def download_pyside2_packages():
max_depth=2 # Limit depth for demo max_depth=2 # Limit depth for demo
) )
print(f"✅ Download completed!") print("✅ Download completed!")
print(f"📊 Download Summary:") print("📊 Download Summary:")
summary = result['summary'] summary = result['summary']
print(f" - Total packages: {summary['total_packages']}") print(f" - Total packages: {summary['total_packages']}")
print(f" - Successful downloads: {summary['successful_downloads']}") print(f" - Successful downloads: {summary['successful_downloads']}")
@ -77,7 +77,7 @@ async def download_pyside2_packages():
print(f" - Download directory: {summary['download_directory']}") print(f" - Download directory: {summary['download_directory']}")
if result['failed_downloads']: if result['failed_downloads']:
print(f"\n⚠️ Failed downloads:") print("\n⚠️ Failed downloads:")
for failure in result['failed_downloads']: for failure in result['failed_downloads']:
print(f" - {failure['package']}: {failure['error']}") print(f" - {failure['package']}: {failure['error']}")
@ -104,10 +104,10 @@ async def analyze_small_package():
print(f"✅ Successfully resolved dependencies for {result['package_name']}") print(f"✅ Successfully resolved dependencies for {result['package_name']}")
# Show detailed dependency tree # Show detailed dependency tree
print(f"\n🌳 Dependency Tree:") print("\n🌳 Dependency Tree:")
dependency_tree = result['dependency_tree'] dependency_tree = result['dependency_tree']
for pkg_name, pkg_info in dependency_tree.items(): for _pkg_name, pkg_info in dependency_tree.items():
indent = " " * pkg_info['depth'] indent = " " * pkg_info['depth']
print(f"{indent}- {pkg_info['name']} ({pkg_info['version']})") print(f"{indent}- {pkg_info['name']} ({pkg_info['version']})")
@ -143,12 +143,12 @@ async def main():
print("✨ Demo completed!") print("✨ Demo completed!")
if click_result: if click_result:
print(f"📝 Click analysis saved to: click_dependencies.json") print("📝 Click analysis saved to: click_dependencies.json")
with open("click_dependencies.json", "w") as f: with open("click_dependencies.json", "w") as f:
json.dump(click_result, f, indent=2) json.dump(click_result, f, indent=2)
if pyside2_result: if pyside2_result:
print(f"📝 PySide2 analysis saved to: pyside2_dependencies.json") print("📝 PySide2 analysis saved to: pyside2_dependencies.json")
with open("pyside2_dependencies.json", "w") as f: with open("pyside2_dependencies.json", "w") as f:
json.dump(pyside2_result, f, indent=2) json.dump(pyside2_result, f, indent=2)

View File

@ -1,11 +1,11 @@
"""Dependency parsing utilities for PyPI packages.""" """Dependency parsing utilities for PyPI packages."""
import re
from typing import Any, Dict, List, Optional, Set, Tuple
from packaging.requirements import Requirement
from packaging.specifiers import SpecifierSet
from packaging.version import Version
import logging import logging
import re
from typing import Any
from packaging.requirements import Requirement
from packaging.version import Version
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -14,9 +14,9 @@ class DependencyParser:
"""Parser for Python package dependencies.""" """Parser for Python package dependencies."""
def __init__(self): def __init__(self):
self.parsed_cache: Dict[str, List[Requirement]] = {} self.parsed_cache: dict[str, list[Requirement]] = {}
def parse_requirements(self, requires_dist: List[str]) -> List[Requirement]: def parse_requirements(self, requires_dist: list[str]) -> list[Requirement]:
"""Parse requirements from requires_dist list. """Parse requirements from requires_dist list.
Args: Args:
@ -42,9 +42,9 @@ class DependencyParser:
def filter_requirements_by_python_version( def filter_requirements_by_python_version(
self, self,
requirements: List[Requirement], requirements: list[Requirement],
python_version: str python_version: str
) -> List[Requirement]: ) -> list[Requirement]:
"""Filter requirements based on Python version. """Filter requirements based on Python version.
Args: Args:
@ -99,8 +99,8 @@ class DependencyParser:
def categorize_dependencies( def categorize_dependencies(
self, self,
requirements: List[Requirement] requirements: list[Requirement]
) -> Dict[str, List[Requirement]]: ) -> dict[str, list[Requirement]]:
"""Categorize dependencies into runtime, development, and optional groups. """Categorize dependencies into runtime, development, and optional groups.
Args: Args:
@ -142,7 +142,7 @@ class DependencyParser:
return categories return categories
def extract_package_names(self, requirements: List[Requirement]) -> Set[str]: def extract_package_names(self, requirements: list[Requirement]) -> set[str]:
"""Extract package names from requirements. """Extract package names from requirements.
Args: Args:
@ -153,7 +153,7 @@ class DependencyParser:
""" """
return {req.name.lower() for req in requirements} return {req.name.lower() for req in requirements}
def get_version_constraints(self, req: Requirement) -> Dict[str, Any]: def get_version_constraints(self, req: Requirement) -> dict[str, Any]:
"""Get version constraints from a requirement. """Get version constraints from a requirement.
Args: Args:

View File

@ -1,13 +1,15 @@
"""Dependency resolution tools for PyPI packages.""" """Dependency resolution tools for PyPI packages."""
import asyncio
import logging import logging
from typing import Any, Dict, List, Optional, Set from typing import Any
from packaging.requirements import Requirement
from ..core import PyPIClient, PyPIError from ..core import PyPIClient, PyPIError
from ..core.dependency_parser import DependencyParser from ..core.dependency_parser import DependencyParser
from ..core.exceptions import InvalidPackageNameError, NetworkError, PackageNotFoundError from ..core.exceptions import (
InvalidPackageNameError,
NetworkError,
PackageNotFoundError,
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -18,16 +20,16 @@ class DependencyResolver:
def __init__(self, max_depth: int = 10): def __init__(self, max_depth: int = 10):
self.max_depth = max_depth self.max_depth = max_depth
self.parser = DependencyParser() self.parser = DependencyParser()
self.resolved_cache: Dict[str, Dict[str, Any]] = {} self.resolved_cache: dict[str, dict[str, Any]] = {}
async def resolve_dependencies( async def resolve_dependencies(
self, self,
package_name: str, package_name: str,
python_version: Optional[str] = None, python_version: str | None = None,
include_extras: Optional[List[str]] = None, include_extras: list[str] | None = None,
include_dev: bool = False, include_dev: bool = False,
max_depth: Optional[int] = None max_depth: int | None = None
) -> Dict[str, Any]: ) -> dict[str, Any]:
"""Resolve all dependencies for a package recursively. """Resolve all dependencies for a package recursively.
Args: Args:
@ -49,7 +51,7 @@ class DependencyResolver:
logger.info(f"Resolving dependencies for {package_name} (Python {python_version})") logger.info(f"Resolving dependencies for {package_name} (Python {python_version})")
# Track visited packages to avoid circular dependencies # Track visited packages to avoid circular dependencies
visited: Set[str] = set() visited: set[str] = set()
dependency_tree = {} dependency_tree = {}
try: try:
@ -90,11 +92,11 @@ class DependencyResolver:
async def _resolve_recursive( async def _resolve_recursive(
self, self,
package_name: str, package_name: str,
python_version: Optional[str], python_version: str | None,
include_extras: List[str], include_extras: list[str],
include_dev: bool, include_dev: bool,
visited: Set[str], visited: set[str],
dependency_tree: Dict[str, Any], dependency_tree: dict[str, Any],
current_depth: int, current_depth: int,
max_depth: int max_depth: int
) -> None: ) -> None:
@ -188,7 +190,7 @@ class DependencyResolver:
logger.error(f"Error resolving {package_name}: {e}") logger.error(f"Error resolving {package_name}: {e}")
# Continue with other dependencies # Continue with other dependencies
def _generate_dependency_summary(self, dependency_tree: Dict[str, Any]) -> Dict[str, Any]: def _generate_dependency_summary(self, dependency_tree: dict[str, Any]) -> dict[str, Any]:
"""Generate summary statistics for the dependency tree.""" """Generate summary statistics for the dependency tree."""
total_packages = len(dependency_tree) total_packages = len(dependency_tree)
@ -218,11 +220,11 @@ class DependencyResolver:
async def resolve_package_dependencies( async def resolve_package_dependencies(
package_name: str, package_name: str,
python_version: Optional[str] = None, python_version: str | None = None,
include_extras: Optional[List[str]] = None, include_extras: list[str] | None = None,
include_dev: bool = False, include_dev: bool = False,
max_depth: int = 5 max_depth: int = 5
) -> Dict[str, Any]: ) -> dict[str, Any]:
"""Resolve package dependencies with comprehensive analysis. """Resolve package dependencies with comprehensive analysis.
Args: Args:

View File

@ -1,17 +1,18 @@
"""Package download tools for PyPI packages.""" """Package download tools for PyPI packages."""
import asyncio
import hashlib import hashlib
import logging import logging
import os
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional, Set from typing import Any
from urllib.parse import urlparse
import httpx import httpx
from ..core import PyPIClient, PyPIError from ..core import PyPIClient, PyPIError
from ..core.exceptions import InvalidPackageNameError, NetworkError, PackageNotFoundError from ..core.exceptions import (
InvalidPackageNameError,
NetworkError,
PackageNotFoundError,
)
from .dependency_resolver import DependencyResolver from .dependency_resolver import DependencyResolver
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -28,13 +29,13 @@ class PackageDownloader:
async def download_package_with_dependencies( async def download_package_with_dependencies(
self, self,
package_name: str, package_name: str,
python_version: Optional[str] = None, python_version: str | None = None,
include_extras: Optional[List[str]] = None, include_extras: list[str] | None = None,
include_dev: bool = False, include_dev: bool = False,
prefer_wheel: bool = True, prefer_wheel: bool = True,
verify_checksums: bool = True, verify_checksums: bool = True,
max_depth: int = 5 max_depth: int = 5
) -> Dict[str, Any]: ) -> dict[str, Any]:
"""Download a package and all its dependencies. """Download a package and all its dependencies.
Args: Args:
@ -110,11 +111,11 @@ class PackageDownloader:
async def _download_single_package( async def _download_single_package(
self, self,
package_name: str, package_name: str,
version: Optional[str] = None, version: str | None = None,
python_version: Optional[str] = None, python_version: str | None = None,
prefer_wheel: bool = True, prefer_wheel: bool = True,
verify_checksums: bool = True verify_checksums: bool = True
) -> Dict[str, Any]: ) -> dict[str, Any]:
"""Download a single package.""" """Download a single package."""
logger.info(f"Downloading {package_name} version {version or 'latest'}") logger.info(f"Downloading {package_name} version {version or 'latest'}")
@ -157,10 +158,10 @@ class PackageDownloader:
def _select_best_file( def _select_best_file(
self, self,
release_files: List[Dict[str, Any]], release_files: list[dict[str, Any]],
python_version: Optional[str] = None, python_version: str | None = None,
prefer_wheel: bool = True prefer_wheel: bool = True
) -> Optional[Dict[str, Any]]: ) -> dict[str, Any] | None:
"""Select the best file to download from available release files.""" """Select the best file to download from available release files."""
# Separate wheels and source distributions # Separate wheels and source distributions
@ -187,9 +188,9 @@ class PackageDownloader:
def _filter_compatible_wheels( def _filter_compatible_wheels(
self, self,
wheels: List[Dict[str, Any]], wheels: list[dict[str, Any]],
python_version: str python_version: str
) -> List[Dict[str, Any]]: ) -> list[dict[str, Any]]:
"""Filter wheels compatible with the specified Python version.""" """Filter wheels compatible with the specified Python version."""
# Simple compatibility check based on filename # Simple compatibility check based on filename
@ -213,9 +214,9 @@ class PackageDownloader:
async def _download_file( async def _download_file(
self, self,
file_info: Dict[str, Any], file_info: dict[str, Any],
verify_checksums: bool = True verify_checksums: bool = True
) -> Dict[str, Any]: ) -> dict[str, Any]:
"""Download a single file.""" """Download a single file."""
url = file_info.get("url") url = file_info.get("url")
@ -269,9 +270,9 @@ class PackageDownloader:
def _generate_download_summary( def _generate_download_summary(
self, self,
download_results: Dict[str, Any], download_results: dict[str, Any],
failed_downloads: List[Dict[str, Any]] failed_downloads: list[dict[str, Any]]
) -> Dict[str, Any]: ) -> dict[str, Any]:
"""Generate download summary statistics.""" """Generate download summary statistics."""
successful_downloads = len(download_results) successful_downloads = len(download_results)
@ -295,13 +296,13 @@ class PackageDownloader:
async def download_package_with_dependencies( async def download_package_with_dependencies(
package_name: str, package_name: str,
download_dir: str = "./downloads", download_dir: str = "./downloads",
python_version: Optional[str] = None, python_version: str | None = None,
include_extras: Optional[List[str]] = None, include_extras: list[str] | None = None,
include_dev: bool = False, include_dev: bool = False,
prefer_wheel: bool = True, prefer_wheel: bool = True,
verify_checksums: bool = True, verify_checksums: bool = True,
max_depth: int = 5 max_depth: int = 5
) -> Dict[str, Any]: ) -> dict[str, Any]:
"""Download a package and its dependencies to local directory. """Download a package and its dependencies to local directory.
Args: Args:

View File

@ -1,10 +1,14 @@
"""Tests for dependency resolver functionality.""" """Tests for dependency resolver functionality."""
import pytest
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from pypi_query_mcp.tools.dependency_resolver import DependencyResolver, resolve_package_dependencies import pytest
from pypi_query_mcp.core.exceptions import InvalidPackageNameError, PackageNotFoundError from pypi_query_mcp.core.exceptions import InvalidPackageNameError, PackageNotFoundError
from pypi_query_mcp.tools.dependency_resolver import (
DependencyResolver,
resolve_package_dependencies,
)
class TestDependencyResolver: class TestDependencyResolver:

View File

@ -1,13 +1,16 @@
"""Tests for package downloader functionality.""" """Tests for package downloader functionality."""
import pytest
from pathlib import Path
from unittest.mock import AsyncMock, patch, mock_open
import tempfile
import shutil import shutil
import tempfile
from unittest.mock import AsyncMock, mock_open, patch
from pypi_query_mcp.tools.package_downloader import PackageDownloader, download_package_with_dependencies import pytest
from pypi_query_mcp.core.exceptions import InvalidPackageNameError, PackageNotFoundError
from pypi_query_mcp.core.exceptions import InvalidPackageNameError
from pypi_query_mcp.tools.package_downloader import (
PackageDownloader,
download_package_with_dependencies,
)
class TestPackageDownloader: class TestPackageDownloader:
@ -218,25 +221,6 @@ class TestPackageDownloader:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_download_package_with_dependencies_function(self, temp_download_dir): async def test_download_package_with_dependencies_function(self, temp_download_dir):
"""Test the standalone download_package_with_dependencies function.""" """Test the standalone download_package_with_dependencies function."""
mock_package_data = {
"info": {
"name": "test-package",
"version": "1.0.0",
"requires_python": ">=3.8",
"requires_dist": []
},
"releases": {
"1.0.0": [
{
"filename": "test_package-1.0.0-py3-none-any.whl",
"url": "https://files.pythonhosted.org/packages/test_package-1.0.0-py3-none-any.whl",
"packagetype": "bdist_wheel",
"md5_digest": "abc123",
"size": 1024
}
]
}
}
with patch('pypi_query_mcp.tools.package_downloader.PackageDownloader') as mock_downloader_class: with patch('pypi_query_mcp.tools.package_downloader.PackageDownloader') as mock_downloader_class:
# Setup downloader mock # Setup downloader mock