Skip to content

sdist filenames are not PEP 625 normalized #1317

Description

@mprpic

Problem

PEP 625 requires a source distribution to be named {name}-{version}.tar.gz, where name is normalized per PEP 503 and then has - replaced with _.

default_build_sdist builds the filename from the requirement string instead:

sdist_filename = ctx.sdists_builds / f"{req.name}-{version}.tar.gz"

req.name is whatever spelling the requirement was written with, so the result is PEP 625 compliant only by coincidence — when the requested name happens to contain no separators or capitals.

validate_sdist_filename does not catch this, because it parses the name with packaging.utils.parse_sdist_filename, which canonicalizes before comparing. The non-normalized form validates cleanly.

Example

From an index built with fromager:

published by the index    : colpali-engine-0.3.18.tar.gz
Name: in its own PKG-INFO : colpali_engine
published by upstream     : colpali_engine-0.3.18.tar.gz
PEP 625 requires          : colpali_engine-0.3.18.tar.gz

The filename disagrees with the spec, with the sdist's own metadata, and with the upstream artifact for the same version.

In that index 4,814 of 11,813 sdists, across 671 projects, are named this way. Where filenames are compliant it is incidental: Cython produces cython-3.3.0.tar.gz correctly only because the requested spelling had no separators.

Impact

Low. pip and uv resolve and install these without complaint, since parse_sdist_filename canonicalizes. What it does affect:

  • PyPI has enforced PEP 625 on upload since 2023, so these artifacts cannot be republished to a compliant index without being renamed.
  • Filename-keyed comparison against a PyPI-derived set — mirror deduplication, cache keys, "do I already have this file" checks — does not match.

Suggested fix

Normalize when constructing the filename:

from packaging.utils import canonicalize_name

sdist_filename = (
    ctx.sdists_builds / f"{canonicalize_name(req.name).replace('-', '_')}-{version}.tar.gz"
)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions