forked from python/pymanager
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathverutils.py
More file actions
138 lines (119 loc) · 4.4 KB
/
verutils.py
File metadata and controls
138 lines (119 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
from .logging import LOGGER
class Version:
TEXT_MAP = {
"*": 0,
"dev": 1,
"a": 2,
"b": 3,
"c": 4,
"rc": 4,
"": 1000,
}
_TEXT_UNMAP = {v: k for k, v in TEXT_MAP.items()}
_LEVELS = None
# Versions with more fields than this will be truncated.
MAX_FIELDS = 8
def __init__(self, s):
import re
if isinstance(s, Version):
s = s.s
if not Version._LEVELS:
Version._LEVELS = "|".join(re.escape(k) for k in self.TEXT_MAP if k)
m = re.match(
r"^(?P<numbers>\d+(\.\d+)*)([\.\-]?(?P<level>" + Version._LEVELS + r")[\.]?(?P<serial>\d*))?$",
s,
re.I,
)
if not m:
raise ValueError("Failed to parse version %s", s)
bits = [int(v) for v in m.group("numbers").split(".")]
try:
dev = self.TEXT_MAP[(m.group("level") or "").lower()]
except LookupError:
dev = 0
LOGGER.warn("Version %s has invalid development level specified which will be ignored", s)
self.s = s
if len(bits) > self.MAX_FIELDS:
LOGGER.warn("Version %s is too long and will be truncated to %s for ordering purposes",
s, ".".join(map(str, bits[:self.MAX_FIELDS])))
self.sortkey = (
*bits[:self.MAX_FIELDS],
*([0] * (self.MAX_FIELDS - len(bits))),
len(bits), # for sort stability
dev,
int(m.group("serial") or 0)
)
self.prefix_match = dev == self.TEXT_MAP["*"]
self.prerelease_match = dev == self.TEXT_MAP["dev"]
def __str__(self):
return self.s
def __repr__(self):
return self.s
def __hash__(self):
return hash(self.sortkey)
def _are_equal(self, other, prefix_match=None, other_prefix_match=None, prerelease_match=None):
if other is None:
return False
if isinstance(other, str):
return self.s.casefold() == other.casefold()
if not isinstance(other, type(self)):
return False
if self.sortkey == other.sortkey:
return True
if prefix_match is not None and prefix_match or self.prefix_match:
if (self.sortkey[-3] <= other.sortkey[-3]
and self.sortkey[:self.sortkey[-3]] == other.sortkey[:self.sortkey[-3]]):
return True
elif other_prefix_match is not None and other_prefix_match or other.prefix_match:
if (self.sortkey[-3] >= other.sortkey[-3]
and self.sortkey[:other.sortkey[-3]] == other.sortkey[:other.sortkey[-3]]):
return True
if prerelease_match is not None and prerelease_match or self.prerelease_match:
if self.sortkey[:-3] == other.sortkey[:-3]:
return True
return False
def startswith(self, other):
return self._are_equal(other, other_prefix_match=True)
def above_lower_bound(self, other):
if other is None:
return True
if self.sortkey[:other.sortkey[-3]] > other.sortkey[:other.sortkey[-3]]:
return True
return False
def below_upper_bound(self, other):
if other is None:
return True
if self.sortkey[:other.sortkey[-3]] < other.sortkey[:other.sortkey[-3]]:
return True
return False
def __eq__(self, other):
return self._are_equal(other)
def __gt__(self, other):
if other is None:
return True
if isinstance(other, str):
other = type(self)(other)
return self.sortkey > other.sortkey
def __lt__(self, other):
if other is None:
return False
if isinstance(other, str):
other = type(self)(other)
return self.sortkey < other.sortkey
def __le__(self, other):
return self < other or self == other
def __ge__(self, other):
return self > other or self == other
@property
def is_prerelease(self):
return self.sortkey[-2] < self.TEXT_MAP[""]
def to_python_style(self, n=3, with_dev=True):
v = ".".join(str(i) for i in self.sortkey[:min(n, self.MAX_FIELDS)])
if with_dev:
try:
dev = self._TEXT_UNMAP[self.sortkey[-2]]
if dev:
v += f"{dev}{self.sortkey[-1]}"
except LookupError:
pass
return v