|
25 | 25 |
|
26 | 26 | # stdlib
|
27 | 27 | import re
|
28 |
| -from typing import Generator, Sequence, Tuple, Union |
| 28 | +from typing import Dict, Generator, Iterable, Sequence, Tuple, Union |
| 29 | + |
| 30 | +# 3rd party |
| 31 | +from typing_extensions import final |
29 | 32 |
|
30 | 33 | __all__ = ["Version"]
|
31 | 34 |
|
32 | 35 |
|
| 36 | +@final |
33 | 37 | class Version(Tuple[int, int, int]):
|
34 | 38 | """
|
35 | 39 | NamedTuple-like class to represent a version number.
|
36 | 40 |
|
37 |
| - :param major: The major version number. |
38 |
| - :type major: :class:`int` |
39 |
| - :param minor: The minor version number. |
40 |
| - :type minor: :class:`int` |
41 |
| - :param patch: The patch version number. |
42 |
| - :type patch: :class:`int` |
| 41 | + :param major: |
43 | 42 |
|
44 | 43 | .. versionadded:: 0.4.4
|
| 44 | +
|
| 45 | + .. versionchanged:: 1.4.0 Implemented the same interface as a :func:`collections.namedtuple`. |
45 | 46 | """
|
46 | 47 |
|
| 48 | + __slots__ = () |
| 49 | + |
| 50 | + #: The major version number. |
47 | 51 | major: int
|
48 |
| - "The major version number." |
49 | 52 |
|
| 53 | + #: The minor version number. |
50 | 54 | minor: int
|
51 |
| - "The minor version number." |
52 | 55 |
|
| 56 | + #: The patch version number. |
53 | 57 | patch: int
|
54 |
| - "The patch number." |
| 58 | + |
| 59 | + _fields: Tuple[str, str, str] = ("major", "minor", "patch") |
| 60 | + """ |
| 61 | + Tuple of strings listing the field names. |
| 62 | +
|
| 63 | + Useful for introspection and for creating new named tuple types from existing named tuples. |
| 64 | +
|
| 65 | + .. versionadded:: 1.4.0 |
| 66 | + """ |
| 67 | + |
| 68 | + _field_defaults: Dict[str, int] = {"major": 0, "minor": 0, "patch": 0} |
| 69 | + """ |
| 70 | + Dictionary mapping field names to default values. |
| 71 | +
|
| 72 | + .. versionadded:: 1.4.0 |
| 73 | + """ |
| 74 | + |
| 75 | + @property # type: ignore |
| 76 | + def major(self): |
| 77 | + return self[0] |
| 78 | + |
| 79 | + @property # type: ignore |
| 80 | + def minor(self): |
| 81 | + return self[1] |
| 82 | + |
| 83 | + @property # type: ignore |
| 84 | + def patch(self): |
| 85 | + return self[2] |
55 | 86 |
|
56 | 87 | def __new__(cls, major=0, minor=0, patch=0) -> "Version":
|
57 | 88 | t: "Version" = super().__new__(cls, (int(major), int(minor), int(patch))) # type: ignore
|
58 | 89 |
|
59 |
| - t.__dict__["major"] = int(major) |
60 |
| - t.__dict__["minor"] = int(minor) |
61 |
| - t.__dict__["patch"] = int(patch) |
62 |
| - |
63 | 90 | return t
|
64 | 91 |
|
65 | 92 | def __repr__(self) -> str:
|
66 | 93 | """
|
67 | 94 | Return the representation of the version.
|
68 | 95 | """
|
69 | 96 |
|
70 |
| - field_names = self.__annotations__.keys() |
71 |
| - repr_fmt = '(' + ", ".join(f"{name}=%r" for name in field_names) + ')' |
| 97 | + repr_fmt = '(' + ", ".join(f"{name}=%r" for name in self._fields) + ')' |
| 98 | + print(repr_fmt) |
72 | 99 | return self.__class__.__name__ + repr_fmt % self
|
73 | 100 |
|
74 | 101 | def __str__(self) -> str:
|
@@ -211,6 +238,48 @@ def from_float(cls, version_float: float) -> "Version":
|
211 | 238 |
|
212 | 239 | return cls.from_str(str(version_float))
|
213 | 240 |
|
| 241 | + def _asdict(self) -> Dict[str, int]: |
| 242 | + """ |
| 243 | + Return a new dict which maps field names to their corresponding values. |
| 244 | +
|
| 245 | + :rtype: |
| 246 | +
|
| 247 | + .. versionadded:: 1.4.0 |
| 248 | + """ |
| 249 | + |
| 250 | + return { |
| 251 | + "major": self.major, |
| 252 | + "minor": self.minor, |
| 253 | + "patch": self.patch, |
| 254 | + } |
| 255 | + |
| 256 | + def _replace(self, **kwargs) -> "Version": |
| 257 | + """ |
| 258 | + Return a new instance of the named tuple replacing specified fields with new values: |
| 259 | +
|
| 260 | + :param kwargs: |
| 261 | +
|
| 262 | + :rtype: |
| 263 | +
|
| 264 | + .. versionadded:: 1.4.0 |
| 265 | + """ |
| 266 | + |
| 267 | + return self.__class__(**{**self._asdict(), **kwargs}) |
| 268 | + |
| 269 | + @classmethod |
| 270 | + def _make(cls, iterable: Iterable[Union[str, int]]) -> "Version": |
| 271 | + """ |
| 272 | + Class method that makes a new instance from an existing sequence or iterable. |
| 273 | +
|
| 274 | + :param iterable: |
| 275 | +
|
| 276 | + :rtype: |
| 277 | +
|
| 278 | + .. versionadded:: 1.4.0 |
| 279 | + """ |
| 280 | + |
| 281 | + return cls(*(int(x) for x in tuple(iterable)[:3])) |
| 282 | + |
214 | 283 |
|
215 | 284 | def _iter_string(version_string: str) -> Generator[int, None, None]:
|
216 | 285 | """
|
|
0 commit comments