Skip to content

Commit ee4110b

Browse files
authored
Merge pull request #118 from jwodder/gh-117
Add `{normalized_version}` field for `write` and `onbuild` steps
2 parents 6d72f00 + 6252ba9 commit ee4110b

File tree

9 files changed

+108
-9
lines changed

9 files changed

+108
-9
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
v3.3.0 (in development)
2+
-----------------------
3+
- Added `{normalized_version}` to the fields available to the `write` and
4+
`onbuild` steps
5+
16
v3.2.0 (2025-06-10)
27
-------------------
38
- Support reading configuration from a `versioningit.toml` file instead of

docs/changelog.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
Changelog
44
=========
55

6+
v3.3.0 (in development)
7+
-----------------------
8+
- Added ``{normalized_version}`` to the fields available to the ``write`` and
9+
``onbuild`` steps
10+
11+
612
v3.2.0 (2025-06-10)
713
-------------------
814
- Support reading configuration from a :file:`versioningit.toml` file instead

docs/configuration.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,13 +395,20 @@ The ``[tool.versioningit.template-fields]`` Subtable
395395

396396
.. versionadded:: 2.0.0
397397

398+
.. versionadded:: 3.3.0
399+
400+
The ``{normalized_version}`` field
401+
398402
The ``template-fields`` subtable controls the fields available for the
399403
templates of the ``write`` and ``onbuild`` steps. ``versioningit`` provides
400404
one ``template-fields`` method, ``"basic"`` (the default), which provides the
401405
following template fields:
402406

403407
- ``{version}`` — the project's final version
404408

409+
- ``{normalized_version}`` — the project's final version, normalized as per
410+
:pep:`440`; if the version string cannot be normalized, it is left as-is
411+
405412
- ``{version_tuple}`` — a string representation of a tuple of ``{version}``'s
406413
components; see below for how to configure how the version is split up
407414

src/versioningit/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
<https://versioningit.rtfd.io> for more information.
4545
"""
4646

47-
__version__ = "3.2.0"
47+
__version__ = "3.3.0.dev1"
4848
__author__ = "John Thorvald Wodder II"
4949
__author_email__ = "versioningit@varonathe.org"
5050
__license__ = "MIT"

src/versioningit/basics.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from pathlib import Path
44
import re
55
from typing import Any, Optional
6+
from packaging.version import Version
67
from .core import VCSDescription
78
from .errors import ConfigError, InvalidTagError
89
from .logging import log, warn_extra_fields
@@ -194,4 +195,8 @@ def basic_template_fields(
194195
fields["next_version"] = next_version
195196
fields["version"] = version
196197
fields["version_tuple"] = version_tuple
198+
try:
199+
fields["normalized_version"] = str(Version(version))
200+
except ValueError:
201+
fields["normalized_version"] = version
197202
return fields
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"version": "0.1.0-r2",
3+
"pkg_version": "0.1.0.post2",
4+
"next_version": "0.2.0",
5+
"files": [
6+
{
7+
"sdist_path": "src/mypackage/_version.py",
8+
"wheel_path": "mypackage/_version.py",
9+
"contents": "__raw_version__ = \"0.1.0-r2\"\n__version__ = \"0.1.0.post2\"\n"
10+
},
11+
{
12+
"sdist_path": "src/mypackage/__init__.py",
13+
"wheel_path": "mypackage/__init__.py",
14+
"in_project": false,
15+
"contents": "\"\"\" A test package \"\"\"\n\n__raw_version__ = \"0.1.0-r2\"\n__version__ = \"0.1.0.post2\"\n"
16+
}
17+
]
18+
}
14.1 KB
Binary file not shown.

test/test_end2end.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,20 @@ class ErrorDetails(BaseModel):
6464

6565
class CaseDetails(BaseModel):
6666
version: str
67+
# Version reported by packaging metadata rather than by versioningit;
68+
# differs from `version` when normalization happens:
69+
pkg_version: Union[str, None] = None
6770
next_version: Union[str, ErrorDetails]
6871
local_modules: List[str] = Field(default_factory=list)
6972
files: List[File] = Field(default_factory=list)
7073
logmsgs: List[LogMsg] = Field(default_factory=list)
7174

75+
def get_pkg_version(self) -> str:
76+
if self.pkg_version is not None:
77+
return self.pkg_version
78+
else:
79+
return self.version
80+
7281

7382
def mkcases(
7483
subdir: str,
@@ -142,13 +151,13 @@ def test_end2end(
142151
f.check(srcdir, "project")
143152

144153
sdist_src = unpack_sdist(srcdir / "dist", tmp_path)
145-
assert get_version_from_pkg_info(sdist_src) == details.version
154+
assert get_version_from_pkg_info(sdist_src) == details.get_pkg_version()
146155
for f in details.files:
147156
f.check(sdist_src, "sdist")
148157

149158
wheel_src, wheel_dist_info = unpack_wheel(srcdir / "dist", tmp_path)
150159
metadata = (wheel_dist_info / "METADATA").read_text(encoding="utf-8")
151-
assert parse_version_from_metadata(metadata) == details.version
160+
assert parse_version_from_metadata(metadata) == details.get_pkg_version()
152161
for f in details.files:
153162
f.check(wheel_src, "wheel")
154163

@@ -383,7 +392,7 @@ def test_build_wheel_directly(repopath: str, tmp_path: Path) -> None:
383392

384393
wheel_src, wheel_dist_info = unpack_wheel(srcdir / "dist", tmp_path)
385394
metadata = (wheel_dist_info / "METADATA").read_text(encoding="utf-8")
386-
assert parse_version_from_metadata(metadata) == details.version
395+
assert parse_version_from_metadata(metadata) == details.get_pkg_version()
387396
for f in details.files:
388397
f.check(wheel_src, "wheel")
389398

@@ -408,7 +417,7 @@ def test_editable_mode(cmd: list[str], tmp_path: Path) -> None:
408417
try:
409418
assert get_repo_status(srcdir) == status
410419
info = readcmd(sys.executable, "-m", "pip", "show", "mypackage")
411-
assert parse_version_from_metadata(info) == details.version
420+
assert parse_version_from_metadata(info) == details.get_pkg_version()
412421
version_var = readcmd(
413422
sys.executable, "-c", "import mypackage; print(mypackage.__version__)"
414423
)
@@ -438,7 +447,7 @@ def test_editable_mode_hatch(tmp_path: Path) -> None:
438447
try:
439448
assert get_repo_status(srcdir) == status
440449
info = readcmd(sys.executable, "-m", "pip", "show", "mypackage")
441-
assert parse_version_from_metadata(info) == details.version
450+
assert parse_version_from_metadata(info) == details.get_pkg_version()
442451
version_var = readcmd(
443452
sys.executable, "-c", "import mypackage; print(mypackage.__version__)"
444453
)
@@ -472,13 +481,13 @@ def test_setup_py(tmp_path: Path) -> None:
472481
f.check(srcdir, "project")
473482

474483
sdist_src = unpack_sdist(srcdir / "dist", tmp_path)
475-
assert get_version_from_pkg_info(sdist_src) == details.version
484+
assert get_version_from_pkg_info(sdist_src) == details.get_pkg_version()
476485
for f in details.files:
477486
f.check(sdist_src, "sdist")
478487

479488
wheel_src, wheel_dist_info = unpack_wheel(srcdir / "dist", tmp_path)
480489
metadata = (wheel_dist_info / "METADATA").read_text(encoding="utf-8")
481-
assert parse_version_from_metadata(metadata) == details.version
490+
assert parse_version_from_metadata(metadata) == details.get_pkg_version()
482491
for f in details.files:
483492
f.check(wheel_src, "wheel")
484493

test/test_methods/test_template_fields.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def test_basic_template_fields(
9797
"build_date": BUILD_DATE,
9898
"branch": "main",
9999
"version": version,
100+
"normalized_version": version,
100101
"version_tuple": version_tuple,
101102
"base_version": "0.1.0",
102103
"next_version": "0.2.0",
@@ -141,7 +142,11 @@ def test_basic_template_fields_bad_pep440_version() -> None:
141142
None,
142143
None,
143144
None,
144-
{"version": "1.2.3.post5", "version_tuple": '(1, 2, 3, "post5")'},
145+
{
146+
"version": "1.2.3.post5",
147+
"version_tuple": '(1, 2, 3, "post5")',
148+
"normalized_version": "1.2.3.post5",
149+
},
145150
),
146151
(
147152
DESCRIPTION,
@@ -155,6 +160,7 @@ def test_basic_template_fields_bad_pep440_version() -> None:
155160
"rev": "abcdef0",
156161
"build_date": BUILD_DATE,
157162
"branch": "main",
163+
"normalized_version": "1.2.3.post5",
158164
},
159165
),
160166
(
@@ -170,6 +176,7 @@ def test_basic_template_fields_bad_pep440_version() -> None:
170176
"build_date": BUILD_DATE,
171177
"branch": "main",
172178
"base_version": "1.2.3",
179+
"normalized_version": "1.2.3.post5",
173180
},
174181
),
175182
],
@@ -190,3 +197,45 @@ def test_basic_template_fields_none_inputs(
190197
)
191198
== fields
192199
)
200+
201+
202+
def test_basic_template_fields_nonnormalized_version() -> None:
203+
assert basic_template_fields(
204+
version="2025.06.01",
205+
description=DESCRIPTION,
206+
base_version="2025.06.01",
207+
next_version="2025.07.01",
208+
params={},
209+
) == {
210+
"distance": 5,
211+
"vcs": "g",
212+
"rev": "abcdef0",
213+
"build_date": BUILD_DATE,
214+
"branch": "main",
215+
"version": "2025.06.01",
216+
"normalized_version": "2025.6.1",
217+
"version_tuple": "(2025, 6, 1)",
218+
"base_version": "2025.06.01",
219+
"next_version": "2025.07.01",
220+
}
221+
222+
223+
def test_basic_template_fields_nonpep440_version() -> None:
224+
assert basic_template_fields(
225+
version="2025.06.01j",
226+
description=DESCRIPTION,
227+
base_version="2025.06.01",
228+
next_version="2025.07.01",
229+
params={},
230+
) == {
231+
"distance": 5,
232+
"vcs": "g",
233+
"rev": "abcdef0",
234+
"build_date": BUILD_DATE,
235+
"branch": "main",
236+
"version": "2025.06.01j",
237+
"normalized_version": "2025.06.01j",
238+
"version_tuple": '(2025, 6, "01j")',
239+
"base_version": "2025.06.01",
240+
"next_version": "2025.07.01",
241+
}

0 commit comments

Comments
 (0)