@@ -28,10 +28,13 @@ def str_from_console(s):
2828
2929
3030try :
31+ import collections
32+ import functools
3133 import re
3234 from typing import Iterator , List , Tuple
3335
34- from packaging .version import Version , _BaseVersion
36+ from packaging import version as V
37+ from packaging .version import VERSION_PATTERN , Version , _BaseVersion
3538
3639 ###
3740 ### Legacy support for LooseVersion / LegacyVersion, e.g. 2.4-openbsd
@@ -127,6 +130,126 @@ def base_version(self) -> str:
127130 def epoch (self ) -> int :
128131 return - 1
129132
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+
130253 LooseVersion = LegacyVersion
131254except ImportError :
132255 from distutils .version import LooseVersion , Version
0 commit comments