Skip to content

fix: correct semver scheme handling of .dev0 tags and exact pre-releases#1349

Merged
RonnyPfannschmidt merged 2 commits into
pypa:mainfrom
RonnyPfannschmidt:fix/version-schemes
Mar 29, 2026
Merged

fix: correct semver scheme handling of .dev0 tags and exact pre-releases#1349
RonnyPfannschmidt merged 2 commits into
pypa:mainfrom
RonnyPfannschmidt:fix/version-schemes

Conversation

@RonnyPfannschmidt
Copy link
Copy Markdown
Contributor

Summary

  • Exact = tag (P1): simplified_semver_version now returns the tag as-is for exact checkouts (matching release_branch_semver_version). Previously it stripped pre-release info — 2.0.dev0 exact became 2.0.0, 1.0.0rc1 exact became 1.0.0.
  • .dev0 anchors (P3): guess_next_simple_semver now recognizes .dev0 tags as explicit version anchors, returning the base version normalized to 3 segments without bumping. 2.0.dev0 at distance 5 now correctly produces 2.0.0.dev5 instead of 2.0.1.dev5 or 2.1.0.dev5.
  • Both fixes are grounded in first principles documented in the plan: PEP 440 ordering, exact = tag, .dev0 as explicit anchor, guessed version must sort higher than tag.

Behavior changes

Scenario Before After
semver-pep440 exact 2.0.dev0 2.0.0 (wrong) 2.0.dev0
semver-pep440 exact 1.0.0rc1 1.0.0 (wrong) 1.0.0rc1
semver-pep440 exact 1.0 1.0.0 1.0 (PEP 440 equivalent)
semver-pep440 2.0.dev0 dist=5 default 2.0.1.dev5 (wrong) 2.0.0.dev5
semver-pep440 2.0.dev0 dist=5 feature 2.1.0.dev5 (wrong) 2.0.0.dev5
semver-pep440-release-branch 2.0.dev0 dist=5 master 2.1.0.dev5 (wrong) 2.0.0.dev5

Fixes #523.

Test plan

  • All existing version scheme tests pass (87 tests)
  • New test cases for exact .dev0 and rc1 tag preservation on both semver schemes
  • New test cases for .dev0 anchor behavior on default, feature, and release branches
  • Pre-commit (ruff, mypy, codespell) passes

Made with Cursor

Apply first principles to semver-pep440 and semver-pep440-release-branch:

- P1 (exact = tag): simplified_semver_version now returns the tag as-is
  for exact checkouts, matching release_branch_semver_version. Previously
  it stripped pre-release info (2.0.dev0 → 2.0.0, 1.0.0rc1 → 1.0.0).

- P3 (.dev0 anchors): guess_next_simple_semver now recognizes .dev0 tags
  as explicit version anchors, returning the base version normalized to
  3 segments without bumping. 2.0.dev0 at distance 5 → 2.0.0.dev5
  (was incorrectly 2.0.1.dev5 or 2.1.0.dev5).

Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Anthropic Claude <claude@anthropic.com>
Copilot AI review requested due to automatic review settings March 29, 2026 17:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the semver-pep440 and semver-pep440-release-branch version schemes in vcs-versioning to preserve exact tag versions (including pre-releases) and to treat .dev0 tags as explicit anchors when guessing the next dev version, aligning behavior with PEP 440 ordering and the project’s intended semantics.

Changes:

  • Preserve the tag verbatim for exact checkouts in simplified_semver_version (including rc and .dev0 tags).
  • Treat .dev0 tags as anchors in guess_next_simple_semver so guessed dev versions don’t bump past the anchored release.
  • Add test coverage and a towncrier changelog fragment for the corrected behaviors.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
vcs-versioning/src/vcs_versioning/_version_schemes/_standard.py Updates semver-pep440 scheme logic for exact-tag preservation and .dev0 anchor handling.
vcs-versioning/testing_vcs/test_version.py Adds/updates parametrized cases covering exact pre-release preservation and .dev0 anchor behavior across branches.
vcs-versioning/changelog.d/523.bugfix.md Documents the behavior fixes for the semver-pep440 schemes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +48 to +51
parts = list(version.tag.release)
while len(parts) < SEMVER_LEN:
parts.append(0)
return ".".join(str(i) for i in parts)
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

guess_next_simple_semver treats any PEP 440 dev release tag as an anchor via is_devrelease. That includes tags like 1.0.dev1, which can produce a guessed version that is not guaranteed to sort higher than the tag (e.g., distance=1 would yield 1.0.0.dev1, effectively equal to the tag). If the intended behavior is specifically for .dev0 anchors, gate this branch on version.tag.dev == 0 (or an equivalent .dev0 check) and either fall back to the normal incrementing behavior or raise a ValueError for nonzero .devN to match the existing .devX-unsupported policy in _modify_version._bump_dev.

Suggested change
parts = list(version.tag.release)
while len(parts) < SEMVER_LEN:
parts.append(0)
return ".".join(str(i) for i in parts)
dev_number = getattr(version.tag, "dev", None)
if dev_number == 0:
parts = list(version.tag.release)
while len(parts) < SEMVER_LEN:
parts.append(0)
return ".".join(str(i) for i in parts)

Copilot uses AI. Check for mistakes.
Use `version.tag.dev == 0` instead of `is_devrelease` to match only
.dev0 tags as version anchors. Tags like 1.0.dev1 would produce
incorrect ordering (1.0.0.dev1 == 1.0.dev1) and are already rejected
by _bump_dev. This keeps the semver schemes consistent with the
existing .devX-unsupported policy.

Co-authored-by: Cursor AI <ai@cursor.sh>
Co-authored-by: Anthropic Claude <claude@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@RonnyPfannschmidt RonnyPfannschmidt merged commit 5d34df7 into pypa:main Mar 29, 2026
31 checks passed
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.

release_branch_semver_version version guessing ignores explicit tags fo the next version

2 participants