0
# Core PURL Operations
1
2
Essential PackageURL parsing, construction, and manipulation functionality. The core operations provide the fundamental capabilities for working with Package URLs including parsing strings, creating objects, and normalizing components.
3
4
## Capabilities
5
6
### PackageURL Class
7
8
The main class for representing Package URLs with full parsing, validation, and serialization capabilities.
9
10
```python { .api }
11
class PackageURL:
12
"""
13
A Package URL object representing a standardized package identifier.
14
15
Attributes:
16
type (str): Package type (e.g., 'maven', 'npm', 'pypi')
17
namespace (str | None): Package namespace/group
18
name (str): Package name
19
version (str | None): Package version
20
qualifiers (dict[str, str]): Additional qualifiers as key-value pairs
21
subpath (str | None): Subpath within package
22
"""
23
24
def __init__(
25
self,
26
type: str | bytes | None = None,
27
namespace: str | bytes | None = None,
28
name: str | bytes | None = None,
29
version: str | bytes | None = None,
30
qualifiers: str | bytes | dict[str, str] | None = None,
31
subpath: str | bytes | None = None
32
):
33
"""
34
Create a PackageURL object with normalized components.
35
36
Args:
37
type: Package type (required)
38
namespace: Package namespace (optional)
39
name: Package name (required)
40
version: Package version (optional)
41
qualifiers: Qualifiers as dict or string (optional)
42
subpath: Subpath within package (optional)
43
44
Raises:
45
ValueError: If required fields (type, name) are missing or invalid
46
"""
47
48
@classmethod
49
def from_string(cls, purl: str) -> 'PackageURL':
50
"""
51
Parse a PackageURL from a string.
52
53
Args:
54
purl: PURL string to parse
55
56
Returns:
57
PackageURL object
58
59
Raises:
60
ValueError: If purl string is invalid or malformed
61
"""
62
63
def to_string(self, encode: bool = True) -> str:
64
"""
65
Convert PackageURL to string representation.
66
67
Args:
68
encode: Whether to percent-encode components (default: True)
69
70
Returns:
71
PURL string representation
72
"""
73
74
def to_dict(self, encode: bool = False, empty: any = None) -> dict[str, any]:
75
"""
76
Convert PackageURL to dictionary representation.
77
78
Args:
79
encode: Whether to encode qualifiers as string (default: False)
80
empty: Value to use for empty/None fields (default: None)
81
82
Returns:
83
Dictionary with PURL components
84
"""
85
86
def __str__(self) -> str:
87
"""String representation (same as to_string())."""
88
89
def __hash__(self) -> int:
90
"""Hash based on string representation."""
91
92
def _asdict(self) -> dict[str, any]:
93
"""
94
Return PackageURL fields as an ordered dictionary.
95
96
Returns:
97
Ordered dictionary of field names to values
98
"""
99
100
SCHEME: str = "pkg" # PURL scheme constant
101
```
102
103
### Normalization Functions
104
105
Component-wise normalization and validation functions for PackageURL components.
106
107
```python { .api }
108
def normalize(
109
type: str | bytes | None,
110
namespace: str | bytes | None,
111
name: str | bytes | None,
112
version: str | bytes | None,
113
qualifiers: str | bytes | dict[str, str] | None,
114
subpath: str | bytes | None,
115
encode: bool = True
116
) -> tuple[str | None, str | None, str | None, str | None, str | dict[str, str] | None, str | None]:
117
"""
118
Normalize all PackageURL components.
119
120
Args:
121
type: Package type to normalize
122
namespace: Namespace to normalize
123
name: Name to normalize
124
version: Version to normalize
125
qualifiers: Qualifiers to normalize
126
subpath: Subpath to normalize
127
encode: Whether to encode components (default: True)
128
129
Returns:
130
Tuple of normalized components
131
"""
132
133
def normalize_type(type: str | bytes | None, encode: bool = True) -> str | None:
134
"""
135
Normalize package type.
136
137
Args:
138
type: Package type to normalize
139
encode: Whether to percent-encode (default: True)
140
141
Returns:
142
Normalized type string (lowercase, stripped)
143
"""
144
145
def normalize_namespace(
146
namespace: str | bytes | None,
147
ptype: str | None,
148
encode: bool = True
149
) -> str | None:
150
"""
151
Normalize package namespace.
152
153
Args:
154
namespace: Namespace to normalize
155
ptype: Package type (affects normalization rules)
156
encode: Whether to percent-encode (default: True)
157
158
Returns:
159
Normalized namespace string
160
"""
161
162
def normalize_name(
163
name: str | bytes | None,
164
ptype: str | None,
165
encode: bool = True
166
) -> str | None:
167
"""
168
Normalize package name.
169
170
Args:
171
name: Package name to normalize
172
ptype: Package type (affects normalization rules)
173
encode: Whether to percent-encode (default: True)
174
175
Returns:
176
Normalized name string
177
"""
178
179
def normalize_version(version: str | bytes | None, encode: bool = True) -> str | None:
180
"""
181
Normalize package version.
182
183
Args:
184
version: Version to normalize
185
encode: Whether to percent-encode (default: True)
186
187
Returns:
188
Normalized version string
189
"""
190
191
def normalize_qualifiers(
192
qualifiers: str | bytes | dict[str, str] | None,
193
encode: bool = True
194
) -> str | dict[str, str] | None:
195
"""
196
Normalize qualifiers.
197
198
Args:
199
qualifiers: Qualifiers as string or dict
200
encode: Whether to encode as string (True) or return dict (False)
201
202
Returns:
203
Normalized qualifiers as string or dict
204
205
Raises:
206
ValueError: If qualifiers format is invalid
207
"""
208
209
def normalize_subpath(subpath: str | bytes | None, encode: bool = True) -> str | None:
210
"""
211
Normalize subpath.
212
213
Args:
214
subpath: Subpath to normalize
215
encode: Whether to percent-encode (default: True)
216
217
Returns:
218
Normalized subpath string
219
"""
220
```
221
222
### Utility Functions
223
224
Low-level utility functions for encoding and decoding.
225
226
```python { .api }
227
def quote(s: str | bytes) -> str:
228
"""
229
Percent-encode string except for colons.
230
231
Args:
232
s: String or bytes to encode
233
234
Returns:
235
Percent-encoded string
236
"""
237
238
def unquote(s: str | bytes) -> str:
239
"""
240
Percent-decode string.
241
242
Args:
243
s: String or bytes to decode
244
245
Returns:
246
Percent-decoded string
247
"""
248
249
def get_quoter(encode: bool | None = True) -> callable:
250
"""
251
Get appropriate encoding/decoding function.
252
253
Args:
254
encode: True for quote, False for unquote, None for identity
255
256
Returns:
257
Encoding/decoding function
258
"""
259
```
260
261
## Usage Examples
262
263
### Creating PackageURLs
264
265
```python
266
from packageurl import PackageURL
267
268
# Create from components
269
purl = PackageURL(
270
type="maven",
271
namespace="org.apache.commons",
272
name="io",
273
version="1.3.4"
274
)
275
276
# Create with qualifiers
277
purl = PackageURL(
278
type="npm",
279
name="lodash",
280
version="4.17.21",
281
qualifiers={"arch": "x64", "os": "linux"}
282
)
283
```
284
285
### Parsing PURLs
286
287
```python
288
# Parse various PURL formats
289
maven_purl = PackageURL.from_string("pkg:maven/org.springframework/spring-core@5.3.21")
290
npm_purl = PackageURL.from_string("pkg:npm/%40angular/core@12.0.0")
291
pypi_purl = PackageURL.from_string("pkg:pypi/django@3.2.0?extra=security")
292
293
# Access components
294
print(maven_purl.type) # "maven"
295
print(maven_purl.namespace) # "org.springframework"
296
print(maven_purl.name) # "spring-core"
297
print(maven_purl.version) # "5.3.21"
298
```
299
300
### Normalization
301
302
```python
303
from packageurl import normalize, normalize_qualifiers
304
305
# Normalize all components
306
type_n, ns_n, name_n, ver_n, qual_n, sub_n = normalize(
307
"MAVEN",
308
"Org.Apache.Commons",
309
"IO",
310
"1.3.4",
311
"classifier=sources&type=jar",
312
"src/main"
313
)
314
315
# Normalize qualifiers specifically
316
qualifiers_dict = normalize_qualifiers("key1=value1&key2=value2", encode=False)
317
qualifiers_str = normalize_qualifiers({"key1": "value1", "key2": "value2"}, encode=True)
318
```