Skip to content

feat(wheelname): add ParseTags, which does not require a parseable version - #56

Merged
jonyoder merged 1 commit into
mainfrom
fix/wheelname-version-unescape
Sep 18, 2026
Merged

jonyoder merged 1 commit into
mainfrom
fix/wheelname-version-unescape

Conversation

@jonyoder

Copy link
Copy Markdown
Collaborator

Adds wheelname.ParseTags, which reads a wheel's compatibility tags without requiring its version to parse. Parse is unchanged.

Fixes #55.


Why additive rather than un-escaping inside Parse

The issue proposed un-escaping _ back to + before PEP 440 parsing. I probed this library's own version.Parse first, and the inverse is ambiguous silently:

candidate from the escaped 2.5.0_post1_cpu result
2.5.0+post1_cpu parses → 2.5.0+post1.cpu
2.5.0_post1+cpu parses → 2.5.0.post1+cpu

Both parse, and only the second is right for torch-2.5.0.post1+cpu. Any candidate-ordering heuristic therefore returns a plausible wrong version with no error on some inputs. Also worth noting: _ and - are already accepted as pre/post/dev separators (1.0_rc1 parses today), so the only genuinely broken case is the local-version + — and the tag component of those filenames parses standalone.

So the version was never needed to answer the tag question. ParseTags recovers all 221 affected filenames rather than the ~137 unambiguous ones, and cannot ever return a wrong version.

Shape

  • WheelTags{Name, Build, Tags} is a distinct type, not a WheelFilename with an empty Version — a caller cannot read a zero version and mistake it for a real one.
  • Both entry points go through parseExceptVersion, so they cannot drift on what a wheel filename is. A test asserts they agree on name, build and tags for a valid filename.

⚠️ The trade-off, on the record

Dropping version validation also drops the only signal that rejected some malformed names. too-few-py3-none-any.whl splits into five fields with few where a version belongs, so ParseTags accepts it where Parse does not. Re-validating the version would defeat the function's purpose, so there is a test documenting this rather than hiding it.

Separately, I noticed tags.ParseTag accepts a platform containing ! (e.g. py3-none-not!a!platform), so both Parse and ParseTags accept it. Pre-existing and left alone — flagging it in case it is worth its own issue.

Verification

  • go build, go vet, gofmt clean; go test ./... green across all 12 packages
  • 4 new tests, and I mutated ParseTags to delegate to Parse: exactly the two behaviour-carrying tests failed while the drift and rejection guards kept passing
  • golangci-lint not yet run locally (another process held its lock); CI covers it

🤖 Generated with Claude Code

…rsion

Parse rejects a whole filename when only the version fails PEP 440, and the
version contributes nothing to a PEP 425 tag. PEP 427 escapes non-alphanumeric
runs to "_", so a legal 1.0+cpu reaches disk as 1.0_cpu and does not parse. Over
a sweep of 14.3M mirrored PyPI wheels, 221 of 299 rejected filenames failed on
the version alone with readable tags, understating real platform compatibility.

Un-escaping inside Parse was rejected: the escaping is not losslessly invertible.
Both 2.5.0+post1_cpu and 2.5.0_post1+cpu parse from the escaped 2.5.0_post1_cpu
and only the second is right, so it would return a wrong version with no error.

Both entry points share parseExceptVersion so they cannot disagree about what a
wheel filename is. WheelTags is a separate type rather than a WheelFilename with
an empty Version, so no caller can read a zero version as a real one.

Fixes #55

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jonyoder
jonyoder merged commit b8ef6ef into main Sep 18, 2026
4 checks passed
@jonyoder
jonyoder deleted the fix/wheelname-version-unescape branch September 18, 2026 18:11
jonyoder added a commit that referenced this pull request Sep 18, 2026
Releases wheelname.ParseTags (#56) so the PyPI manifest producer can consume it; rstudio/package-manager#20776 is blocked on this tag existing.

Additive only; Parse's behaviour is unchanged. Minor bump while major is 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wheelname.Parse discards readable tags when only the version fails PEP 440

1 participant