#1153061 pybuild.pm make_pep440_compliant() breaks on setuptools-scm dev versions

Package:
dh-python
Source:
dh-python
Submitter:
Singer, Leo P. (GSFC-6610)
Date:
2026-11-04 22:33:02 UTC
Severity:
normal
#1153061#5
Date:
2026-11-04 22:31:39 UTC
From:
To:
make_pep440_compliant() in dh/pybuild.pm (ba9cca3f) mis-parses versions
that are already a valid PEP 440 dev/post release with a local segment
-- the format setuptools-scm itself emits for untagged commits (e.g.
"0.1.dev516+g595c8c1").

Encountered in the CI/CD pipeline for
https://git.ligo.org/computing/software/igwn-segments.

Repro (function copied verbatim, no build needed):

    perl -e '
    sub make_pep440_compliant {
        my $version = shift;
        my (undef, $public, $local) = split(qr/^([0-9][0-9.]*(?:(?:a|b|rc|\.post|\.dev)[0-9]+)*)\+?/, $version, 2);
        return $version if !$local;
        my $sanitized_local = $local;
        $sanitized_local =~ s/[+~-]+/./g;
        $sanitized_local =~ s/^\.+|\.+$//g;
        return "$public+$sanitized_local";
    }
    print make_pep440_compliant("0.1.dev516+g595c8c1"), "\n";
    '

Got:      0.1.+dev516.g595c8c1
Expected: 0.1.dev516+g595c8c1 (unchanged)

Cause: [0-9][0-9.]* is greedy and eats the "." before ".dev", so the
split misreads public="0.1." local="dev516+g595c8c1" instead of
public="0.1.dev516" local="g595c8c1".

pybuild.pm exports SETUPTOOLS_SCM_PRETEND_VERSION (and, via the same
function, PDM_BUILD_SCM_VERSION/POETRY_DYNAMIC_VERSIONING_BYPASS/
PBR_VERSION) from this output. Any setuptools-scm/flit-scm/hatch-vcs/
pdm-backend/poetry-dynamic-versioning/pbr package built with pybuild
from a dev-snapshot upstream version (no .git for the backend to fall
back to) fails with InvalidVersion.

Fix:
-     my (undef, $public, $local) = split(qr/^([0-9][0-9.]*(?:(?:a|b|rc|\.post|\.dev)[0-9]+)*)\+?/, $version, 2);
+     my (undef, $public, $local) = split(qr/^([0-9]+(?:\.[0-9]+)*(?:(?:a|b|rc|\.post|\.dev)[0-9]+)*)\+?/, $version, 2);

Passes all 10 cases in t/test_make_pep440_compliant.t plus the case
above.

(Diagnosed and drafted with AI (Claude) assistance; reproducer and
patch output shown above were generated by running the scripts, not
verified by hand.)