Skip to content

Commit 75a1d7d

Browse files
authored
refactor!: Drop VersionInfo in favor of tuple (#124)
* fix: fix and refactor version tests to handle release candidates correctly * fix: remove VersionInfo entirely keep graphql_server.version_info as a plain tuple add tests using the packaging package to make sure graphql_server.version and graphql_server.version_info are PEP 440–compliant and pointing to the same version * chore: update pre-commit hooks
1 parent 9180278 commit 75a1d7d

File tree

4 files changed

+50
-106
lines changed

4 files changed

+50
-106
lines changed

.pre-commit-config.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
default_language_version:
2-
python: python3.10
2+
python: python3.11
33
exclude: LICENSE
44
repos:
55
- repo: https://github.com/pre-commit/pre-commit-hooks
6-
rev: v4.4.0
6+
rev: v4.5.0
77
hooks:
88
- id: check-merge-conflict
99
- id: check-json
@@ -20,11 +20,11 @@ repos:
2020
hooks:
2121
- id: check-manifest
2222
- repo: https://github.com/psf/black
23-
rev: 23.7.0
23+
rev: 23.9.1
2424
hooks:
2525
- id: black
2626
- repo: https://github.com/astral-sh/ruff-pre-commit
27-
rev: v0.0.283
27+
rev: v0.1.0
2828
hooks:
2929
- id: ruff
3030
args: [--fix, --exit-non-zero-on-fix, --show-fixes]

graphql_server/version.py

+11-40
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,15 @@
1-
import re
2-
from typing import NamedTuple
3-
41
__all__ = ["version", "version_info"]
52

63

74
version = "3.0.0b7"
8-
9-
_re_version = re.compile(r"(\d+)\.(\d+)\.(\d+)(\D*)(\d*)")
10-
11-
12-
class VersionInfo(NamedTuple):
13-
major: int
14-
minor: int
15-
micro: int
16-
releaselevel: str
17-
serial: int
18-
19-
@classmethod
20-
def from_str(cls, v: str) -> "VersionInfo":
21-
groups = _re_version.match(v).groups() # type: ignore
22-
major, minor, micro = map(int, groups[:3])
23-
level = (groups[3] or "")[:1]
24-
if level == "a":
25-
level = "alpha"
26-
elif level == "b":
27-
level = "beta"
28-
elif level in ("c", "r"):
29-
level = "candidate"
30-
else:
31-
level = "final"
32-
serial = groups[4]
33-
serial = int(serial) if serial else 0
34-
return cls(major, minor, micro, level, serial)
35-
36-
def __str__(self) -> str:
37-
v = f"{self.major}.{self.minor}.{self.micro}"
38-
level = self.releaselevel
39-
if level and level != "final":
40-
v = f"{v}{level[:1]}{self.serial}"
41-
return v
42-
43-
44-
version_info = VersionInfo.from_str(version)
5+
version_info = (3, 0, 0, "beta", 7)
6+
# version_info has the same format as django.VERSION
7+
# https://github.com/django/django/blob/4a5048b036fd9e965515e31fdd70b0af72655cba/django/utils/version.py#L22
8+
#
9+
# examples
10+
# "3.0.0" -> (3, 0, 0, "final", 0)
11+
# "3.0.0rc1" -> (3, 0, 0, "rc", 1)
12+
# "3.0.0b7" -> (3, 0, 0, "beta", 7)
13+
# "3.0.0a2" -> (3, 0, 0, "alpha", 2)
14+
#
15+
# also see tests/test_version.py

setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"pytest-cov>=4,<5",
1414
"Jinja2>=3.1,<4",
1515
"sanic-testing>=22.3,<24",
16+
"packaging==23.2",
1617
]
1718

1819
dev_requires = [

tests/test_version.py

+34-62
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,50 @@
1-
import re
1+
import packaging
2+
from packaging.version import Version
23

3-
import graphql_server
4-
from graphql_server.version import VersionInfo, version, version_info
4+
from graphql_server.version import version, version_info
55

6-
_re_version = re.compile(r"(\d+)\.(\d+)\.(\d+)(?:([abc])(\d+))?$")
6+
RELEASE_LEVEL = {"alpha": "a", "beta": "b", "rc": "rc", "final": None}
77

88

9-
def test_create_version_info_from_fields():
10-
v = VersionInfo(1, 2, 3, "alpha", 4)
11-
assert v.major == 1
12-
assert v.minor == 2
13-
assert v.micro == 3
14-
assert v.releaselevel == "alpha"
15-
assert v.serial == 4
9+
parsed_version = Version(version)
1610

1711

18-
def test_create_version_info_from_str():
19-
v = VersionInfo.from_str("1.2.3")
20-
assert v.major == 1
21-
assert v.minor == 2
22-
assert v.micro == 3
23-
assert v.releaselevel == "final"
24-
assert v.serial == 0
25-
v = VersionInfo.from_str("1.2.3a4")
26-
assert v.major == 1
27-
assert v.minor == 2
28-
assert v.micro == 3
29-
assert v.releaselevel == "alpha"
30-
assert v.serial == 4
31-
v = VersionInfo.from_str("1.2.3beta4")
32-
assert v.major == 1
33-
assert v.minor == 2
34-
assert v.micro == 3
35-
assert v.releaselevel == "beta"
36-
assert v.serial == 4
37-
v = VersionInfo.from_str("12.34.56rc789")
38-
assert v.major == 12
39-
assert v.minor == 34
40-
assert v.micro == 56
41-
assert v.releaselevel == "candidate"
42-
assert v.serial == 789
12+
def test_valid_version() -> None:
13+
packaging.version.parse(version)
4314

4415

45-
def test_serialize_as_str():
46-
v = VersionInfo(1, 2, 3, "final", 0)
47-
assert str(v) == "1.2.3"
48-
v = VersionInfo(1, 2, 3, "alpha", 4)
49-
assert str(v) == "1.2.3a4"
16+
def test_valid_version_info() -> None:
17+
"""version_info has to be a tuple[int, int, int, str, int]"""
18+
assert isinstance(version_info, tuple)
19+
assert len(version_info) == 5
5020

21+
major, minor, micro, release_level, serial = version_info
22+
assert isinstance(major, int)
23+
assert isinstance(minor, int)
24+
assert isinstance(micro, int)
25+
assert isinstance(release_level, str)
26+
assert isinstance(serial, int)
5127

52-
def test_base_package_has_correct_version():
53-
assert graphql_server.__version__ == version
54-
assert graphql_server.version == version
5528

29+
def test_valid_version_release_level() -> None:
30+
if parsed_version.pre is not None:
31+
valid_release_levels = {v for v in RELEASE_LEVEL.values() if v is not None}
32+
assert parsed_version.pre[0] in valid_release_levels
5633

57-
def test_base_package_has_correct_version_info():
58-
assert graphql_server.__version_info__ is version_info
59-
assert graphql_server.version_info is version_info
6034

35+
def test_valid_version_info_release_level() -> None:
36+
assert version_info[3] in RELEASE_LEVEL.keys()
6137

62-
def test_version_has_correct_format():
63-
assert isinstance(version, str)
64-
assert _re_version.match(version)
6538

39+
def test_version_same_as_version_info() -> None:
40+
assert (
41+
parsed_version.major,
42+
parsed_version.minor,
43+
parsed_version.micro,
44+
) == version_info[:3]
6645

67-
def test_version_info_has_correct_fields():
68-
assert isinstance(version_info, tuple)
69-
assert str(version_info) == version
70-
groups = _re_version.match(version).groups() # type: ignore
71-
assert version_info.major == int(groups[0])
72-
assert version_info.minor == int(groups[1])
73-
assert version_info.micro == int(groups[2])
74-
if groups[3] is None: # pragma: no cover
75-
assert groups[4] is None
76-
else: # pragma: no cover
77-
assert version_info.releaselevel[:1] == groups[3]
78-
assert version_info.serial == int(groups[4])
46+
release_level, serial = version_info[-2:]
47+
if parsed_version.is_prerelease:
48+
assert (RELEASE_LEVEL[release_level], serial) == parsed_version.pre
49+
else:
50+
assert (release_level, serial) == ("final", 0)

0 commit comments

Comments
 (0)