1
1
# -*- coding: utf8 -*-
2
2
# flake8: NOQA
3
+ import functools
3
4
import sys
4
5
from collections .abc import MutableMapping
5
6
@@ -25,3 +26,105 @@ def str_from_console(s):
25
26
return str (s )
26
27
except UnicodeDecodeError :
27
28
return str (s , encoding = "utf_8" )
29
+
30
+
31
+ try :
32
+ import re
33
+ from typing import Iterator , List , Tuple
34
+
35
+ from packaging .version import Version
36
+
37
+ ###
38
+ ### Legacy support for LooseVersion / LegacyVersion, e.g. 2.4-openbsd
39
+ ### https://github.com/pypa/packaging/blob/21.3/packaging/version.py#L106-L115
40
+ ### License: BSD, Accessed: Jan 14th, 2022
41
+ ###
42
+
43
+ LegacyCmpKey = Tuple [int , Tuple [str , ...]]
44
+
45
+ _legacy_version_component_re = re .compile (r"(\d+ | [a-z]+ | \.| -)" , re .VERBOSE )
46
+ _legacy_version_replacement_map = {
47
+ "pre" : "c" ,
48
+ "preview" : "c" ,
49
+ "-" : "final-" ,
50
+ "rc" : "c" ,
51
+ "dev" : "@" ,
52
+ }
53
+
54
+ def _parse_version_parts (s : str ) -> Iterator [str ]:
55
+ for part in _legacy_version_component_re .split (s ):
56
+ part = _legacy_version_replacement_map .get (part , part )
57
+
58
+ if not part or part == "." :
59
+ continue
60
+
61
+ if part [:1 ] in "0123456789" :
62
+ # pad for numeric comparison
63
+ yield part .zfill (8 )
64
+ else :
65
+ yield "*" + part
66
+
67
+ # ensure that alpha/beta/candidate are before final
68
+ yield "*final"
69
+
70
+ def _legacy_cmpkey (version : str ) -> LegacyCmpKey :
71
+ # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
72
+ # greater than or equal to 0. This will effectively put the LegacyVersion,
73
+ # which uses the defacto standard originally implemented by setuptools,
74
+ # as before all PEP 440 versions.
75
+ epoch = - 1
76
+
77
+ # This scheme is taken from pkg_resources.parse_version setuptools prior to
78
+ # it's adoption of the packaging library.
79
+ parts : List [str ] = []
80
+ for part in _parse_version_parts (version .lower ()):
81
+ if part .startswith ("*" ):
82
+ # remove "-" before a prerelease tag
83
+ if part < "*final" :
84
+ while parts and parts [- 1 ] == "*final-" :
85
+ parts .pop ()
86
+
87
+ # remove trailing zeros from each series of numeric parts
88
+ while parts and parts [- 1 ] == "00000000" :
89
+ parts .pop ()
90
+
91
+ parts .append (part )
92
+
93
+ return epoch , tuple (parts )
94
+
95
+ @functools .total_ordering
96
+ class LegacyVersion :
97
+ _key = None # type: Union[CmpKey, LegacyCmpKey]
98
+
99
+ def __hash__ (self ) -> int :
100
+ return hash (self ._key )
101
+
102
+ def __init__ (self , version : str ) -> None :
103
+ self ._version = str (version )
104
+ self ._key = _legacy_cmpkey (self ._version )
105
+
106
+ def __str__ (self ) -> str :
107
+ return self ._version
108
+
109
+ def __lt__ (self , other ):
110
+ if isinstance (other , str ):
111
+ other = LegacyVersion (other )
112
+ if not isinstance (other , LegacyVersion ):
113
+ return NotImplemented
114
+
115
+ return self ._key < other ._key
116
+
117
+ def __eq__ (self , other ) -> bool :
118
+ if isinstance (other , str ):
119
+ other = LegacyVersion (other )
120
+ if not isinstance (other , LegacyVersion ):
121
+ return NotImplemented
122
+
123
+ return self ._key == other ._key
124
+
125
+ def __repr__ (self ) -> str :
126
+ return "<LegacyVersion({0})>" .format (repr (str (self )))
127
+
128
+ LooseVersion = LegacyVersion
129
+ except ImportError :
130
+ from distutils .version import LooseVersion , Version
0 commit comments