24
24
# Visit https://github.com/package-url/packageurl-python for support and
25
25
# download.
26
26
27
+ from __future__ import annotations
28
+
27
29
import string
28
30
from collections import namedtuple
29
31
from typing import TYPE_CHECKING
30
32
from typing import Any
31
- from typing import AnyStr
32
33
from typing import Dict
33
34
from typing import Optional
34
35
from typing import Tuple
43
44
from collections .abc import Iterable
44
45
45
46
from typing_extensions import Literal
47
+ from typing_extensions import Self
48
+
49
+ AnyStr = Union [str , bytes ]
46
50
47
51
# Python 3
48
52
basestring = (
49
53
bytes ,
50
54
str ,
51
- ) # NOQA
55
+ )
52
56
53
57
"""
54
58
A purl (aka. Package URL) implementation as specified at:
@@ -84,16 +88,16 @@ def unquote(s: AnyStr) -> str:
84
88
85
89
86
90
@overload
87
- def get_quoter (encode : bool = True ) -> " Callable[[AnyStr], str]" : ...
91
+ def get_quoter (encode : bool = True ) -> Callable [[AnyStr ], str ]: ...
88
92
89
93
90
94
@overload
91
- def get_quoter (encode : None ) -> " Callable[[str], str]" : ...
95
+ def get_quoter (encode : None ) -> Callable [[str ], str ]: ...
92
96
93
97
94
98
def get_quoter (
95
99
encode : Optional [bool ] = True ,
96
- ) -> " Union[Callable[[AnyStr], str], Callable[[str], str]]" :
100
+ ) -> Union [Callable [[AnyStr ], str ], Callable [[str ], str ]]:
97
101
"""
98
102
Return quoting callable given an `encode` tri-boolean (True, False or None)
99
103
"""
@@ -105,22 +109,22 @@ def get_quoter(
105
109
return lambda x : x
106
110
107
111
108
- def normalize_type (type : Optional [AnyStr ], encode : Optional [bool ] = True ) -> Optional [str ]: # NOQA
112
+ def normalize_type (type : Optional [AnyStr ], encode : Optional [bool ] = True ) -> Optional [str ]:
109
113
if not type :
110
114
return None
111
115
if not isinstance (type , str ):
112
- type_str = type .decode ("utf-8" ) # NOQA
116
+ type_str = type .decode ("utf-8" )
113
117
else :
114
118
type_str = type
115
119
116
120
quoter = get_quoter (encode )
117
- type_str = quoter (type_str ) # NOQA
121
+ type_str = quoter (type_str )
118
122
return type_str .strip ().lower () or None
119
123
120
124
121
125
def normalize_namespace (
122
126
namespace : Optional [AnyStr ], ptype : Optional [str ], encode : Optional [bool ] = True
123
- ) -> Optional [str ]: # NOQA
127
+ ) -> Optional [str ]:
124
128
if not namespace :
125
129
return None
126
130
if not isinstance (namespace , str ):
@@ -138,7 +142,7 @@ def normalize_namespace(
138
142
139
143
def normalize_name (
140
144
name : Optional [AnyStr ], ptype : Optional [str ], encode : Optional [bool ] = True
141
- ) -> Optional [str ]: # NOQA
145
+ ) -> Optional [str ]:
142
146
if not name :
143
147
return None
144
148
if not isinstance (name , str ):
@@ -156,9 +160,7 @@ def normalize_name(
156
160
return name_str or None
157
161
158
162
159
- def normalize_version (
160
- version : Optional [AnyStr ], encode : Optional [bool ] = True
161
- ) -> Optional [str ]: # NOQA
163
+ def normalize_version (version : Optional [AnyStr ], encode : Optional [bool ] = True ) -> Optional [str ]:
162
164
if not version :
163
165
return None
164
166
if not isinstance (version , str ):
@@ -173,25 +175,25 @@ def normalize_version(
173
175
174
176
@overload
175
177
def normalize_qualifiers (
176
- qualifiers : Union [AnyStr , Dict [str , str ], None ] , encode : " Literal[True]" = ...
178
+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]]] , encode : Literal [True ] = ...
177
179
) -> Optional [str ]: ...
178
180
179
181
180
182
@overload
181
183
def normalize_qualifiers (
182
- qualifiers : Union [AnyStr , Dict [str , str ], None ] , encode : " Optional[Literal[False]]"
183
- ) -> Optional [ Dict [str , str ] ]: ...
184
+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]]] , encode : Optional [Literal [False ]]
185
+ ) -> Dict [str , str ]: ...
184
186
185
187
186
188
@overload
187
189
def normalize_qualifiers (
188
- qualifiers : Union [AnyStr , Dict [str , str ], None ], encode : Optional [bool ] = ...
189
- ) -> Union [str , Dict [str , str ], None ]: ...
190
+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ], encode : Optional [bool ] = ...
191
+ ) -> Optional [ Union [str , Dict [str , str ]] ]: ...
190
192
191
193
192
194
def normalize_qualifiers (
193
- qualifiers : Union [AnyStr , Dict [str , str ], None ], encode : Optional [bool ] = True
194
- ) -> Union [str , Dict [str , str ], None ]: # NOQA
195
+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ], encode : Optional [bool ] = True
196
+ ) -> Optional [ Union [str , Dict [str , str ]]]:
195
197
"""
196
198
Return normalized `qualifiers` as a mapping (or as a string if `encode` is
197
199
True). The `qualifiers` arg is either a mapping or a string.
@@ -213,7 +215,7 @@ def normalize_qualifiers(
213
215
f"Invalid qualifier. Must be a string of key=value pairs:{ repr (qualifiers_list )} "
214
216
)
215
217
qualifiers_parts = [kv .partition ("=" ) for kv in qualifiers_list ]
216
- qualifiers_pairs : " Iterable[Tuple[str, str]]" = [(k , v ) for k , _ , v in qualifiers_parts ]
218
+ qualifiers_pairs : Iterable [Tuple [str , str ]] = [(k , v ) for k , _ , v in qualifiers_parts ]
217
219
elif isinstance (qualifiers , dict ):
218
220
qualifiers_pairs = qualifiers .items ()
219
221
else :
@@ -255,9 +257,7 @@ def normalize_qualifiers(
255
257
return qualifiers_map
256
258
257
259
258
- def normalize_subpath (
259
- subpath : Optional [AnyStr ], encode : Optional [bool ] = True
260
- ) -> Optional [str ]: # NOQA
260
+ def normalize_subpath (subpath : Optional [AnyStr ], encode : Optional [bool ] = True ) -> Optional [str ]:
261
261
if not subpath :
262
262
return None
263
263
if not isinstance (subpath , str ):
@@ -278,9 +278,9 @@ def normalize(
278
278
namespace : Optional [AnyStr ],
279
279
name : Optional [AnyStr ],
280
280
version : Optional [AnyStr ],
281
- qualifiers : Union [AnyStr , Dict [str , str ], None ],
281
+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ],
282
282
subpath : Optional [AnyStr ],
283
- encode : " Literal[True]" = ...,
283
+ encode : Literal [True ] = ...,
284
284
) -> Tuple [str , Optional [str ], str , Optional [str ], Optional [str ], Optional [str ]]: ...
285
285
286
286
@@ -290,10 +290,10 @@ def normalize(
290
290
namespace : Optional [AnyStr ],
291
291
name : Optional [AnyStr ],
292
292
version : Optional [AnyStr ],
293
- qualifiers : Union [AnyStr , Dict [str , str ], None ],
293
+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ],
294
294
subpath : Optional [AnyStr ],
295
- encode : " Optional[Literal[False]]" ,
296
- ) -> Tuple [str , Optional [str ], str , Optional [str ], Optional [ Dict [str , str ] ], Optional [str ]]: ...
295
+ encode : Optional [Literal [False ]],
296
+ ) -> Tuple [str , Optional [str ], str , Optional [str ], Dict [str , str ], Optional [str ]]: ...
297
297
298
298
299
299
@overload
@@ -302,11 +302,11 @@ def normalize(
302
302
namespace : Optional [AnyStr ],
303
303
name : Optional [AnyStr ],
304
304
version : Optional [AnyStr ],
305
- qualifiers : Union [AnyStr , Dict [str , str ], None ],
305
+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ],
306
306
subpath : Optional [AnyStr ],
307
307
encode : Optional [bool ] = ...,
308
308
) -> Tuple [
309
- str , Optional [str ], str , Optional [str ], Union [str , Dict [str , str ], None ], Optional [str ]
309
+ str , Optional [str ], str , Optional [str ], Optional [ Union [str , Dict [str , str ]] ], Optional [str ]
310
310
]: ...
311
311
312
312
@@ -315,21 +315,21 @@ def normalize(
315
315
namespace : Optional [AnyStr ],
316
316
name : Optional [AnyStr ],
317
317
version : Optional [AnyStr ],
318
- qualifiers : Union [AnyStr , Dict [str , str ], None ],
318
+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ],
319
319
subpath : Optional [AnyStr ],
320
320
encode : Optional [bool ] = True ,
321
321
) -> Tuple [
322
322
Optional [str ],
323
323
Optional [str ],
324
324
Optional [str ],
325
325
Optional [str ],
326
- Union [str , Dict [str , str ], None ],
326
+ Optional [ Union [str , Dict [str , str ]] ],
327
327
Optional [str ],
328
- ]: # NOQA
328
+ ]:
329
329
"""
330
330
Return normalized purl components
331
331
"""
332
- type_norm = normalize_type (type , encode ) # NOQA
332
+ type_norm = normalize_type (type , encode )
333
333
namespace_norm = normalize_namespace (namespace , type_norm , encode )
334
334
name_norm = normalize_name (name , type_norm , encode )
335
335
version_norm = normalize_version (version , encode )
@@ -346,22 +346,22 @@ class PackageURL(
346
346
https://github.com/package-url/purl-spec
347
347
"""
348
348
349
- name : str
350
- namespace : Optional [str ]
351
- qualifiers : Union [str , Dict [str , str ], None ]
352
- subpath : Optional [str ]
353
349
type : str
350
+ namespace : Optional [str ]
351
+ name : str
354
352
version : Optional [str ]
353
+ qualifiers : Dict [str , str ]
354
+ subpath : Optional [str ]
355
355
356
356
def __new__ (
357
- self ,
357
+ cls ,
358
358
type : Optional [AnyStr ] = None ,
359
359
namespace : Optional [AnyStr ] = None ,
360
- name : Optional [AnyStr ] = None , # NOQA
360
+ name : Optional [AnyStr ] = None ,
361
361
version : Optional [AnyStr ] = None ,
362
- qualifiers : Union [AnyStr , Dict [str , str ], None ] = None ,
362
+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ] = None ,
363
363
subpath : Optional [AnyStr ] = None ,
364
- ) -> "PackageURL" : # this should be ' Self' https://github.com/python/mypy/pull/13133
364
+ ) -> Self :
365
365
required = dict (type = type , name = name )
366
366
for key , value in required .items ():
367
367
if value :
@@ -399,12 +399,10 @@ def __new__(
399
399
version_norm ,
400
400
qualifiers_norm ,
401
401
subpath_norm ,
402
- ) = normalize ( # NOQA
403
- type , namespace , name , version , qualifiers , subpath , encode = None
404
- )
402
+ ) = normalize (type , namespace , name , version , qualifiers , subpath , encode = None )
405
403
406
404
return super ().__new__ (
407
- PackageURL ,
405
+ cls ,
408
406
type = type_norm ,
409
407
namespace = namespace_norm ,
410
408
name = name_norm ,
@@ -439,7 +437,7 @@ def to_string(self) -> str:
439
437
"""
440
438
Return a purl string built from components.
441
439
"""
442
- type , namespace , name , version , qualifiers , subpath = normalize ( # NOQA
440
+ type , namespace , name , version , qualifiers , subpath = normalize (
443
441
self .type ,
444
442
self .namespace ,
445
443
self .name ,
@@ -472,7 +470,7 @@ def to_string(self) -> str:
472
470
return "" .join (purl )
473
471
474
472
@classmethod
475
- def from_string (cls , purl : str ) -> "PackageURL" :
473
+ def from_string (cls , purl : str ) -> Self :
476
474
"""
477
475
Return a PackageURL object parsed from a string.
478
476
Raise ValueError on errors.
@@ -490,7 +488,7 @@ def from_string(cls, purl: str) -> "PackageURL":
490
488
version : Optional [str ] # this line is just for type hinting
491
489
subpath : Optional [str ] # this line is just for type hinting
492
490
493
- type , sep , remainder = remainder .partition ("/" ) # NOQA
491
+ type , sep , remainder = remainder .partition ("/" )
494
492
if not type or not sep :
495
493
raise ValueError (f"purl is missing the required type component: { repr (purl )} ." )
496
494
@@ -536,7 +534,7 @@ def from_string(cls, purl: str) -> "PackageURL":
536
534
if not name :
537
535
raise ValueError (f"purl is missing the required name component: { repr (purl )} " )
538
536
539
- type , namespace , name , version , qualifiers , subpath = normalize ( # NOQA
537
+ type , namespace , name , version , qualifiers , subpath = normalize (
540
538
type ,
541
539
namespace ,
542
540
name ,
@@ -546,4 +544,4 @@ def from_string(cls, purl: str) -> "PackageURL":
546
544
encode = False ,
547
545
)
548
546
549
- return PackageURL (type , namespace , name , version , qualifiers , subpath )
547
+ return cls (type , namespace , name , version , qualifiers , subpath )
0 commit comments