@@ -20,20 +20,33 @@ class CannotParseVersionException(Exception):
20
20
"""
21
21
22
22
23
+ class UnknownVersion (Exception ):
24
+ """
25
+ Thrown if version is null or "unknown".
26
+ """
27
+
28
+
23
29
def parse_version (version_string : str ):
24
30
"""
25
31
Splits a version string into an array for comparison.
26
32
This includes dealing with some letters.
27
33
28
34
e.g. 1.1.1a would become [1, 1, 1, a]
29
35
"""
30
- versionString = version_string
36
+
37
+ if not version_string or version_string .lower () == "unknown" :
38
+ raise UnknownVersion (f"version string = { version_string } " )
39
+
40
+ versionString = version_string .strip ()
31
41
versionArray = []
32
42
33
43
# convert - and _ to be treated like . below
34
44
# we could switch to a re split but it seems to leave blanks so this is less hassle
35
45
versionString = versionString .replace ("-" , "." )
36
46
versionString = versionString .replace ("_" , "." )
47
+ # Note: there may be other non-alphanumeric characters we want to add here in the
48
+ # future, but we'd like to look at those cases before adding them in case the version
49
+ # logic is very different.
37
50
38
51
# Attempt a split
39
52
split_version = versionString .split ("." )
@@ -52,6 +65,7 @@ def parse_version(version_string: str):
52
65
versionArray .append (section )
53
66
54
67
# if it looks like 42a split out the letters and numbers
68
+ # We will treat 42a as coming *after* version 42.
55
69
elif re .match (number_letter , section ):
56
70
result = re .findall (number_letter , section )
57
71
@@ -65,6 +79,7 @@ def parse_version(version_string: str):
65
79
66
80
# if it looks like rc1 or dev7 we'll leave it together as it may be some kind of pre-release
67
81
# and we'll probably want to handle it specially in the compare.
82
+ # We need to threat 42dev7 as coming *before* version 42.
68
83
elif re .match (letter_number , section ):
69
84
versionArray .append (section )
70
85
@@ -101,10 +116,12 @@ def version_compare(v1: str, v2: str):
101
116
# This might be a bad choice in some cases: Do we want ag < z?
102
117
# I suspect projects using letters in version names may not use ranges in nvd
103
118
# for this reason (e.g. openssl)
119
+ # Converting to lower() so that 3.14a == 3.14A
120
+ # but this may not be ideal in all cases
104
121
elif v1_array [i ].isalpha () and v2_array [i ].isalpha ():
105
- if v1_array [i ] > v2_array [i ]:
122
+ if v1_array [i ]. lower () > v2_array [i ]. lower () :
106
123
return 1
107
- if v1_array [i ] < v2_array [i ]:
124
+ if v1_array [i ]. lower () < v2_array [i ]. lower () :
108
125
return - 1
109
126
110
127
else :
@@ -170,25 +187,33 @@ class Version(str):
170
187
"""
171
188
172
189
def __cmp__ (self , other ):
190
+ """compare"""
173
191
return version_compare (self , other )
174
192
175
193
def __lt__ (self , other ):
194
+ """<"""
176
195
return bool (version_compare (self , other ) < 0 )
177
196
178
197
def __le__ (self , other ):
198
+ """<="""
179
199
return bool (version_compare (self , other ) <= 0 )
180
200
181
201
def __gt__ (self , other ):
202
+ """>"""
182
203
return bool (version_compare (self , other ) > 0 )
183
204
184
205
def __ge__ (self , other ):
206
+ """>="""
185
207
return bool (version_compare (self , other ) >= 0 )
186
208
187
209
def __eq__ (self , other ):
210
+ """=="""
188
211
return bool (version_compare (self , other ) == 0 )
189
212
190
213
def __ne__ (self , other ):
214
+ """!="""
191
215
return bool (version_compare (self , other ) != 0 )
192
216
193
217
def __repr__ (self ):
218
+ """print the version string"""
194
219
return f"Version: { self } "
0 commit comments