Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/packaging/pylock.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,14 @@ def _validate_path_url(path: str | None, url: str | None) -> None:
raise PylockValidationError("path or url must be provided")


def _validate_absolute_url(url: str | None, context: str) -> None:
if url is None:
return
parsed = urlparse(url)
if not parsed.scheme or not parsed.netloc:
raise PylockValidationError("URL must be absolute", context=context)


def _path_name(path: str | None) -> str | None:
if not path:
return None
Expand Down Expand Up @@ -352,6 +360,7 @@ def _from_dict(cls, d: Mapping[str, Any]) -> Self:
subdirectory=_get(d, str, "subdirectory"),
)
_validate_path_url(package_vcs.path, package_vcs.url)
_validate_absolute_url(package_vcs.url, "url")
return package_vcs


Expand Down Expand Up @@ -420,6 +429,7 @@ def _from_dict(cls, d: Mapping[str, Any]) -> Self:
subdirectory=_get(d, str, "subdirectory"),
)
_validate_path_url(package_archive.path, package_archive.url)
_validate_absolute_url(package_archive.url, "url")
return package_archive


Expand Down Expand Up @@ -461,6 +471,7 @@ def _from_dict(cls, d: Mapping[str, Any]) -> Self:
hashes=_get_required_as(d, Mapping, _validate_hashes, "hashes"), # type: ignore[type-abstract]
)
_validate_path_url(package_sdist.path, package_sdist.url)
_validate_absolute_url(package_sdist.url, "url")
return package_sdist

@property
Expand Down Expand Up @@ -510,6 +521,7 @@ def _from_dict(cls, d: Mapping[str, Any]) -> Self:
hashes=_get_required_as(d, Mapping, _validate_hashes, "hashes"), # type: ignore[type-abstract]
)
_validate_path_url(package_wheel.path, package_wheel.url)
_validate_absolute_url(package_wheel.url, "url")
return package_wheel

@property
Expand Down Expand Up @@ -599,6 +611,7 @@ def _from_dict(cls, d: Mapping[str, Any]) -> Self:
"Exactly one of vcs, directory, archive must be set "
"if sdist and wheels are not set"
)
_validate_absolute_url(package.index, "index")
for i, wheel in enumerate(package.wheels or []):
try:
(name, version, _, _) = parse_wheel_filename(wheel.filename)
Expand Down
48 changes: 48 additions & 0 deletions tests/test_pylock.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,54 @@ def test_pylock_invalid_vcs() -> None:
assert str(exc_info.value) == "path or url must be provided"


@pytest.mark.parametrize(
("data", "expected"),
[
(
{
"lock-version": "1.0",
"created-by": "pip",
"packages": [
{
"name": "example",
"index": "not-a-url",
"wheels": [
{
"name": "example-1.0-py3-none-any.whl",
"url": "https://example.com/example-1.0-py3-none-any.whl",
"hashes": {"sha256": "f" * 40},
}
],
}
],
},
"URL must be absolute in 'packages[0].index'",
),
(
{
"lock-version": "1.0",
"created-by": "pip",
"packages": [
{
"name": "example",
"vcs": {
"type": "git",
"url": "not-a-url",
"commit-id": "f" * 40,
},
}
],
},
"URL must be absolute in 'packages[0].vcs.url'",
),
],
)
def test_pylock_invalid_urls(data: dict[str, Any], expected: str) -> None:
with pytest.raises(PylockValidationError) as exc_info:
Pylock.from_dict(data)
assert str(exc_info.value) == expected


@pytest.mark.parametrize(
("dist", "expected_filename"),
[
Expand Down
Loading