0
# Data Models
1
2
Core classes for representing packages, requirements, and dependency relationships in a hierarchical dependency tree structure.
3
4
## Capabilities
5
6
### Package Base Class
7
8
Abstract base class for all package wrapper objects.
9
10
```python { .api }
11
class Package(ABC):
12
"""Abstract class for wrappers around objects that pip returns."""
13
14
UNKNOWN_LICENSE_STR = "(Unknown license)"
15
16
def __init__(self, project_name: str) -> None: ...
17
18
def licenses(self) -> str:
19
"""
20
Get license information for the package.
21
22
Returns:
23
License string in format "(license1, license2)" or "(Unknown license)"
24
"""
25
26
@abstractmethod
27
def render_as_root(self, *, frozen: bool) -> str: ...
28
29
@abstractmethod
30
def render_as_branch(self, *, frozen: bool) -> str: ...
31
32
@abstractmethod
33
def as_dict(self) -> dict[str, str]: ...
34
35
def render(
36
self,
37
parent: DistPackage | ReqPackage | None = None,
38
*,
39
frozen: bool = False,
40
) -> str: ...
41
```
42
43
### DistPackage Class
44
45
Wrapper for installed distribution packages with full metadata access.
46
47
```python { .api }
48
class DistPackage(Package):
49
"""
50
Wrapper class for importlib.metadata.Distribution instances.
51
52
Parameters:
53
- obj: importlib.metadata.Distribution to wrap over
54
- req: optional ReqPackage object for reverse tree display
55
"""
56
57
def __init__(self, obj: Distribution, req: ReqPackage | None = None) -> None: ...
58
59
def requires(self) -> Iterator[Requirement]:
60
"""
61
Return an iterator of the distribution's required dependencies.
62
63
Yields:
64
Requirement objects for dependencies that apply to current environment
65
66
Raises:
67
InvalidRequirementError: If metadata contains invalid requirement strings
68
"""
69
70
@property
71
def version(self) -> str:
72
"""The installed version of the package."""
73
74
def unwrap(self) -> Distribution:
75
"""Exposes the internal importlib.metadata.Distribution object."""
76
77
def as_requirement(self) -> ReqPackage:
78
"""Return a ReqPackage representation of this DistPackage."""
79
80
def as_parent_of(self, req: ReqPackage | None) -> DistPackage:
81
"""
82
Return a DistPackage instance associated to a requirement.
83
84
This association is necessary for reversing the PackageDAG.
85
"""
86
87
def as_dict(self) -> dict[str, str]:
88
"""
89
Returns:
90
Dictionary with keys: key, package_name, installed_version
91
"""
92
```
93
94
### ReqPackage Class
95
96
Wrapper for requirement packages with version constraint information.
97
98
```python { .api }
99
class ReqPackage(Package):
100
"""
101
Wrapper class for Requirement instance.
102
103
Parameters:
104
- obj: The Requirement instance to wrap over
105
- dist: optional importlib.metadata.Distribution instance for this requirement
106
"""
107
108
UNKNOWN_VERSION = "?"
109
110
def __init__(self, obj: Requirement, dist: DistPackage | None = None) -> None: ...
111
112
@property
113
def version_spec(self) -> str | None:
114
"""
115
Version specification string from requirement.
116
117
Returns:
118
Comma-joined version specifiers (e.g., ">=1.0,<2.0") or None
119
"""
120
121
@property
122
def installed_version(self) -> str:
123
"""
124
Currently installed version of the package.
125
126
Returns:
127
Version string or "?" if unknown/missing
128
"""
129
130
def is_conflicting(self) -> bool:
131
"""
132
Check if installed version conflicts with required version.
133
134
Returns:
135
True if installed version doesn't satisfy requirement or is missing
136
"""
137
138
@property
139
def is_missing(self) -> bool:
140
"""Check if package is missing (installed_version == "?")."""
141
142
def as_dict(self) -> dict[str, str]:
143
"""
144
Returns:
145
Dictionary with keys: key, package_name, installed_version, required_version
146
"""
147
```
148
149
### PackageDAG Class
150
151
Directed acyclic graph representing package dependencies using a mapping structure.
152
153
```python { .api }
154
class PackageDAG(Mapping[DistPackage, list[ReqPackage]]):
155
"""
156
Representation of Package dependencies as directed acyclic graph.
157
158
The internal structure maps each package to its list of requirements:
159
{package_a: [req_b, req_c],
160
package_b: [req_d],
161
package_c: [req_d, req_e],
162
package_d: [req_e],
163
package_e: []}
164
"""
165
166
@classmethod
167
def from_pkgs(cls, pkgs: list[Distribution]) -> PackageDAG:
168
"""
169
Create PackageDAG from list of Distribution objects.
170
171
Parameters:
172
- pkgs: List of importlib.metadata.Distribution objects
173
174
Returns:
175
PackageDAG instance with dependency relationships mapped
176
"""
177
178
def __init__(self, m: dict[DistPackage, list[ReqPackage]]) -> None: ...
179
180
def filter_nodes(
181
self,
182
include: list[str] | None,
183
exclude: set[str] | None,
184
exclude_deps: bool = False
185
):
186
"""
187
Filter the dependency tree to include/exclude specific packages.
188
189
Parameters:
190
- include: List of package patterns to include (supports wildcards)
191
- exclude: Set of package patterns to exclude (supports wildcards)
192
- exclude_deps: Whether to also exclude dependencies of excluded packages
193
194
Returns:
195
Filtered PackageDAG
196
197
Raises:
198
IncludeExcludeOverlapError: If include and exclude sets overlap
199
IncludePatternNotFoundError: If include patterns not found
200
"""
201
202
def reverse(self) -> ReversedPackageDAG:
203
"""
204
Create reversed view showing which packages depend on each package.
205
206
Returns:
207
ReversedPackageDAG with inverted dependency relationships
208
"""
209
210
def get_node_as_parent(self, key: str) -> DistPackage | None:
211
"""Get a package node by its canonical key."""
212
213
# Standard Mapping interface methods
214
def __getitem__(self, key: DistPackage) -> list[ReqPackage]: ...
215
def __iter__(self) -> Iterator[DistPackage]: ...
216
def __len__(self) -> int: ...
217
```
218
219
### ReversedPackageDAG Class
220
221
Inverted view of the dependency graph showing reverse dependencies.
222
223
```python { .api }
224
class ReversedPackageDAG(Mapping[ReqPackage, list[DistPackage]]):
225
"""
226
Reversed representation where each requirement maps to packages that depend on it.
227
"""
228
```
229
230
## Usage Examples
231
232
### Creating and Working with PackageDAG
233
234
```python
235
from pipdeptree._discovery import get_installed_distributions
236
from pipdeptree._models import PackageDAG
237
238
# Get installed packages and create dependency tree
239
distributions = get_installed_distributions()
240
tree = PackageDAG.from_pkgs(distributions)
241
242
# Filter to show only specific packages
243
filtered_tree = tree.filter_nodes(
244
include=['django', 'requests*'],
245
exclude=None
246
)
247
248
# Create reverse dependency view
249
reverse_tree = tree.reverse()
250
251
# Iterate through dependencies
252
for package, requirements in tree.items():
253
print(f"{package.project_name}=={package.version}")
254
for req in requirements:
255
print(f" requires {req.project_name} {req.version_spec}")
256
```
257
258
### Working with Individual Packages
259
260
```python
261
from pipdeptree._models import DistPackage, ReqPackage
262
263
# Access package information
264
for package, requirements in tree.items():
265
# Get package metadata
266
print(f"Package: {package.project_name}")
267
print(f"Version: {package.version}")
268
print(f"License: {package.licenses()}")
269
270
# Check requirements
271
for req in requirements:
272
if req.is_conflicting():
273
print(f"CONFLICT: {req.project_name}")
274
print(f" Required: {req.version_spec}")
275
print(f" Installed: {req.installed_version}")
276
```
277
278
## Exceptions
279
280
```python { .api }
281
class InvalidRequirementError(ValueError):
282
"""
283
An invalid requirement string was found.
284
285
When raising an exception, this should provide just the problem requirement string.
286
"""
287
288
class IncludeExcludeOverlapError(Exception):
289
"""Include and exclude sets passed as input violate mutual exclusivity requirement."""
290
291
class IncludePatternNotFoundError(Exception):
292
"""Include patterns weren't found when filtering a PackageDAG."""
293
```
294
295
## Type Definitions
296
297
```python { .api }
298
# Common type aliases used in the models
299
from importlib.metadata import Distribution, Requirement
300
from collections.abc import Iterator, Mapping
301
from typing import TYPE_CHECKING
302
303
if TYPE_CHECKING:
304
from collections.abc import Iterator
305
from importlib.metadata import Distribution
306
```