Command line utility to show dependency tree of packages.
—
Validates dependency trees to identify conflicting versions and circular dependencies with detailed reporting and configurable warning levels.
Primary validation entry point that checks for conflicts and cycles.
def validate(tree: PackageDAG) -> None:
"""
Validate the dependency tree for conflicts and circular dependencies.
Prints warnings to stderr if conflicts or cycles are found and warnings are enabled.
The behavior depends on the current WarningPrinter configuration.
Parameters:
- tree: PackageDAG to validate
"""Identifies packages with conflicting version requirements.
def conflicting_deps(tree: PackageDAG) -> dict[DistPackage, list[ReqPackage]]:
"""
Return dependencies which are not present or conflict with requirements.
Finds cases where:
- A package requires version X but version Y is installed
- A required package is missing entirely
Parameters:
- tree: The requirements tree to analyze
Returns:
Dictionary mapping packages to their conflicting requirements
"""Detects circular dependencies in the dependency graph.
def cyclic_deps(tree: PackageDAG) -> list[list[Package]]:
"""
Return cyclic dependencies as list of lists.
Each inner list represents one dependency cycle, showing the path
that creates the circular reference.
Parameters:
- tree: Package dependency tree to analyze
Returns:
List of dependency cycles, where each cycle is a list of Package objects
"""Functions to format validation results for display.
def render_conflicts_text(conflicts: dict[DistPackage, list[ReqPackage]]) -> None:
"""
Print conflicts in a human-readable format to stderr.
Output format:
* package==version
- conflicting_req [required: >=1.0, installed: 0.9]
"""
def render_cycles_text(cycles: list[list[Package]]) -> None:
"""
Print circular dependencies in a human-readable format to stderr.
Output format:
* package_a => package_b => package_c => package_a
"""from pipdeptree._discovery import get_installed_distributions
from pipdeptree._models import PackageDAG
from pipdeptree._validate import validate
# Create dependency tree and validate
distributions = get_installed_distributions()
tree = PackageDAG.from_pkgs(distributions)
# Validate for conflicts and cycles (prints warnings if found)
validate(tree)from pipdeptree._validate import conflicting_deps, render_conflicts_text
# Check for conflicts manually
conflicts = conflicting_deps(tree)
if conflicts:
print("Found conflicting dependencies:")
render_conflicts_text(conflicts)
# Process conflicts programmatically
for package, conflicting_reqs in conflicts.items():
print(f"\nPackage {package.project_name} has conflicts:")
for req in conflicting_reqs:
print(f" - {req.project_name}: required {req.version_spec}, "
f"installed {req.installed_version}")from pipdeptree._validate import cyclic_deps, render_cycles_text
# Check for circular dependencies
cycles = cyclic_deps(tree)
if cycles:
print("Found circular dependencies:")
render_cycles_text(cycles)
# Process cycles programmatically
for i, cycle in enumerate(cycles, 1):
cycle_names = [pkg.project_name for pkg in cycle]
print(f"Cycle {i}: {' -> '.join(cycle_names)}")from pipdeptree._warning import get_warning_printer, WarningType
from pipdeptree._validate import validate
# Configure warning behavior
warning_printer = get_warning_printer()
warning_printer.warning_type = WarningType.FAIL # Exit with error code on warnings
# Validate (will now fail with exit code 1 if issues found)
validate(tree)
# Check if validation failed
if warning_printer.has_warned_with_failure():
print("Validation failed with conflicts or cycles")The validation system detects several types of conflicts:
When installed version doesn't satisfy requirement specification:
* Django==3.0.0
- requests [required: >=2.25.0, installed: 2.20.0]When a required package is not installed:
* mypackage==1.0.0
- missing-dep [required: >=1.0, installed: ?]When package metadata contains malformed requirement strings (logged separately):
Invalid requirement strings found for the following distributions:
mypackage
Skipping "invalid>=requirement string"The cycle detection uses depth-first search to identify circular dependencies:
Cycles are returned as lists showing the dependency path that creates the circular reference.
Validation integrates with pipdeptree's warning system:
The validation results are automatically printed to stderr when warnings are enabled, and the return code is determined by the warning configuration.
Install with Tessl CLI
npx tessl i tessl/pypi-pipdeptree