• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

domdfcoding / domdf_python_tools / 7166137878

11 Dec 2023 10:30AM UTC coverage: 97.456%. Remained the same
7166137878

push

github

domdfcoding
Bump version v3.7.0 -> v3.8.0

1 of 1 new or added line in 1 file covered. (100.0%)

2145 of 2201 relevant lines covered (97.46%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.12
/domdf_python_tools/versions.py
1
#!/usr/bin/env python
2
#
3
#  versions.py
4
"""
1✔
5
NamedTuple-like class to represent a version number.
6

7
.. versionadded:: 0.4.4
8
"""
9
#
10
#  Copyright © 2020 Dominic Davis-Foster <dominic@davis-foster.co.uk>
11
#
12
#  Permission is hereby granted, free of charge, to any person obtaining a copy
13
#  of this software and associated documentation files (the "Software"), to deal
14
#  in the Software without restriction, including without limitation the rights
15
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
#  copies of the Software, and to permit persons to whom the Software is
17
#  furnished to do so, subject to the following conditions:
18
#
19
#  The above copyright notice and this permission notice shall be included in all
20
#  copies or substantial portions of the Software.
21
#
22
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25
#  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
26
#  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
27
#  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
28
#  OR OTHER DEALINGS IN THE SOFTWARE.
29
#
30

31
# stdlib
32
import re
1✔
33
from typing import Dict, Generator, Iterable, Sequence, Tuple, Type, TypeVar, Union
1✔
34

35
# 3rd party
36
from typing_extensions import final
1✔
37

38
__all__ = ["Version"]
1✔
39

40
_V = TypeVar("_V", bound="Version")
1✔
41

42

43
@final
1✔
44
class Version(Tuple[int, int, int]):
1✔
45
        """
46
        NamedTuple-like class to represent a version number.
47

48
        :param major:
49

50
        .. versionchanged:: 1.4.0 Implemented the same interface as a :func:`collections.namedtuple`.
51
        """
52

53
        __slots__ = ()
1✔
54

55
        #: The major version number.
56
        major: int
1✔
57

58
        #: The minor version number.
59
        minor: int
1✔
60

61
        #: The patch version number.
62
        patch: int
1✔
63

64
        _fields: Tuple[str, str, str] = ("major", "minor", "patch")
1✔
65
        """
66
        Tuple of strings listing the field names.
67

68
        Useful for introspection and for creating new named tuple types from existing named tuples.
69

70
        .. versionadded:: 1.4.0
71
        """
72

73
        _field_defaults: Dict[str, int] = {"major": 0, "minor": 0, "patch": 0}
1✔
74
        """
75
        Dictionary mapping field names to default values.
76

77
        .. versionadded:: 1.4.0
78
        """
79

80
        @property  # type: ignore
1✔
81
        def major(self):  # noqa: D102
1✔
82
                return self[0]
1✔
83

84
        @property  # type: ignore
1✔
85
        def minor(self):  # noqa: D102
1✔
86
                return self[1]
×
87

88
        @property  # type: ignore
1✔
89
        def patch(self):  # noqa: D102
1✔
90
                return self[2]
×
91

92
        def __new__(cls: Type[_V], major=0, minor=0, patch=0) -> _V:  # noqa: D102
1✔
93
                t: _V = super().__new__(cls, (int(major), int(minor), int(patch)))  # type: ignore
1✔
94

95
                return t
1✔
96

97
        def __repr__(self) -> str:
1✔
98
                """
99
                Return the representation of the version.
100
                """
101

102
                repr_fmt = '(' + ", ".join(f"{name}=%r" for name in self._fields) + ')'
1✔
103
                return self.__class__.__name__ + repr_fmt % self
1✔
104

105
        def __str__(self) -> str:
1✔
106
                """
107
                Return version as a string.
108
                """
109

110
                return 'v' + '.'.join(str(x) for x in self)  # pylint: disable=not-an-iterable
1✔
111

112
        def __float__(self) -> float:
1✔
113
                """
114
                Return the major and minor version number as a float.
115
                """
116

117
                return float('.'.join(str(x) for x in self[:2]))
1✔
118

119
        def __int__(self) -> int:
1✔
120
                """
121
                Return the major version number as an integer.
122
                """
123

124
                return self.major
1✔
125

126
        def __getnewargs__(self):
1✔
127
                """
128
                Return Version as a plain tuple. Used by copy and pickle.
129
                """
130

131
                return tuple(self)
1✔
132

133
        def __eq__(self, other) -> bool:
1✔
134
                """
135
                Returns whether this version is equal to the other version.
136

137
                :type other: :class:`str`, :class:`float`, :class:`~.Version`
138
                """
139

140
                other = _prep_for_eq(other)
1✔
141

142
                if other is NotImplemented:
1✔
143
                        return NotImplemented  # pragma: no cover
144
                else:
145
                        shortest = min(len(self), (len(other)))
1✔
146
                        return self[:shortest] == other[:shortest]
1✔
147

148
        def __gt__(self, other) -> bool:
1✔
149
                """
150
                Returns whether this version is greater than the other version.
151

152
                :type other: :class:`str`, :class:`float`, :class:`~.Version`
153
                """
154

155
                other = _prep_for_eq(other)
1✔
156

157
                if other is NotImplemented:
1✔
158
                        return NotImplemented  # pragma: no cover
159
                else:
160
                        return tuple(self) > other
1✔
161

162
        def __lt__(self, other) -> bool:
1✔
163
                """
164
                Returns whether this version is less than the other version.
165

166
                :type other: :class:`str`, :class:`float`, :class:`~.Version`
167
                """
168

169
                other = _prep_for_eq(other)
1✔
170

171
                if other is NotImplemented:
1✔
172
                        return NotImplemented  # pragma: no cover
173
                else:
174
                        return tuple(self) < other
1✔
175

176
        def __ge__(self, other) -> bool:
1✔
177
                """
178
                Returns whether this version is greater than or equal to the other version.
179

180
                :type other: :class:`str`, :class:`float`, :class:`~.Version`
181
                """
182

183
                other = _prep_for_eq(other)
1✔
184

185
                if other is NotImplemented:
1✔
186
                        return NotImplemented  # pragma: no cover
187
                else:
188
                        return tuple(self)[:len(other)] >= other
1✔
189

190
        def __le__(self, other) -> bool:
1✔
191
                """
192
                Returns whether this version is less than or equal to the other version.
193

194
                :type other: :class:`str`, :class:`float`, :class:`~.Version`
195
                """
196

197
                other = _prep_for_eq(other)
1✔
198

199
                if other is NotImplemented:
1✔
200
                        return NotImplemented  # pragma: no cover
201
                else:
202
                        return tuple(self)[:len(other)] <= other
1✔
203

204
        @classmethod
1✔
205
        def from_str(cls: Type[_V], version_string: str) -> _V:
1✔
206
                """
207
                Create a :class:`~.Version` from a :class:`str`.
208

209
                :param version_string: The version number.
210

211
                :return: The created :class:`~domdf_python_tools.versions.Version`.
212
                """
213

214
                return cls(*_iter_string(version_string))
1✔
215

216
        @classmethod
1✔
217
        def from_tuple(cls: Type[_V], version_tuple: Tuple[Union[str, int], ...]) -> _V:
1✔
218
                """
219
                Create a :class:`~.Version` from a :class:`tuple`.
220

221
                :param version_tuple: The version number.
222

223
                :return: The created :class:`~domdf_python_tools.versions.Version`.
224

225
                .. versionchanged:: 0.9.0
226

227
                        Tuples with more than three elements are truncated.
228
                        Previously a :exc:`TypeError` was raised.
229
                """
230

231
                return cls(*(int(x) for x in version_tuple[:3]))
1✔
232

233
        @classmethod
1✔
234
        def from_float(cls: Type[_V], version_float: float) -> _V:
1✔
235
                """
236
                Create a :class:`~.Version` from a :class:`float`.
237

238
                :param version_float: The version number.
239

240
                :return: The created :class:`~domdf_python_tools.versions.Version`.
241
                """
242

243
                return cls.from_str(str(version_float))
1✔
244

245
        def _asdict(self) -> Dict[str, int]:
1✔
246
                """
247
                Return a new dict which maps field names to their corresponding values.
248

249
                .. versionadded:: 1.4.0
250
                """
251

252
                return {
×
253
                                "major": self.major,
254
                                "minor": self.minor,
255
                                "patch": self.patch,
256
                                }
257

258
        def _replace(self: _V, **kwargs) -> _V:
1✔
259
                """
260
                Return a new instance of the named tuple replacing specified fields with new values.
261

262
                .. versionadded:: 1.4.0
263

264
                :param kwargs:
265
                """
266

267
                return self.__class__(**{**self._asdict(), **kwargs})
×
268

269
        @classmethod
1✔
270
        def _make(cls: Type[_V], iterable: Iterable[Union[str, int]]) -> _V:
1✔
271
                """
272
                Class method that makes a new instance from an existing sequence or iterable.
273

274
                .. versionadded:: 1.4.0
275

276
                :param iterable:
277
                """
278

279
                return cls(*(int(x) for x in tuple(iterable)[:3]))
×
280

281

282
def _iter_string(version_string: str) -> Generator[int, None, None]:
1✔
283
        """
284
        Iterate over the version elements from a string.
285

286
        :param version_string: The version as a string.
287

288
        :return: Iterable elements of the version.
289
        """
290

291
        return (int(x) for x in re.split("[.,]", version_string))
1✔
292

293

294
def _iter_float(version_float: float) -> Generator[int, None, None]:
1✔
295
        """
296
        Iterate over the version elements from a float.
297

298
        :param version_float: The version as a float.
299

300
        :return: Iterable elements of the version.
301
        """
302

303
        return _iter_string(str(version_float))
1✔
304

305

306
def _prep_for_eq(other: Union[str, float, Version], ) -> Tuple[int, ...]:
1✔
307
        """
308
        Prepare 'other' for use in ``__eq__``, ``__le__``, ``__ge__``, ``__gt__``, and ``__lt__``.
309
        """
310

311
        if isinstance(other, str):
1✔
312
                return tuple(_iter_string(other))
1✔
313
        elif isinstance(other, (Version, Sequence)):
1✔
314
                return tuple(int(x) for x in other)
1✔
315
        elif isinstance(other, (int, float)):
1✔
316
                return tuple(_iter_float(other))
1✔
317
        else:  # pragma: no cover
318
                return NotImplemented
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc