-
Notifications
You must be signed in to change notification settings - Fork 1
/
versions.py
235 lines (180 loc) · 7 KB
/
versions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
"""
Get and define python versions.
Get Operating System.
Get package info?
"""
from generallibrary.object import initBases
from packaging import version
import pkg_resources
from distutils.version import StrictVersion
import re
# Todo: Replace this temporary Ver class with revamped VerInfo split into isolated parts.
class Ver(StrictVersion):
def __init__(self, ver):
super().__init__(str(ver))
def bump(self):
""" Return a new Ver with bumped last value. """
if str(self).count(".") == 0:
return f"{self}.0.1"
elif str(self).count(".") == 1:
return f"{self}.1"
else:
bulk, micro = re.findall("(.*)(\\d)", str(self))[0]
return Ver(f"{bulk}{int(micro) + 1}")
class _OsInfo:
"""Get info regarding running operating system."""
_translate = {
"windows": "Windows",
"linux": "Linux",
"mac": "Darwin",
"java": "Java"
}
def __init__(self):
import platform
self._system = platform.system()
assert len(self._getOSList()) == 1
@property
def windows(self):
""" Get whether running on Windows. """
return self._system == self._translate["windows"]
@property
def linux(self):
""" Get whether running on Linux. """
return self._system == self._translate["linux"]
@property
def mac(self):
""" Get whether running on Mac. """
return self._system == self._translate["mac"]
@property
def java(self):
""" Get whether running on Java. """
return self._system == self._translate["java"]
@property
def os(self):
""" Return name of running operating system. """
return self._getOSList()[0]
def _getOSList(self):
return [name for name, system in self._translate.items() if getattr(self, name)]
class _PythonInfo:
""" Get info regarding running python version. """
_releaseLevels = {
"alpha": "a",
"beta": "b",
"candidate": "rc",
"final": ""
}
def __init__(self):
import sys
self._versionInfo = sys.version_info
assert self.pythonReleaseLevel in self._releaseLevels # Recognize release level
assert not (self.pythonFinal and self.pythonSerial) # Don't think final releases can have a serial number
@property
def pythonMajor(self):
""" Return first digit of python version. """
return self._versionInfo.major
@property
def pythonMinor(self):
""" Return second digit of python version. """
return self._versionInfo.minor
@property
def pythonMicro(self):
""" Return third digit of python version. """
return self._versionInfo.micro
@property
def pythonReleaseLevel(self):
""" Return release level of python version.
It's alpha, beta, candidate or final. """
return self._versionInfo.releaselevel
@property
def pythonSerial(self):
""" Return serial number of python version. I think it's only used for non-final release levels. """
return self._versionInfo.serial
@property
def pythonSerialString(self):
""" Return serial number of python version as a string, should be empty if it's 0. """
return str(self._versionInfo.serial) if self._versionInfo.serial else ""
@property
def pythonAlpha(self):
""" Return whether release level is 'alpha'. """
return self.pythonReleaseLevel == "alpha"
@property
def pythonBeta(self):
""" Return whether release level is 'beta'. """
return self.pythonReleaseLevel == "beta"
@property
def pythonCandidate(self):
""" Return whether release level is 'candidate'. """
return self.pythonReleaseLevel == "candidate"
@property
def pythonFinal(self):
""" Return whether release level is 'final'. """
return self.pythonReleaseLevel == "final"
@property
def pythonReleaseKeyword(self):
""" Return keyword for release level such as 'a', 'b', 'rc' or '' for final. """
return self._releaseLevels[self.pythonReleaseLevel]
@property
def pythonString(self):
""" Return python version as '3.8.5' or '3.8.5a4' if alpha release 4. """
return f"{self.pythonMajor}.{self.pythonMinor}.{self.pythonMicro}{self.pythonReleaseKeyword}{self.pythonSerialString}"
@property
def pythonVersion(self):
""" Returns a PythonVersion object that can be used to compare directly to an int, float or str. """
return PythonVersion(self.pythonString)
class _ConditionalFunctionalities:
""" Groups all functionality properties. """
@property
def caseSensitive(self):
""" Get whether current OS is case sensitive.
:param VerInfo self: """
return not self.windows
@property
def positionalArgument(self):
""" Get whether current python version supports positional arguments.
:param VerInfo self: """
return self.pythonVersion >= 3.8
@property
def pathDelimiter(self):
""" Get current OS's path delimiter.
:param VerInfo self: """
return "\\" if self.windows else "/"
@property
def pathRootIsDelimiter(self):
""" Get whether current OS defines path root as a starting delimiter.
:param VerInfo self: """
return not self.windows
@property
def pathRootHasColon(self):
""" Get whether current OS defines path root with a colon in the first part.
:param VerInfo self: """
return self.windows
@initBases
class VerInfo(_OsInfo, _PythonInfo, _ConditionalFunctionalities):
""" Get version info regarding current Python, OS and conditional functionalities.
Use conditional feature properties if possible. """
class DuckTyping:
""" I have an idea here to pair syntax tests to python versions.
We can then run them all and make sure they succeed / fail based on running versions.
Would have to deal with syntax error by some importing technique then I guess. """
from generallibrary.functions import Operators
@Operators.deco_define_comparisons(lambda left: left.version, lambda right: version.parse(str(right)))
class PythonVersion(DuckTyping):
""" Used by VerInfo.pythonVersion to easily compare python versions to int, float or string. """
def __init__(self, pythonString):
self._version = version.parse(pythonString)
@property
def version(self):
""" Get python version.
Protect variable."""
return self._version
def __eq__(self, other): ...
def __gt__(self, other): ...
def __lt__(self, other): ...
def __ge__(self, other): ...
def __le__(self, other): ...
def get_installed_packages():
""" Get a list of all installed packages as strings. """
return [pkg.key for pkg in pkg_resources.working_set]
def package_is_installed(*names):
""" Returns whether a package is installed. """
return all([name in get_installed_packages() for name in names])