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
19 changes: 16 additions & 3 deletions src/wheel/_commands/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,25 @@ def _compute_tags(original_tags: Iterable[str], new_tags: str | None) -> set[str
return set(original_tags)

if new_tags.startswith("+"):
return {*original_tags, *new_tags[1:].split(".")}
parts = new_tags[1:].split(".")
_reject_empty_tag_components(new_tags, parts)
return {*original_tags, *parts}

if new_tags.startswith("-"):
return set(original_tags) - set(new_tags[1:].split("."))
parts = new_tags[1:].split(".")
_reject_empty_tag_components(new_tags, parts)
return set(original_tags) - set(parts)

return set(new_tags.split("."))
parts = new_tags.split(".")
_reject_empty_tag_components(new_tags, parts)
return set(parts)


def _reject_empty_tag_components(new_tags: str, parts: list[str]) -> None:
if not parts or any(part == "" for part in parts):
raise ValueError(
f"Invalid tags value {new_tags!r}: empty tag components are not allowed"
)


def _strip_zip64_extra(extra: bytes) -> bytes:
Expand Down
8 changes: 8 additions & 0 deletions tests/commands/test_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,11 @@ def test_retag_does_not_leak_zip64_into_local_headers(
)

output_file.unlink()


def test_compute_tags_rejects_empty_components() -> None:
from wheel._commands.tags import _compute_tags

for bad in ("", "py3..py2", "+", "+py2.", "-", "py3."):
with pytest.raises(ValueError, match="empty tag"):
_compute_tags(["py3"], bad)
Loading