Skip to content

Commit 7a10de8

Browse files
committed
Added new "versions" module.
1 parent c779cc0 commit 7a10de8

File tree

4 files changed

+655
-1
lines changed

4 files changed

+655
-1
lines changed

doc-source/api/versions.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
************************************
2+
:mod:`domdf_python_tools.versions`
3+
************************************
4+
5+
.. automodule:: domdf_python_tools.versions
6+
:members:
7+
:autosummary:
8+
:undoc-members:

domdf_python_tools/utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
3636
# MA 02110-1301, USA.
3737
#
38-
#
3938

4039
# stdlib
4140
import sys

domdf_python_tools/versions.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#!/usr/bin/env python
2+
#
3+
# versions.py
4+
"""
5+
NamedTuple-like class to represent a version number.
6+
"""
7+
#
8+
# Copyright © 2020 Dominic Davis-Foster <dominic@davis-foster.co.uk>
9+
#
10+
# This program is free software; you can redistribute it and/or modify
11+
# it under the terms of the GNU Lesser General Public License as published by
12+
# the Free Software Foundation; either version 3 of the License, or
13+
# (at your option) any later version.
14+
#
15+
# This program is distributed in the hope that it will be useful,
16+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
# GNU Lesser General Public License for more details.
19+
#
20+
# You should have received a copy of the GNU Lesser General Public License
21+
# along with this program; if not, write to the Free Software
22+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23+
# MA 02110-1301, USA.
24+
#
25+
26+
# stdlib
27+
from typing import Generator, Sequence, Tuple, Union
28+
29+
30+
class Version(Tuple[int, int, int]):
31+
"""
32+
NamedTuple-like class to represent a version number.
33+
34+
.. versionadded:: 0.4.4
35+
"""
36+
37+
major: int
38+
minor: int
39+
patch: int
40+
41+
def __new__(cls, major=0, minor=0, patch=0) -> "Version":
42+
t: "Version" = super().__new__(cls, (int(major), int(minor), int(patch))) # type: ignore
43+
44+
t.__dict__["major"] = int(major)
45+
t.__dict__["minor"] = int(minor)
46+
t.__dict__["patch"] = int(patch)
47+
48+
return t
49+
50+
def __repr__(self) -> str:
51+
"""
52+
Return the representation of the version.
53+
"""
54+
55+
types = self.__annotations__
56+
field_names = list(types.keys())
57+
repr_fmt = '(' + ', '.join(f"{name}=%r" for name in field_names) + ')'
58+
return self.__class__.__name__ + repr_fmt % self
59+
60+
def __str__(self) -> str:
61+
"""
62+
Return version as a string.
63+
"""
64+
65+
return "v" + ".".join(str(x) for x in self)
66+
67+
def __float__(self) -> float:
68+
"""
69+
Return the major and minor version number as a float.
70+
"""
71+
72+
return float(".".join(str(x) for x in self[:2]))
73+
74+
def __int__(self) -> int:
75+
"""
76+
Return the major version number as an integer.
77+
"""
78+
79+
return self.major
80+
81+
def __getnewargs__(self):
82+
"""
83+
Return Version as a plain tuple. Used by copy and pickle.
84+
"""
85+
86+
return tuple(self)
87+
88+
def __eq__(self, other) -> bool:
89+
other = _prep_for_eq(other)
90+
shortest = min(len(self), (len(other)))
91+
92+
return self[:shortest] == other[:shortest]
93+
94+
def __gt__(self, other) -> bool:
95+
other = _prep_for_eq(other)
96+
return tuple(self) > other
97+
98+
def __lt__(self, other) -> bool:
99+
other = _prep_for_eq(other)
100+
return tuple(self) < other
101+
102+
def __ge__(self, other) -> bool:
103+
other = _prep_for_eq(other)
104+
105+
return tuple(self)[:len(other)] >= other
106+
107+
def __le__(self, other) -> bool:
108+
other = _prep_for_eq(other)
109+
return tuple(self)[:len(other)] <= other
110+
111+
@classmethod
112+
def from_str(cls, version_string: str) -> "Version":
113+
return cls(*_iter_string(version_string))
114+
115+
@classmethod
116+
def from_tuple(cls, version_tuple: Tuple[Union[str, int], Union[str, int], Union[str, int]]) -> "Version":
117+
return cls(*(int(x) for x in version_tuple))
118+
119+
@classmethod
120+
def from_float(cls, version_float: float) -> "Version":
121+
return cls.from_str(str(version_float))
122+
123+
124+
def _iter_string(version_string: str) -> Generator[int, None, None]:
125+
return (int(x) for x in version_string.split("."))
126+
127+
128+
def _iter_float(version_float: float) -> Generator[int, None, None]:
129+
return _iter_string(str(version_float))
130+
131+
132+
def _prep_for_eq(other) -> Tuple[int, ...]:
133+
if isinstance(other, str):
134+
other = tuple(_iter_string(other))
135+
elif isinstance(other, (Version, Sequence)):
136+
other = tuple((int(x) for x in other))
137+
elif isinstance(other, (int, float)):
138+
other = tuple(_iter_float(other))
139+
else: # pragma: no cover
140+
raise NotImplementedError
141+
142+
return other

0 commit comments

Comments
 (0)