@@ -120,8 +120,21 @@ def normalize_namespace(
120120
121121 namespace_str = namespace if isinstance (namespace , str ) else namespace .decode ("utf-8" )
122122 namespace_str = namespace_str .strip ().strip ("/" )
123- if ptype in ("bitbucket" , "github" , "pypi" , "gitlab" , "composer" ):
123+ if ptype in (
124+ "bitbucket" ,
125+ "github" ,
126+ "pypi" ,
127+ "gitlab" ,
128+ "composer" ,
129+ "luarocks" ,
130+ "qpkg" ,
131+ "alpm" ,
132+ "apk" ,
133+ "hex" ,
134+ ):
124135 namespace_str = namespace_str .lower ()
136+ if ptype in ("cpan" ):
137+ namespace_str = namespace_str .upper ()
125138 segments = [seg for seg in namespace_str .split ("/" ) if seg .strip ()]
126139 segments_quoted = map (get_quoter (encode ), segments )
127140 return "/" .join (segments_quoted ) or None
@@ -162,10 +175,23 @@ def normalize_name(
162175 name_str = name_str .strip ().strip ("/" )
163176 if ptype and ptype in ("mlflow" ):
164177 return normalize_mlflow_name (name_str , qualifiers )
165- if ptype in ("bitbucket" , "github" , "pypi" , "gitlab" , "composer" ):
178+ if ptype in (
179+ "bitbucket" ,
180+ "github" ,
181+ "pypi" ,
182+ "gitlab" ,
183+ "composer" ,
184+ "luarocks" ,
185+ "oci" ,
186+ "npm" ,
187+ "alpm" ,
188+ "apk" ,
189+ "bitnami" ,
190+ "hex" ,
191+ ):
166192 name_str = name_str .lower ()
167193 if ptype == "pypi" :
168- name_str = name_str .replace ("_" , "-" )
194+ name_str = name_str .replace ("_" , "-" ). lower ()
169195 return name_str or None
170196
171197
@@ -178,7 +204,7 @@ def normalize_version(
178204 version_str = version if isinstance (version , str ) else version .decode ("utf-8" )
179205 quoter = get_quoter (encode )
180206 version_str = quoter (version_str .strip ())
181- if ptype and isinstance (ptype , str ) and ptype in ("huggingface" ):
207+ if ptype and isinstance (ptype , str ) and ptype in ("huggingface" , "oci" ):
182208 return version_str .lower ()
183209 return version_str or None
184210
@@ -369,6 +395,7 @@ def __new__(
369395 version : AnyStr | None = None ,
370396 qualifiers : AnyStr | dict [str , str ] | None = None ,
371397 subpath : AnyStr | None = None ,
398+ normalize_purl = True ,
372399 ) -> Self :
373400 required = dict (type = type , name = name )
374401 for key , value in required .items ():
@@ -394,23 +421,32 @@ def __new__(
394421 f"Invalid purl: qualifiers argument must be a dict or a string: { qualifiers !r} ."
395422 )
396423
397- (
398- type_norm ,
399- namespace_norm ,
400- name_norm ,
401- version_norm ,
402- qualifiers_norm ,
403- subpath_norm ,
404- ) = normalize (type , namespace , name , version , qualifiers , subpath , encode = None )
424+ if normalize_purl :
425+ (
426+ type_final ,
427+ namespace_final ,
428+ name_final ,
429+ version_final ,
430+ qualifiers_final ,
431+ subpath_final ,
432+ ) = normalize (type , namespace , name , version , qualifiers , subpath , encode = None )
433+
434+ else :
435+ type_final = type
436+ namespace_final = namespace
437+ name_final = name
438+ version_final = version
439+ qualifiers_final = qualifiers
440+ subpath_final = subpath
405441
406442 return super ().__new__ (
407443 cls ,
408- type = type_norm ,
409- namespace = namespace_norm ,
410- name = name_norm ,
411- version = version_norm ,
412- qualifiers = qualifiers_norm ,
413- subpath = subpath_norm ,
444+ type = type_final ,
445+ namespace = namespace_final ,
446+ name = name_final ,
447+ version = version_final ,
448+ qualifiers = qualifiers_final ,
449+ subpath = subpath_final ,
414450 )
415451
416452 def __str__ (self , * args : Any , ** kwargs : Any ) -> str :
0 commit comments