2424# Visit https://github.com/package-url/packageurl-python for support and
2525# download.
2626
27+ from __future__ import annotations
28+
2729import string
2830from collections import namedtuple
2931from typing import TYPE_CHECKING
3032from typing import Any
31- from typing import AnyStr
3233from typing import Dict
3334from typing import Optional
3435from typing import Tuple
4344 from collections .abc import Iterable
4445
4546 from typing_extensions import Literal
47+ from typing_extensions import Self
48+
49+ AnyStr = Union [str , bytes ]
4650
4751# Python 3
4852basestring = (
4953 bytes ,
5054 str ,
51- ) # NOQA
55+ )
5256
5357"""
5458A purl (aka. Package URL) implementation as specified at:
@@ -84,16 +88,16 @@ def unquote(s: AnyStr) -> str:
8488
8589
8690@overload
87- def get_quoter (encode : bool = True ) -> " Callable[[AnyStr], str]" : ...
91+ def get_quoter (encode : bool = True ) -> Callable [[AnyStr ], str ]: ...
8892
8993
9094@overload
91- def get_quoter (encode : None ) -> " Callable[[str], str]" : ...
95+ def get_quoter (encode : None ) -> Callable [[str ], str ]: ...
9296
9397
9498def get_quoter (
9599 encode : Optional [bool ] = True ,
96- ) -> " Union[Callable[[AnyStr], str], Callable[[str], str]]" :
100+ ) -> Union [Callable [[AnyStr ], str ], Callable [[str ], str ]]:
97101 """
98102 Return quoting callable given an `encode` tri-boolean (True, False or None)
99103 """
@@ -105,22 +109,22 @@ def get_quoter(
105109 return lambda x : x
106110
107111
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 ]:
109113 if not type :
110114 return None
111115 if not isinstance (type , str ):
112- type_str = type .decode ("utf-8" ) # NOQA
116+ type_str = type .decode ("utf-8" )
113117 else :
114118 type_str = type
115119
116120 quoter = get_quoter (encode )
117- type_str = quoter (type_str ) # NOQA
121+ type_str = quoter (type_str )
118122 return type_str .strip ().lower () or None
119123
120124
121125def normalize_namespace (
122126 namespace : Optional [AnyStr ], ptype : Optional [str ], encode : Optional [bool ] = True
123- ) -> Optional [str ]: # NOQA
127+ ) -> Optional [str ]:
124128 if not namespace :
125129 return None
126130 if not isinstance (namespace , str ):
@@ -138,7 +142,7 @@ def normalize_namespace(
138142
139143def normalize_name (
140144 name : Optional [AnyStr ], ptype : Optional [str ], encode : Optional [bool ] = True
141- ) -> Optional [str ]: # NOQA
145+ ) -> Optional [str ]:
142146 if not name :
143147 return None
144148 if not isinstance (name , str ):
@@ -156,9 +160,7 @@ def normalize_name(
156160 return name_str or None
157161
158162
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 ]:
162164 if not version :
163165 return None
164166 if not isinstance (version , str ):
@@ -173,25 +175,25 @@ def normalize_version(
173175
174176@overload
175177def normalize_qualifiers (
176- qualifiers : Union [AnyStr , Dict [str , str ], None ] , encode : " Literal[True]" = ...
178+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]]] , encode : Literal [True ] = ...
177179) -> Optional [str ]: ...
178180
179181
180182@overload
181183def 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 ]: ...
184186
185187
186188@overload
187189def 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 ]] ]: ...
190192
191193
192194def 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 ]]]:
195197 """
196198 Return normalized `qualifiers` as a mapping (or as a string if `encode` is
197199 True). The `qualifiers` arg is either a mapping or a string.
@@ -213,7 +215,7 @@ def normalize_qualifiers(
213215 f"Invalid qualifier. Must be a string of key=value pairs:{ repr (qualifiers_list )} "
214216 )
215217 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 ]
217219 elif isinstance (qualifiers , dict ):
218220 qualifiers_pairs = qualifiers .items ()
219221 else :
@@ -255,9 +257,7 @@ def normalize_qualifiers(
255257 return qualifiers_map
256258
257259
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 ]:
261261 if not subpath :
262262 return None
263263 if not isinstance (subpath , str ):
@@ -278,9 +278,9 @@ def normalize(
278278 namespace : Optional [AnyStr ],
279279 name : Optional [AnyStr ],
280280 version : Optional [AnyStr ],
281- qualifiers : Union [AnyStr , Dict [str , str ], None ],
281+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ],
282282 subpath : Optional [AnyStr ],
283- encode : " Literal[True]" = ...,
283+ encode : Literal [True ] = ...,
284284) -> Tuple [str , Optional [str ], str , Optional [str ], Optional [str ], Optional [str ]]: ...
285285
286286
@@ -290,10 +290,10 @@ def normalize(
290290 namespace : Optional [AnyStr ],
291291 name : Optional [AnyStr ],
292292 version : Optional [AnyStr ],
293- qualifiers : Union [AnyStr , Dict [str , str ], None ],
293+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ],
294294 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 ]]: ...
297297
298298
299299@overload
@@ -302,11 +302,11 @@ def normalize(
302302 namespace : Optional [AnyStr ],
303303 name : Optional [AnyStr ],
304304 version : Optional [AnyStr ],
305- qualifiers : Union [AnyStr , Dict [str , str ], None ],
305+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ],
306306 subpath : Optional [AnyStr ],
307307 encode : Optional [bool ] = ...,
308308) -> 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 ]
310310]: ...
311311
312312
@@ -315,21 +315,21 @@ def normalize(
315315 namespace : Optional [AnyStr ],
316316 name : Optional [AnyStr ],
317317 version : Optional [AnyStr ],
318- qualifiers : Union [AnyStr , Dict [str , str ], None ],
318+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ],
319319 subpath : Optional [AnyStr ],
320320 encode : Optional [bool ] = True ,
321321) -> Tuple [
322322 Optional [str ],
323323 Optional [str ],
324324 Optional [str ],
325325 Optional [str ],
326- Union [str , Dict [str , str ], None ],
326+ Optional [ Union [str , Dict [str , str ]] ],
327327 Optional [str ],
328- ]: # NOQA
328+ ]:
329329 """
330330 Return normalized purl components
331331 """
332- type_norm = normalize_type (type , encode ) # NOQA
332+ type_norm = normalize_type (type , encode )
333333 namespace_norm = normalize_namespace (namespace , type_norm , encode )
334334 name_norm = normalize_name (name , type_norm , encode )
335335 version_norm = normalize_version (version , encode )
@@ -346,22 +346,22 @@ class PackageURL(
346346 https://github.com/package-url/purl-spec
347347 """
348348
349- name : str
350- namespace : Optional [str ]
351- qualifiers : Union [str , Dict [str , str ], None ]
352- subpath : Optional [str ]
353349 type : str
350+ namespace : Optional [str ]
351+ name : str
354352 version : Optional [str ]
353+ qualifiers : Dict [str , str ]
354+ subpath : Optional [str ]
355355
356356 def __new__ (
357- self ,
357+ cls ,
358358 type : Optional [AnyStr ] = None ,
359359 namespace : Optional [AnyStr ] = None ,
360- name : Optional [AnyStr ] = None , # NOQA
360+ name : Optional [AnyStr ] = None ,
361361 version : Optional [AnyStr ] = None ,
362- qualifiers : Union [AnyStr , Dict [str , str ], None ] = None ,
362+ qualifiers : Optional [ Union [AnyStr , Dict [str , str ]] ] = None ,
363363 subpath : Optional [AnyStr ] = None ,
364- ) -> "PackageURL" : # this should be ' Self' https://github.com/python/mypy/pull/13133
364+ ) -> Self :
365365 required = dict (type = type , name = name )
366366 for key , value in required .items ():
367367 if value :
@@ -399,12 +399,10 @@ def __new__(
399399 version_norm ,
400400 qualifiers_norm ,
401401 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 )
405403
406404 return super ().__new__ (
407- PackageURL ,
405+ cls ,
408406 type = type_norm ,
409407 namespace = namespace_norm ,
410408 name = name_norm ,
@@ -439,7 +437,7 @@ def to_string(self) -> str:
439437 """
440438 Return a purl string built from components.
441439 """
442- type , namespace , name , version , qualifiers , subpath = normalize ( # NOQA
440+ type , namespace , name , version , qualifiers , subpath = normalize (
443441 self .type ,
444442 self .namespace ,
445443 self .name ,
@@ -472,7 +470,7 @@ def to_string(self) -> str:
472470 return "" .join (purl )
473471
474472 @classmethod
475- def from_string (cls , purl : str ) -> "PackageURL" :
473+ def from_string (cls , purl : str ) -> Self :
476474 """
477475 Return a PackageURL object parsed from a string.
478476 Raise ValueError on errors.
@@ -490,7 +488,7 @@ def from_string(cls, purl: str) -> "PackageURL":
490488 version : Optional [str ] # this line is just for type hinting
491489 subpath : Optional [str ] # this line is just for type hinting
492490
493- type , sep , remainder = remainder .partition ("/" ) # NOQA
491+ type , sep , remainder = remainder .partition ("/" )
494492 if not type or not sep :
495493 raise ValueError (f"purl is missing the required type component: { repr (purl )} ." )
496494
@@ -536,7 +534,7 @@ def from_string(cls, purl: str) -> "PackageURL":
536534 if not name :
537535 raise ValueError (f"purl is missing the required name component: { repr (purl )} " )
538536
539- type , namespace , name , version , qualifiers , subpath = normalize ( # NOQA
537+ type , namespace , name , version , qualifiers , subpath = normalize (
540538 type ,
541539 namespace ,
542540 name ,
@@ -546,4 +544,4 @@ def from_string(cls, purl: str) -> "PackageURL":
546544 encode = False ,
547545 )
548546
549- return PackageURL (type , namespace , name , version , qualifiers , subpath )
547+ return cls (type , namespace , name , version , qualifiers , subpath )
0 commit comments