0
# Data Models
1
2
Core data structures representing dependencies, vulnerabilities, and related information used throughout the pip-audit API.
3
4
## Capabilities
5
6
### Dependency Classes
7
8
Base classes representing Python packages and their states.
9
10
```python { .api }
11
@dataclass(frozen=True)
12
class Dependency:
13
"""
14
Represents an abstract Python package.
15
16
This class cannot be constructed directly.
17
"""
18
19
name: str
20
"""
21
The package's uncanonicalized name.
22
23
Use the canonical_name property when a canonicalized form is necessary.
24
"""
25
26
@property
27
def canonical_name(self) -> str:
28
"""
29
The Dependency's PEP-503 canonicalized name.
30
31
Returns:
32
Canonicalized package name according to PEP-503
33
"""
34
35
def is_skipped(self) -> bool:
36
"""
37
Check whether the Dependency was skipped by the audit.
38
39
Returns:
40
True if this is a SkippedDependency, False otherwise
41
"""
42
```
43
44
### Resolved Dependency
45
46
Represents a fully resolved Python package with a specific version.
47
48
```python { .api }
49
@dataclass(frozen=True)
50
class ResolvedDependency(Dependency):
51
"""
52
Represents a fully resolved Python package.
53
"""
54
55
version: Version
56
"""
57
The resolved version of the package.
58
"""
59
```
60
61
### Skipped Dependency
62
63
Represents a Python package that was unable to be audited.
64
65
```python { .api }
66
@dataclass(frozen=True)
67
class SkippedDependency(Dependency):
68
"""
69
Represents a Python package that was unable to be audited and therefore, skipped.
70
"""
71
72
skip_reason: str
73
"""
74
The reason why this package was skipped during audit.
75
"""
76
```
77
78
### Vulnerability Result
79
80
Represents vulnerability information for a package.
81
82
```python { .api }
83
@dataclass(frozen=True)
84
class VulnerabilityResult:
85
"""
86
Represents a vulnerability result from a vulnerability service.
87
"""
88
89
id: VulnerabilityID
90
"""
91
A service-provided identifier for the vulnerability.
92
"""
93
94
description: str
95
"""
96
A human-readable description of the vulnerability.
97
"""
98
99
fix_versions: list[Version]
100
"""
101
A list of versions that can be upgraded to that resolve the vulnerability.
102
"""
103
104
aliases: set[str]
105
"""
106
A set of aliases (alternative identifiers) for this result.
107
"""
108
109
published: datetime | None = None
110
"""
111
When the vulnerability was first published.
112
"""
113
114
def alias_of(self, other: VulnerabilityResult) -> bool:
115
"""
116
Returns whether this result is an alias of another result.
117
118
Two results are aliases if their respective sets of {id, *aliases} intersect.
119
120
Parameters:
121
- other: VulnerabilityResult, the other result to compare
122
123
Returns:
124
True if this result is an alias of the other result
125
"""
126
127
def merge_aliases(self, other: VulnerabilityResult) -> VulnerabilityResult:
128
"""
129
Merge other's aliases into this result, returning a new result.
130
131
Parameters:
132
- other: VulnerabilityResult, the result to merge aliases from
133
134
Returns:
135
New VulnerabilityResult with merged aliases
136
"""
137
138
def has_any_id(self, ids: set[str]) -> bool:
139
"""
140
Returns whether ids intersects with {id} | aliases.
141
142
Parameters:
143
- ids: set[str], set of IDs to check
144
145
Returns:
146
True if any of the IDs match this result's ID or aliases
147
"""
148
```
149
150
### Type Aliases
151
152
Type definitions used throughout the API.
153
154
```python { .api }
155
VulnerabilityID = NewType("VulnerabilityID", str)
156
"""
157
Type alias for vulnerability identifiers.
158
"""
159
```
160
161
## Usage Examples
162
163
### Working with Dependencies
164
165
```python
166
from pip_audit._service.interface import ResolvedDependency, SkippedDependency
167
from packaging.version import Version
168
169
# Create a resolved dependency
170
dependency = ResolvedDependency(name="requests", version=Version("2.28.0"))
171
print(f"Package: {dependency.name}")
172
print(f"Canonical: {dependency.canonical_name}")
173
print(f"Version: {dependency.version}")
174
print(f"Is skipped: {dependency.is_skipped()}")
175
176
# Create a skipped dependency
177
skipped = SkippedDependency(name="broken-package", skip_reason="Invalid version format")
178
print(f"Skipped: {skipped.name} - {skipped.skip_reason}")
179
print(f"Is skipped: {skipped.is_skipped()}")
180
```
181
182
### Working with Vulnerability Results
183
184
```python
185
from pip_audit._service.interface import VulnerabilityResult, VulnerabilityID
186
from packaging.version import Version
187
from datetime import datetime
188
189
# Create vulnerability result
190
vuln = VulnerabilityResult(
191
id=VulnerabilityID("GHSA-xxxx-yyyy-zzzz"),
192
description="Cross-site scripting vulnerability in user input handling",
193
fix_versions=[Version("2.28.1"), Version("2.29.0")],
194
aliases={"CVE-2022-12345", "SNYK-PYTHON-REQUESTS-12345"}
195
)
196
197
print(f"Vulnerability ID: {vuln.id}")
198
print(f"Description: {vuln.description}")
199
print(f"Fix versions: {[str(v) for v in vuln.fix_versions]}")
200
print(f"Aliases: {vuln.aliases}")
201
```
202
203
### Filtering Dependencies
204
205
```python
206
from pip_audit._service.interface import ResolvedDependency, SkippedDependency
207
208
def filter_resolved_dependencies(dependencies):
209
"""Filter out skipped dependencies and return only resolved ones."""
210
resolved = []
211
skipped = []
212
213
for dep in dependencies:
214
if dep.is_skipped():
215
skipped.append(dep)
216
else:
217
resolved.append(dep)
218
219
return resolved, skipped
220
221
# Example usage
222
dependencies = [
223
ResolvedDependency(name="requests", version=Version("2.28.0")),
224
SkippedDependency(name="broken-pkg", skip_reason="Parse error"),
225
ResolvedDependency(name="flask", version=Version("2.0.0")),
226
]
227
228
resolved, skipped = filter_resolved_dependencies(dependencies)
229
print(f"Resolved: {len(resolved)}, Skipped: {len(skipped)}")
230
```
231
232
### Canonical Name Handling
233
234
```python
235
from pip_audit._service.interface import ResolvedDependency
236
from packaging.version import Version
237
238
# Demonstrate canonical name handling
239
packages = [
240
ResolvedDependency(name="Django", version=Version("4.0.0")),
241
ResolvedDependency(name="PILLOW", version=Version("9.0.0")),
242
ResolvedDependency(name="beautifulsoup4", version=Version("4.10.0")),
243
]
244
245
for pkg in packages:
246
print(f"Original: {pkg.name}")
247
print(f"Canonical: {pkg.canonical_name}")
248
print("---")
249
```