1# SPDX-License-Identifier: MIT
2
3
4from functools import total_ordering
5
6from ._funcs import astuple
7from ._make import attrib, attrs
8
9
10@total_ordering
11@attrs(eq=False, order=False, slots=True, frozen=True)
12class VersionInfo:
13 """
14 A version object that can be compared to tuple of length 1--4:
15
16 >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2)
17 True
18 >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1)
19 True
20 >>> vi = attr.VersionInfo(19, 2, 0, "final")
21 >>> vi < (19, 1, 1)
22 False
23 >>> vi < (19,)
24 False
25 >>> vi == (19, 2,)
26 True
27 >>> vi == (19, 2, 1)
28 False
29
30 .. versionadded:: 19.2
31 """
32
33 year = attrib(type=int)
34 minor = attrib(type=int)
35 micro = attrib(type=int)
36 releaselevel = attrib(type=str)
37
38 @classmethod
39 def _from_version_string(cls, s):
40 """
41 Parse *s* and return a _VersionInfo.
42 """
43 v = s.split(".")
44 if len(v) == 3:
45 v.append("final")
46
47 return cls(
48 year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3]
49 )
50
51 def _ensure_tuple(self, other):
52 """
53 Ensure *other* is a tuple of a valid length.
54
55 Returns a possibly transformed *other* and ourselves as a tuple of
56 the same length as *other*.
57 """
58
59 if self.__class__ is other.__class__:
60 other = astuple(other)
61
62 if not isinstance(other, tuple):
63 raise NotImplementedError
64
65 if not (1 <= len(other) <= 4):
66 raise NotImplementedError
67
68 return astuple(self)[: len(other)], other
69
70 def __eq__(self, other):
71 try:
72 us, them = self._ensure_tuple(other)
73 except NotImplementedError:
74 return NotImplemented
75
76 return us == them
77
78 def __lt__(self, other):
79 try:
80 us, them = self._ensure_tuple(other)
81 except NotImplementedError:
82 return NotImplemented
83
84 # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't
85 # have to do anything special with releaselevel for now.
86 return us < them