@@ -28,10 +28,13 @@ def str_from_console(s):
28
28
29
29
30
30
try :
31
+ import collections
32
+ import functools
31
33
import re
32
34
from typing import Iterator , List , Tuple
33
35
34
- from packaging .version import Version , _BaseVersion
36
+ from packaging import version as V
37
+ from packaging .version import VERSION_PATTERN , Version , _BaseVersion
35
38
36
39
###
37
40
### Legacy support for LooseVersion / LegacyVersion, e.g. 2.4-openbsd
@@ -127,6 +130,126 @@ def base_version(self) -> str:
127
130
def epoch (self ) -> int :
128
131
return - 1
129
132
133
+ @functools .total_ordering
134
+ class _VersionCmpMixin :
135
+ # Credit: @layday
136
+ # Link: https://github.com/pypa/packaging/issues/465#issuecomment-1013715662
137
+ def __eq__ (self , other : object ) -> bool :
138
+ if isinstance (other , str ):
139
+ other = self .__class__ (other )
140
+ return super ().__eq__ (other )
141
+
142
+ def __lt__ (self , other : object ) -> bool :
143
+ if isinstance (other , str ):
144
+ other = self .__class__ (other )
145
+ return super ().__lt__ (other )
146
+
147
+ _Version = collections .namedtuple (
148
+ "_Version" , ["epoch" , "release" , "dev" , "pre" , "post" , "local" , "platform" ]
149
+ )
150
+
151
+ def _cmpkey (
152
+ epoch , # type: int
153
+ release , # type: Tuple[int, ...]
154
+ pre , # type: Optional[Tuple[str, int]]
155
+ post , # type: Optional[Tuple[str, int]]
156
+ dev , # type: Optional[Tuple[str, int]]
157
+ local , # type: Optional[Tuple[SubLocalType]]
158
+ platform , # type: Optional[Tuple[SubLocalType]]
159
+ ):
160
+ return V ._cmpkey (epoch , release , pre , post , dev , local ) + (
161
+ tuple (
162
+ (i , "" ) if isinstance (i , int ) else (V .NegativeInfinity , i )
163
+ for i in platform
164
+ )
165
+ )
166
+
167
+ class LegacyVersion (Version ):
168
+ _regex = re .compile
169
+ _regex = re .compile (
170
+ r"^\s*"
171
+ + VERSION_PATTERN
172
+ + r"(?:(?P<platform>(?:[-_\.][a-z0-9]+)*))? # platform version"
173
+ + r"\s*$" ,
174
+ re .VERBOSE | re .IGNORECASE ,
175
+ )
176
+
177
+ def __init__ (self , version ):
178
+ # type: (str) -> None
179
+
180
+ # Validate the version and parse it into pieces
181
+ match = self ._regex .search (version )
182
+ if not match :
183
+ raise V .InvalidVersion ("Invalid version: '{0}'" .format (version ))
184
+
185
+ # Store the parsed out pieces of the version
186
+ self ._version = _Version (
187
+ epoch = int (match .group ("epoch" )) if match .group ("epoch" ) else 0 ,
188
+ release = tuple (int (i ) for i in match .group ("release" ).split ("." )),
189
+ pre = V ._parse_letter_version (match .group ("pre_l" ), match .group ("pre_n" )),
190
+ post = V ._parse_letter_version (
191
+ match .group ("post_l" ),
192
+ match .group ("post_n1" ) or match .group ("post_n2" ),
193
+ ),
194
+ dev = V ._parse_letter_version (match .group ("dev_l" ), match .group ("dev_n" )),
195
+ local = V ._parse_local_version (match .group ("local" )),
196
+ platform = str (match .group ("platform" ))
197
+ if match .group ("platform" )
198
+ else "" ,
199
+ )
200
+
201
+ # Generate a key which will be used for sorting
202
+ self ._key = _cmpkey (
203
+ self ._version .epoch ,
204
+ self ._version .release ,
205
+ self ._version .pre ,
206
+ self ._version .post ,
207
+ self ._version .dev ,
208
+ self ._version .local ,
209
+ self ._version .platform ,
210
+ )
211
+
212
+ @property
213
+ def platform (self ):
214
+ # type: () -> Optional[str]
215
+ if self ._version .platform :
216
+ return "." .join (str (x ) for x in self ._version .platform )
217
+ else :
218
+ return None
219
+
220
+ def __str__ (self ):
221
+ # type: () -> str
222
+ parts = []
223
+
224
+ # Epoch
225
+ if self .epoch != 0 :
226
+ parts .append ("{0}!" .format (self .epoch ))
227
+
228
+ # Release segment
229
+ parts .append ("." .join (str (x ) for x in self .release ))
230
+
231
+ # Pre-release
232
+ if self .pre is not None :
233
+ parts .append ("" .join (str (x ) for x in self .pre ))
234
+
235
+ # Post-release
236
+ if self .post is not None :
237
+ parts .append (".post{0}" .format (self .post ))
238
+
239
+ # Development release
240
+ if self .dev is not None :
241
+ parts .append (".dev{0}" .format (self .dev ))
242
+
243
+ # Local version segment
244
+ if self .local is not None :
245
+ parts .append ("+{0}" .format (self .local ))
246
+
247
+ # Platform version segment
248
+ if self .platform is not None :
249
+ parts .append ("_{0}" .format (self .platform ))
250
+
251
+ return "" .join (parts )
252
+
130
253
LooseVersion = LegacyVersion
131
254
except ImportError :
132
255
from distutils .version import LooseVersion , Version
0 commit comments