feat: implement comprehensive configuration management system with multi-mirror support

- Add ServerSettings class with pydantic-settings for type-safe configuration
- Support multiple PyPI mirror sources with priority-based fallback mechanism
- Implement RepositoryConfig and RepositoryManager for multi-repository support
- Add environment variable support for all configuration options
- Include private repository authentication configuration
- Add advanced dependency analysis settings (max depth, concurrency, security)
- Provide secure credential management with sensitive data masking
- Update documentation and configuration examples
- Add comprehensive test suite with 23 test cases covering all features
- Include demo script showcasing multi-mirror configuration capabilities

Configuration features:
- Primary, additional, and fallback index URLs
- Automatic duplicate URL removal with priority preservation
- Runtime configuration reloading
- Integration with repository manager for seamless multi-source queries

Signed-off-by: longhao <hal.long@outlook.com>
This commit is contained in:
longhao 2025-05-27 17:36:25 +08:00 committed by Hal
parent f27493d8d2
commit a0c507c3ff
20 changed files with 1276 additions and 165 deletions

View file

@ -99,6 +99,7 @@ class PyPIClient:
def _is_cache_valid(self, cache_entry: dict[str, Any]) -> bool:
"""Check if cache entry is still valid."""
import time
return time.time() - cache_entry.get("timestamp", 0) < self._cache_ttl
async def _make_request(self, url: str) -> dict[str, Any]:
@ -140,7 +141,7 @@ class PyPIClient:
else:
raise PyPIServerError(
response.status_code,
f"Unexpected status code: {response.status_code}"
f"Unexpected status code: {response.status_code}",
)
except httpx.TimeoutException as e:
@ -155,12 +156,16 @@ class PyPIClient:
# Wait before retry (except on last attempt)
if attempt < self.max_retries:
await asyncio.sleep(self.retry_delay * (2 ** attempt)) # Exponential backoff
await asyncio.sleep(
self.retry_delay * (2**attempt)
) # Exponential backoff
# If we get here, all retries failed
raise last_exception
async def get_package_info(self, package_name: str, use_cache: bool = True) -> dict[str, Any]:
async def get_package_info(
self, package_name: str, use_cache: bool = True
) -> dict[str, Any]:
"""Get comprehensive package information from PyPI.
Args:
@ -194,10 +199,8 @@ class PyPIClient:
# Cache the result
import time
self._cache[cache_key] = {
"data": data,
"timestamp": time.time()
}
self._cache[cache_key] = {"data": data, "timestamp": time.time()}
return data
@ -205,7 +208,9 @@ class PyPIClient:
logger.error(f"Failed to fetch package info for {normalized_name}: {e}")
raise
async def get_package_versions(self, package_name: str, use_cache: bool = True) -> list[str]:
async def get_package_versions(
self, package_name: str, use_cache: bool = True
) -> list[str]:
"""Get list of available versions for a package.
Args:
@ -219,7 +224,9 @@ class PyPIClient:
releases = package_info.get("releases", {})
return list(releases.keys())
async def get_latest_version(self, package_name: str, use_cache: bool = True) -> str:
async def get_latest_version(
self, package_name: str, use_cache: bool = True
) -> str:
"""Get the latest version of a package.
Args: