Skip to content

Commit 9fd4f92

Browse files
authored
Fix version to tuple (#10)
1 parent 3626e6f commit 9fd4f92

File tree

4 files changed

+129
-17
lines changed

4 files changed

+129
-17
lines changed

.github/workflows/ci.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,22 @@ jobs:
3636
run: |
3737
ruff format --check .
3838
39+
tests:
40+
name: Unit tests
41+
timeout-minutes: 5
42+
runs-on: ubuntu-latest
43+
strategy:
44+
fail-fast: false
45+
steps:
46+
- uses: actions/checkout@v5
47+
- name: Set up Python
48+
uses: actions/setup-python@v6
49+
with:
50+
python-version: '3.13'
51+
- name: Install dependencies
52+
run: |
53+
python -m pip install --upgrade pip
54+
pip install pytest
55+
- name: Unit tests
56+
run: |
57+
pytest -v .

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,3 @@ The `_version.py` is formatted with Ruff under a strict ruleset so it
6464
can be adopted in most projects without changes.
6565

6666
On every change (i.e. PR) update `_version.py`'s version on the first line.
67-
68-
We don't have tests yet, because we mainly use this for projects related to PyGfx.
69-
Maybe we can add some tests later ... though we don't expect this module to change much.

_version.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
_version.py v1.4
2+
_version.py v1.5
33
44
Simple version string management, using a hard-coded version string
55
for simplicity and compatibility, while adding git info at runtime.
@@ -47,21 +47,18 @@ def get_extended_version() -> str:
4747
"""Get an extended version string with information from git."""
4848
release, post, labels = get_version_info_from_git()
4949

50-
# Sample first 3 parts of __version__
51-
base_release = ".".join(__version__.split(".")[:3])
52-
5350
# Start version string (__version__ string is leading)
54-
version = base_release
51+
version = base_version
5552
tag_prefix = "#"
5653

57-
if release and release != base_release:
54+
if release and release != base_version:
5855
# Can happen between bumping and tagging. And also when merging a
5956
# version bump into a working branch, because we use --first-parent.
6057
release2, _post, _labels = get_version_info_from_git(first_parent=False)
61-
if release2 != base_release:
58+
if release2 != base_version:
6259
warning(
6360
f"{project_name} version from git ({release})"
64-
f" and __version__ ({base_release}) don't match."
61+
f" and __version__ ({base_version}) don't match."
6562
)
6663
version += "+from_tag_" + release.replace(".", "_")
6764
tag_prefix = "."
@@ -121,12 +118,14 @@ def get_version_info_from_git(*, first_parent: bool = True) -> str:
121118

122119

123120
def version_to_tuple(v: str) -> tuple:
124-
v = __version__.split("+")[0] # remove hash
125-
return tuple(int(i) if i.isnumeric() else i for i in v.split("."))
126-
127-
128-
def prnt(m: str) -> None:
129-
sys.stdout.write(m + "\n")
121+
parts = []
122+
for part in v.split("."):
123+
p, _, h = part.partition("#")
124+
if p:
125+
parts.append(p)
126+
if h:
127+
parts.append("#" + h)
128+
return tuple(int(i) if i.isnumeric() else i for i in parts)
130129

131130

132131
def warning(m: str) -> None:
@@ -155,6 +154,10 @@ def warning(m: str) -> None:
155154
import sys
156155
import urllib.request
157156

157+
def prnt(m: str) -> None:
158+
sys.stdout.write(m + "\n")
159+
sys.stdout.flush()
160+
158161
_, *args = sys.argv
159162
this_file = Path(__file__)
160163

@@ -192,3 +195,4 @@ def warning(m: str) -> None:
192195
else:
193196
prnt(f"Unknown command for _version.py: {args[0]!r}")
194197
prnt("Use ``python _version.py help`` to see a list of options.")
198+
sys.exit(1)

test_version.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""A few basic tests for _version.py."""
2+
3+
# ruff: noqa: S101, S603, ANN
4+
5+
import subprocess
6+
import sys
7+
8+
import _version
9+
10+
example_versions = [
11+
("1", (1,)),
12+
("1.2", (1, 2)),
13+
("1.2.3", (1, 2, 3)),
14+
("1.2.3", (1, 2, 3)),
15+
("0.29.0.post4#g3175010", (0, 29, 0, "post4", "#g3175010")),
16+
("2.6.0#gcd877db.dirty", (2, 6, 0, "#gcd877db", "dirty")),
17+
("0.15.0.post16#g63b1a427.dirty", (0, 15, 0, "post16", "#g63b1a427", "dirty")),
18+
("1.#foo", (1, "#foo")),
19+
]
20+
21+
22+
def test_version_to_tuple() -> None:
23+
"""Test test_version_to_tuple function."""
24+
for v, ref in example_versions:
25+
t = _version.version_to_tuple(v)
26+
assert t == ref, f"{v} -> {t} != {ref}"
27+
28+
29+
def test_run_as_script() -> None:
30+
"""Test the basics of the CLI util."""
31+
# Plain call
32+
p = subprocess.run(
33+
[sys.executable, _version.__file__],
34+
capture_output=True,
35+
check=False,
36+
)
37+
assert p.returncode == 0
38+
assert p.stderr.decode().strip() == ""
39+
text = p.stdout.decode().strip()
40+
assert text == "PROJECT_NAME v0.0.0"
41+
42+
# Use 'version'
43+
p = subprocess.run(
44+
[sys.executable, _version.__file__, "version"],
45+
capture_output=True,
46+
check=False,
47+
)
48+
assert p.returncode == 0
49+
assert p.stderr.decode().strip() == ""
50+
text = p.stdout.decode().strip()
51+
assert text == "PROJECT_NAME v0.0.0"
52+
53+
# Use 'help'
54+
p = subprocess.run(
55+
[sys.executable, _version.__file__, "help"],
56+
capture_output=True,
57+
check=False,
58+
)
59+
assert p.returncode == 0
60+
assert p.stderr.decode().strip() == ""
61+
text = p.stdout.decode().strip()
62+
assert text.startswith("_version.py")
63+
assert "help" in text
64+
assert "bump" in text
65+
assert "update" in text
66+
67+
# Use false command
68+
p = subprocess.run(
69+
[sys.executable, _version.__file__, "foobar"],
70+
capture_output=True,
71+
check=False,
72+
)
73+
assert p.returncode == 1
74+
assert p.stderr.decode().strip() == ""
75+
text = p.stdout.decode().strip()
76+
assert text.startswith("Unknown command")
77+
78+
79+
# %%%%%
80+
81+
82+
def run_tests(scope: dict) -> None:
83+
"""Small util to run all tests."""
84+
for func in list(scope.values()):
85+
if callable(func) and func.__name__.startswith("test_"):
86+
sys.stdout.write(f"Running {func.__name__} ...\n")
87+
func()
88+
sys.stdout.write("Done\n")
89+
90+
91+
if __name__ == "__main__":
92+
run_tests(globals())

0 commit comments

Comments
 (0)