diff --git a/src/packageurl/__init__.py b/src/packageurl/__init__.py index 8199e39..9677b73 100644 --- a/src/packageurl/__init__.py +++ b/src/packageurl/__init__.py @@ -459,12 +459,17 @@ def from_string(cls, purl: str) -> Self: url=remainder, scheme="", allow_fragments=True ) - if scheme or authority: - msg = ( - f'Invalid purl {purl!r} cannot contain a "user:pass@host:port" ' - f"URL Authority component: {authority!r}." - ) - raise ValueError(msg) + # The spec (seems) to allow colons in the name and namespace. + # urllib.urlsplit splits on : considers them parts of scheme + # and authority. + # Other libraries do not care about this. + # See https://github.com/package-url/packageurl-python/issues/152#issuecomment-2637692538 + # We do + ":" + to put the colon back that urlsplit removed. + if authority: + path = authority + ":" + path + + if scheme: + path = scheme + ":" + path path = path.lstrip("/") diff --git a/tests/test_packageurl.py b/tests/test_packageurl.py index cb419e2..5d14220 100644 --- a/tests/test_packageurl.py +++ b/tests/test_packageurl.py @@ -330,3 +330,47 @@ def test_to_dict_custom_empty_value(self): def test_purl_is_hashable(): s = {PackageURL(name="hashable", type="pypi")} assert len(s) == 1 + + +def test_colons_in_name_are_handled_correctly() -> None: + p = PackageURL.from_string( + "pkg:nuget/libiconv:%20character%20set%20conversion%20library@1.9?package-id=e11a609df352e292" + ) + + assert p.type == "nuget" + assert p.namespace is None + assert p.name == "libiconv: character set conversion library" + assert p.version == "1.9" + assert p.qualifiers == {"package-id": "e11a609df352e292"} + assert p.subpath is None + + assert PackageURL.from_string(p.to_string()).to_string() == p.to_string() + + +def test_colons_in_namespace_are_handled_correctly() -> None: + p = PackageURL.from_string( + "pkg:nuget/an:odd:space/libiconv:%20character%20set%20conversion%20library@1.9?package-id=e11a609df352e292" + ) + + assert p.type == "nuget" + assert p.namespace == "an:odd:space" + assert p.name == "libiconv: character set conversion library" + assert p.version == "1.9" + assert p.qualifiers == {"package-id": "e11a609df352e292"} + assert p.subpath is None + + assert PackageURL.from_string(p.to_string()).to_string() == p.to_string() + + +def test_encoding_stuff_with_colons_correctly() -> None: + p = PackageURL( + type="nuget", + namespace="an:odd:space", + name="libiconv: character set conversion library", + version="1.9", + qualifiers={"package-id": "e11a609df352e292"}, + ) + assert ( + p.to_string() + == "pkg:nuget/an:odd:space/libiconv:%20character%20set%20conversion%20library@1.9?package-id=e11a609df352e292" + )