Understanding Multiple Package Versions in a Graph
When building complex Python projects, you may encounter situations where
multiple versions of the same package appear in your dependency graph. The
fromager graph explain-duplicates command helps you understand why this
happens and whether it represents a problem.
Basic Usage
To analyze multiple versions in your graph:
fromager graph explain-duplicates e2e/build-parallel/graph.json
This command will scan the entire graph and report on any packages that have multiple versions present.
Understanding the Output
The command output shows:
Package name: The name of the package with multiple versions
Available versions: All versions found in the graph
Requirements analysis: Which packages require which versions
Compatibility assessment: Whether a single version can satisfy all requirements
Example Output
Here’s an example of what you might see:
setuptools
80.8.0
setuptools>=61.2 matches ['80.8.0']
keyring==25.6.0
setuptools>=61 matches ['80.8.0']
setuptools-scm==8.3.1
setuptools matches ['80.8.0']
setuptools-scm==8.3.1
* setuptools==80.8.0 usable by all consumers
This output tells us:
setuptoolsversion 80.8.0 is present in the graphThree different requirement specifications exist for setuptools
All requirements can be satisfied by version 80.8.0
No version conflicts exist
Interpreting Results
Good Case: Single Compatible Version
When you see output like:
* package-name==1.2.3 usable by all consumers
This means all packages that depend on this package can use the same version. This is the ideal situation.
Problem Case: Version Conflicts
When you see output like:
* No single version of package-name meets all requirements
This indicates a dependency conflict where different packages require incompatible versions of the same dependency.
Common Scenarios
Build vs Runtime Dependencies
Sometimes you’ll see the same package required at different versions for build-time and runtime:
setuptools
45.0.0
setuptools<60 matches ['45.0.0']
some-old-package==1.0.0
65.0.0
setuptools>=60 matches ['65.0.0']
modern-package==2.0.0
* No single version of setuptools meets all requirements
In this case, you might need to update the older package or use package overrides.
Transitive Dependencies
Multiple versions can appear when different top-level packages pull in different versions of the same transitive dependency.
Resolution Strategies
When you find version conflicts:
Update packages: Try updating packages to newer versions that have compatible requirements
Use constraints: Create a constraints file to pin specific versions
Package overrides: Use fromager’s override system to force specific versions
Remove conflicting packages: Consider if all dependencies are actually needed
Example Investigation Workflow
# 1. Check for duplicates
fromager graph explain-duplicates e2e/build-parallel/graph.json
# 2. If conflicts found, investigate why specific packages are included
fromager graph why e2e/build-parallel/graph.json problematic-package
# 3. Check the full dependency chain
fromager graph why e2e/build-parallel/graph.json problematic-package --depth -1
# 4. Visualize to better understand the relationships
fromager graph to-dot e2e/build-parallel/graph.json --output graph.dot
dot -Tpng graph.dot -o dependency-analysis.png
This workflow helps you:
Identify which packages have version conflicts
Understand why conflicting packages are included
See the complete dependency chain causing conflicts
Visualize the relationships for better analysis
Best Practices
Run
explain-duplicatesregularly during development to catch conflicts earlyPay attention to build-system vs install requirements, as they often have different version constraints
Use the
whycommand to understand the source of unexpected version requirementsConsider using dependency scanning tools in your CI/CD pipeline to detect new conflicts