@@ -77,11 +77,13 @@ def unquote(s: AnyStr) -> str:
77
77
78
78
79
79
@overload
80
- def get_quoter (encode : bool = True ) -> Callable [[AnyStr ], str ]: ...
80
+ def get_quoter (encode : bool = True ) -> Callable [[AnyStr ], str ]:
81
+ ...
81
82
82
83
83
84
@overload
84
- def get_quoter (encode : None ) -> Callable [[str ], str ]: ...
85
+ def get_quoter (encode : None ) -> Callable [[str ], str ]:
86
+ ...
85
87
86
88
87
89
def get_quoter (encode : bool | None = True ) -> Callable [[AnyStr ], str ] | Callable [[str ], str ]:
@@ -151,19 +153,22 @@ def normalize_version(version: AnyStr | None, encode: bool | None = True) -> str
151
153
@overload
152
154
def normalize_qualifiers (
153
155
qualifiers : AnyStr | dict [str , str ] | None , encode : Literal [True ] = ...
154
- ) -> str | None : ...
156
+ ) -> str | None :
157
+ ...
155
158
156
159
157
160
@overload
158
161
def normalize_qualifiers (
159
162
qualifiers : AnyStr | dict [str , str ] | None , encode : Literal [False ] | None
160
- ) -> dict [str , str ]: ...
163
+ ) -> dict [str , str ]:
164
+ ...
161
165
162
166
163
167
@overload
164
168
def normalize_qualifiers (
165
169
qualifiers : AnyStr | dict [str , str ] | None , encode : bool | None = ...
166
- ) -> str | dict [str , str ] | None : ...
170
+ ) -> str | dict [str , str ] | None :
171
+ ...
167
172
168
173
169
174
def normalize_qualifiers (
@@ -251,7 +256,8 @@ def normalize(
251
256
qualifiers : AnyStr | dict [str , str ] | None ,
252
257
subpath : AnyStr | None ,
253
258
encode : Literal [True ] = ...,
254
- ) -> tuple [str , str | None , str , str | None , str | None , str | None ]: ...
259
+ ) -> tuple [str , str | None , str , str | None , str | None , str | None ]:
260
+ ...
255
261
256
262
257
263
@overload
@@ -263,7 +269,8 @@ def normalize(
263
269
qualifiers : AnyStr | dict [str , str ] | None ,
264
270
subpath : AnyStr | None ,
265
271
encode : Literal [False ] | None ,
266
- ) -> tuple [str , str | None , str , str | None , dict [str , str ], str | None ]: ...
272
+ ) -> tuple [str , str | None , str , str | None , dict [str , str ], str | None ]:
273
+ ...
267
274
268
275
269
276
@overload
@@ -275,7 +282,8 @@ def normalize(
275
282
qualifiers : AnyStr | dict [str , str ] | None ,
276
283
subpath : AnyStr | None ,
277
284
encode : bool | None = ...,
278
- ) -> tuple [str , str | None , str , str | None , str | dict [str , str ] | None , str | None ]: ...
285
+ ) -> tuple [str , str | None , str , str | None , str | dict [str , str ] | None , str | None ]:
286
+ ...
279
287
280
288
281
289
def normalize (
@@ -459,12 +467,17 @@ def from_string(cls, purl: str) -> Self:
459
467
url = remainder , scheme = "" , allow_fragments = True
460
468
)
461
469
462
- if scheme or authority :
463
- msg = (
464
- f'Invalid purl { purl !r} cannot contain a "user:pass@host:port" '
465
- f"URL Authority component: { authority !r} ."
466
- )
467
- raise ValueError (msg )
470
+ # The spec (seems) to allow colons in the name and namespace.
471
+ # urllib.urlsplit splits on : considers them parts of scheme
472
+ # and authority.
473
+ # Other libraries do no care about this.
474
+ # See https://github.com/package-url/packageurl-python/issues/152#issuecomment-2637692538
475
+ # We do + ":" + to put the colon back that urlsplit removed.
476
+ if authority :
477
+ path = authority + ":" + path
478
+
479
+ if scheme :
480
+ path = scheme + ":" + path
468
481
469
482
path = path .lstrip ("/" )
470
483
0 commit comments