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