Fix duplicate dependency constraint causing 500 errors

- Deduplicate dependencies by package name before inserting
- Some packages (like anyio) list the same dep (trio) multiple times with
  different version constraints for different extras
- The unique constraint on (artifact_id, project, package) rejected these
- Also removed debug logging from dependencies.py
This commit is contained in:
Mondo Diaz
2026-01-30 17:43:49 -06:00
parent 62c77dc16d
commit 044a6c1d27
2 changed files with 9 additions and 18 deletions

View File

@@ -10,11 +10,8 @@ Handles:
- Conflict detection - Conflict detection
""" """
import logging
import re import re
import yaml import yaml
logger = logging.getLogger(__name__)
from typing import List, Dict, Any, Optional, Set, Tuple from typing import List, Dict, Any, Optional, Set, Tuple
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from sqlalchemy import and_ from sqlalchemy import and_
@@ -435,8 +432,6 @@ def _resolve_dependency_to_artifact(
if not package: if not package:
return None return None
logger.info(f"_resolve_dependency_to_artifact: package_id={package.id}, version={version!r}, tag={tag!r}")
if version: if version:
# Check if this is a version constraint (>=, <, etc.) or exact version # Check if this is a version constraint (>=, <, etc.) or exact version
if _is_version_constraint(version): if _is_version_constraint(version):
@@ -454,7 +449,6 @@ def _resolve_dependency_to_artifact(
Artifact.id == pkg_version.artifact_id Artifact.id == pkg_version.artifact_id
).first() ).first()
if artifact: if artifact:
logger.info(f"_resolve_dependency_to_artifact: found by version {version}")
return (artifact.id, version, artifact.size) return (artifact.id, version, artifact.size)
# Also check if there's a tag with this exact name # Also check if there's a tag with this exact name
@@ -462,7 +456,6 @@ def _resolve_dependency_to_artifact(
Tag.package_id == package.id, Tag.package_id == package.id,
Tag.name == version, Tag.name == version,
).first() ).first()
logger.info(f"_resolve_dependency_to_artifact: tag lookup by version name, found={tag_record is not None}")
if tag_record: if tag_record:
artifact = db.query(Artifact).filter( artifact = db.query(Artifact).filter(
Artifact.id == tag_record.artifact_id Artifact.id == tag_record.artifact_id
@@ -476,7 +469,6 @@ def _resolve_dependency_to_artifact(
Tag.package_id == package.id, Tag.package_id == package.id,
Tag.name == tag, Tag.name == tag,
).first() ).first()
logger.info(f"_resolve_dependency_to_artifact: tag lookup by tag param, found={tag_record is not None}")
if tag_record: if tag_record:
artifact = db.query(Artifact).filter( artifact = db.query(Artifact).filter(
Artifact.id == tag_record.artifact_id Artifact.id == tag_record.artifact_id
@@ -484,9 +476,6 @@ def _resolve_dependency_to_artifact(
if artifact: if artifact:
return (artifact.id, tag, artifact.size) return (artifact.id, tag, artifact.size)
# Debug: list actual tags
sample_tags = db.query(Tag).filter(Tag.package_id == package.id).limit(3).all()
logger.info(f"_resolve_dependency_to_artifact: NOT FOUND. Sample tags: {[t.name for t in sample_tags]}")
return None return None
@@ -670,12 +659,9 @@ def resolve_dependencies(
CircularDependencyError: If circular dependencies are detected CircularDependencyError: If circular dependencies are detected
DependencyConflictError: If conflicting versions are required DependencyConflictError: If conflicting versions are required
""" """
logger.info(f"resolve_dependencies: project={project_name}, package={package_name}, ref={ref!r}")
# Resolve the initial artifact # Resolve the initial artifact
project = db.query(Project).filter(Project.name == project_name).first() project = db.query(Project).filter(Project.name == project_name).first()
if not project: if not project:
logger.warning(f"resolve_dependencies: project '{project_name}' not found")
raise DependencyNotFoundError(project_name, package_name, ref) raise DependencyNotFoundError(project_name, package_name, ref)
package = db.query(Package).filter( package = db.query(Package).filter(
@@ -683,11 +669,8 @@ def resolve_dependencies(
Package.name == package_name, Package.name == package_name,
).first() ).first()
if not package: if not package:
logger.warning(f"resolve_dependencies: package '{package_name}' not found in project '{project_name}'")
raise DependencyNotFoundError(project_name, package_name, ref) raise DependencyNotFoundError(project_name, package_name, ref)
logger.info(f"resolve_dependencies: found package id={package.id}")
# Try to find artifact by tag or version # Try to find artifact by tag or version
resolved = _resolve_dependency_to_artifact( resolved = _resolve_dependency_to_artifact(
db, project_name, package_name, ref, ref db, project_name, package_name, ref, ref

View File

@@ -737,8 +737,16 @@ async def pypi_download_file(
# Extract and store dependencies # Extract and store dependencies
dependencies = _extract_dependencies(content, filename) dependencies = _extract_dependencies(content, filename)
if dependencies: if dependencies:
logger.info(f"PyPI proxy: extracted {len(dependencies)} dependencies from {filename}") # Deduplicate dependencies by package name (keep first occurrence)
seen_packages = set()
unique_deps = []
for dep_name, dep_version in dependencies: for dep_name, dep_version in dependencies:
if dep_name not in seen_packages:
seen_packages.add(dep_name)
unique_deps.append((dep_name, dep_version))
logger.info(f"PyPI proxy: extracted {len(unique_deps)} dependencies from {filename} (deduped from {len(dependencies)})")
for dep_name, dep_version in unique_deps:
# Check if this dependency already exists for this artifact # Check if this dependency already exists for this artifact
existing_dep = db.query(ArtifactDependency).filter( existing_dep = db.query(ArtifactDependency).filter(
ArtifactDependency.artifact_id == sha256, ArtifactDependency.artifact_id == sha256,