Skip to content

fix(pypi): resolve name and version for PEP 658 metadata sidecars - #222

Open
wickedOne wants to merge 1 commit into
git-pkgs:mainfrom
wickedOne:pypi-fix
Open

fix(pypi): resolve name and version for PEP 658 metadata sidecars#222
wickedOne wants to merge 1 commit into
git-pkgs:mainfrom
wickedOne:pypi-fix

Conversation

@wickedOne

@wickedOne wickedOne commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

hi,

i was experiencing this while caching pypi dependencies

image

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.

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.

1 participant