or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-interface.mddata-models.mdenvironment-detection.mdindex.mdoutput-rendering.mdpackage-discovery.mdvalidation.mdwarning-system.md

validation.mddocs/

0

# Dependency Validation

1

2

Validates dependency trees to identify conflicting versions and circular dependencies with detailed reporting and configurable warning levels.

3

4

## Capabilities

5

6

### Main Validation Function

7

8

Primary validation entry point that checks for conflicts and cycles.

9

10

```python { .api }

11

def validate(tree: PackageDAG) -> None:

12

"""

13

Validate the dependency tree for conflicts and circular dependencies.

14

15

Prints warnings to stderr if conflicts or cycles are found and warnings are enabled.

16

The behavior depends on the current WarningPrinter configuration.

17

18

Parameters:

19

- tree: PackageDAG to validate

20

"""

21

```

22

23

### Conflict Detection

24

25

Identifies packages with conflicting version requirements.

26

27

```python { .api }

28

def conflicting_deps(tree: PackageDAG) -> dict[DistPackage, list[ReqPackage]]:

29

"""

30

Return dependencies which are not present or conflict with requirements.

31

32

Finds cases where:

33

- A package requires version X but version Y is installed

34

- A required package is missing entirely

35

36

Parameters:

37

- tree: The requirements tree to analyze

38

39

Returns:

40

Dictionary mapping packages to their conflicting requirements

41

"""

42

```

43

44

### Cycle Detection

45

46

Detects circular dependencies in the dependency graph.

47

48

```python { .api }

49

def cyclic_deps(tree: PackageDAG) -> list[list[Package]]:

50

"""

51

Return cyclic dependencies as list of lists.

52

53

Each inner list represents one dependency cycle, showing the path

54

that creates the circular reference.

55

56

Parameters:

57

- tree: Package dependency tree to analyze

58

59

Returns:

60

List of dependency cycles, where each cycle is a list of Package objects

61

"""

62

```

63

64

### Text Rendering Functions

65

66

Functions to format validation results for display.

67

68

```python { .api }

69

def render_conflicts_text(conflicts: dict[DistPackage, list[ReqPackage]]) -> None:

70

"""

71

Print conflicts in a human-readable format to stderr.

72

73

Output format:

74

* package==version

75

- conflicting_req [required: >=1.0, installed: 0.9]

76

"""

77

78

def render_cycles_text(cycles: list[list[Package]]) -> None:

79

"""

80

Print circular dependencies in a human-readable format to stderr.

81

82

Output format:

83

* package_a => package_b => package_c => package_a

84

"""

85

```

86

87

## Usage Examples

88

89

### Basic Validation

90

91

```python

92

from pipdeptree._discovery import get_installed_distributions

93

from pipdeptree._models import PackageDAG

94

from pipdeptree._validate import validate

95

96

# Create dependency tree and validate

97

distributions = get_installed_distributions()

98

tree = PackageDAG.from_pkgs(distributions)

99

100

# Validate for conflicts and cycles (prints warnings if found)

101

validate(tree)

102

```

103

104

### Manual Conflict Checking

105

106

```python

107

from pipdeptree._validate import conflicting_deps, render_conflicts_text

108

109

# Check for conflicts manually

110

conflicts = conflicting_deps(tree)

111

112

if conflicts:

113

print("Found conflicting dependencies:")

114

render_conflicts_text(conflicts)

115

116

# Process conflicts programmatically

117

for package, conflicting_reqs in conflicts.items():

118

print(f"\nPackage {package.project_name} has conflicts:")

119

for req in conflicting_reqs:

120

print(f" - {req.project_name}: required {req.version_spec}, "

121

f"installed {req.installed_version}")

122

```

123

124

### Manual Cycle Detection

125

126

```python

127

from pipdeptree._validate import cyclic_deps, render_cycles_text

128

129

# Check for circular dependencies

130

cycles = cyclic_deps(tree)

131

132

if cycles:

133

print("Found circular dependencies:")

134

render_cycles_text(cycles)

135

136

# Process cycles programmatically

137

for i, cycle in enumerate(cycles, 1):

138

cycle_names = [pkg.project_name for pkg in cycle]

139

print(f"Cycle {i}: {' -> '.join(cycle_names)}")

140

```

141

142

### Validation with Custom Warning Control

143

144

```python

145

from pipdeptree._warning import get_warning_printer, WarningType

146

from pipdeptree._validate import validate

147

148

# Configure warning behavior

149

warning_printer = get_warning_printer()

150

warning_printer.warning_type = WarningType.FAIL # Exit with error code on warnings

151

152

# Validate (will now fail with exit code 1 if issues found)

153

validate(tree)

154

155

# Check if validation failed

156

if warning_printer.has_warned_with_failure():

157

print("Validation failed with conflicts or cycles")

158

```

159

160

## Conflict Types

161

162

The validation system detects several types of conflicts:

163

164

### Version Conflicts

165

When installed version doesn't satisfy requirement specification:

166

```

167

* Django==3.0.0

168

- requests [required: >=2.25.0, installed: 2.20.0]

169

```

170

171

### Missing Dependencies

172

When a required package is not installed:

173

```

174

* mypackage==1.0.0

175

- missing-dep [required: >=1.0, installed: ?]

176

```

177

178

### Invalid Requirements

179

When package metadata contains malformed requirement strings (logged separately):

180

```

181

Invalid requirement strings found for the following distributions:

182

mypackage

183

Skipping "invalid>=requirement string"

184

```

185

186

## Cycle Detection Algorithm

187

188

The cycle detection uses depth-first search to identify circular dependencies:

189

190

1. **For each package** in the tree, start a DFS traversal

191

2. **Track visited nodes** to detect when we return to a previously seen package

192

3. **Record the path** when a cycle is found

193

4. **Return all unique cycles** found in the dependency graph

194

195

Cycles are returned as lists showing the dependency path that creates the circular reference.

196

197

## Integration with Warning System

198

199

Validation integrates with pipdeptree's warning system:

200

201

- **WarningType.SILENCE**: No validation output, always return 0

202

- **WarningType.SUPPRESS**: Print warnings but return 0

203

- **WarningType.FAIL**: Print warnings and return 1 if any found

204

205

The validation results are automatically printed to stderr when warnings are enabled, and the return code is determined by the warning configuration.