GeezerVison is showing github.com — fix(pypi): resolve name and version for PEP 658 metadata sidecars by wickedOne · Pull Request #222 · git-pkgs/proxy
Conversation
wickedOne
commented
Jul 30, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
hi,
i was experiencing this while caching pypi dependencies
once again i left the fix to claude (opus), but please challenge me if you have any questions
Problem
PyPI packages sometimes appear in the package overview under a synthetic name like pkg:pypi/_hash_164a211cb654c0d4@0.
These are PEP 658/714 core-metadata sidecar files. When an index advertises data-core-metadata (simple API) or core-metadata (JSON API) for a file, pip fetches .metadata to resolve dependencies without downloading the full wheel. parseFilename only recognised .whl and four sdist extensions, so foo-1.2.0-py3-none-any.whl.metadata matched none of them and returned an empty name. handleDownload then fell back to a hash-derived identifier:
name = fmt.Sprintf("_hash_%s", hashPath(path))
version = "0"
Reproduced against the reported entry — hashPath of the request path for backports_asyncio_runner-1.2.0-py3-none-any.whl.metadata yields exactly 164a211cb654c0d4.
It looks intermittent because the sidecar fetch depends on the index advertising core metadata per-file and pip choosing metadata-only resolution. For backports_asyncio_runner 1.2.0, upstream advertises core metadata on the wheel but not the sdist.
Changes
- Strip the .metadata suffix before parsing, so sidecars resolve to the distribution they describe. This is the actual fix.
- Parse wheels per PEP 427 using the spec-guaranteed field positions instead of scanning for a python tag. The name and version fields have hyphens escaped to _, so parts[0]/parts[1] are authoritative. Fixes build-tagged wheels: foo-1.0-1-py3-none-any.whl previously parsed as name foo-1.0, version 1. Removes the now-unused isPythonTag.
- Recognise more distribution formats — .tar.xz, .tar.Z, .tgz as sdist archives, and .egg/.exe/.msi as tagged formats. All previously hit the same hash fallback. The legacy bdists use the first-two-fields path deliberately: under the sdist heuristic, numpy-1.8.0-py2.7-macosx-10.9-x86_64.egg would parse as name numpy-1.8.0-py2.7-macosx, version 10.9-x86_64.
Testing
- Extended TestPyPIParseFilename with sidecars, build-tagged wheels, the new extensions, and legacy bdists.
- Added TestPyPIParseFilenameNoHashFallback, asserting the three real backports_asyncio_runner filenames all resolve to the same name/version — the property whose failure produces the bogus PURLs.
- go build ./... && go vet ./... && go test ./... pass; gofmt clean.
Note
This stops new hash* entries from being created but does not clean up existing ones. The cache is keyed on (package PURL, version PURL, filename), so already-cached sidecars keep their old identity and remain visible in the overview until purged.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Fixes PyPI filename parsing so PEP 658/714 core-metadata sidecar downloads (*.metadata) resolve to the correct package name/version instead of creating synthetic _hash_*@0 identifiers, improving cache key stability and package overview correctness.
Changes:
- Strip the
.metadata suffix before parsing distribution filenames (PEP 658/714 sidecars).
- Rework wheel parsing to use spec-guaranteed field positions (PEP 427), correctly handling build-tagged wheels.
- Expand recognized distribution extensions (more sdist archives + legacy bdists) and extend unit tests accordingly.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File |
Description |
| internal/handler/pypi.go |
Updates parseFilename to handle .metadata sidecars and broaden filename parsing across more PyPI distribution formats. |
| internal/handler/pypi_test.go |
Extends TestPyPIParseFilename and adds a regression test to prevent _hash_* fallback for sidecars. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Comment on lines
+50
to
+53
|
|
// Legacy bdist formats
|
|
|
{"numpy-1.8.0-py2.7-macosx-10.9-x86_64.egg", "numpy", "1.8.0"},
|
|
|
{"pywin32-223.win32-py2.7.exe", "pywin32", "223.win32"},
|
|
|
|
Comment on lines
473
to
482
|
|
for _, format := range taggedExtensions {
|
|
|
if !strings.HasSuffix(filename, format.ext) {
|
|
|
continue
|
|
|
}
|
|
|
parts := strings.Split(strings.TrimSuffix(filename, format.ext), "-")
|
|
|
if len(parts) < format.minParts {
|
|
|
return "", ""
|
|
|
}
|
|
|
return parts[0], parts[1]
|
|
|
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new .exe handling parses Windows installer filenames incorrectly. For foo-1.0.win32-py2.0.exe, parseFilename returns version 1.0.win32, but win32 is the platform and the version is 1.0. The pywin32 test currently codifies the same error. Please parse Windows installers separately or remove .exe support, and add a regression test using the documented filename form.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
The bdist_wininst and bdist_msi layout joins the platform to the version
with a '.' rather than a '-', so treating .exe/.msi like a wheel folded
the platform into the version: foo-1.0.win32-py2.0.exe resolved to
version "1.0.win32". Eggs shared the problem, as setuptools' hyphen
escaping is not universal: aws-sdk-1.0.0-py3.11.egg resolved to name
"aws", version "sdk".
Give each format its own parser. Wheels keep the PEP 427
spec-guaranteed field positions, eggs locate the version relative to the
py{X.Y} interpreter field, and Windows installers strip the platform and
interpreter fields before splitting name from version.
A PEP 658 sidecar resolves to the same name and version as the
distribution it describes, so it is cached under that version. Browse and
compare took the first cached artifact without checking its extension,
handing openArchive plain text: a version pip had only fetched metadata
for reported hasCached and then 500'd.
Add firstBrowsableArtifact, replacing five duplicated selection loops,
and export PyPIMetadataSuffix so the suffix has a single definition.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
according to claude all issues have been addressed...
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
|
@andrew is there a way we can get a release?
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Oh, actions is broken, may have to wait until tomorrow.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Reviewers
andrew
andrew approved these changes
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|