1 | n/a | #!/usr/bin/env python3 |
---|
2 | n/a | |
---|
3 | n/a | """ This module tries to retrieve as much platform-identifying data as |
---|
4 | n/a | possible. It makes this information available via function APIs. |
---|
5 | n/a | |
---|
6 | n/a | If called from the command line, it prints the platform |
---|
7 | n/a | information concatenated as single string to stdout. The output |
---|
8 | n/a | format is useable as part of a filename. |
---|
9 | n/a | |
---|
10 | n/a | """ |
---|
11 | n/a | # This module is maintained by Marc-Andre Lemburg <mal@egenix.com>. |
---|
12 | n/a | # If you find problems, please submit bug reports/patches via the |
---|
13 | n/a | # Python bug tracker (http://bugs.python.org) and assign them to "lemburg". |
---|
14 | n/a | # |
---|
15 | n/a | # Still needed: |
---|
16 | n/a | # * support for MS-DOS (PythonDX ?) |
---|
17 | n/a | # * support for Amiga and other still unsupported platforms running Python |
---|
18 | n/a | # * support for additional Linux distributions |
---|
19 | n/a | # |
---|
20 | n/a | # Many thanks to all those who helped adding platform-specific |
---|
21 | n/a | # checks (in no particular order): |
---|
22 | n/a | # |
---|
23 | n/a | # Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell, |
---|
24 | n/a | # Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef |
---|
25 | n/a | # Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg |
---|
26 | n/a | # Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark |
---|
27 | n/a | # Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support), |
---|
28 | n/a | # Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve |
---|
29 | n/a | # Dower |
---|
30 | n/a | # |
---|
31 | n/a | # History: |
---|
32 | n/a | # |
---|
33 | n/a | # <see CVS and SVN checkin messages for history> |
---|
34 | n/a | # |
---|
35 | n/a | # 1.0.8 - changed Windows support to read version from kernel32.dll |
---|
36 | n/a | # 1.0.7 - added DEV_NULL |
---|
37 | n/a | # 1.0.6 - added linux_distribution() |
---|
38 | n/a | # 1.0.5 - fixed Java support to allow running the module on Jython |
---|
39 | n/a | # 1.0.4 - added IronPython support |
---|
40 | n/a | # 1.0.3 - added normalization of Windows system name |
---|
41 | n/a | # 1.0.2 - added more Windows support |
---|
42 | n/a | # 1.0.1 - reformatted to make doc.py happy |
---|
43 | n/a | # 1.0.0 - reformatted a bit and checked into Python CVS |
---|
44 | n/a | # 0.8.0 - added sys.version parser and various new access |
---|
45 | n/a | # APIs (python_version(), python_compiler(), etc.) |
---|
46 | n/a | # 0.7.2 - fixed architecture() to use sizeof(pointer) where available |
---|
47 | n/a | # 0.7.1 - added support for Caldera OpenLinux |
---|
48 | n/a | # 0.7.0 - some fixes for WinCE; untabified the source file |
---|
49 | n/a | # 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and |
---|
50 | n/a | # vms_lib.getsyi() configured |
---|
51 | n/a | # 0.6.1 - added code to prevent 'uname -p' on platforms which are |
---|
52 | n/a | # known not to support it |
---|
53 | n/a | # 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k; |
---|
54 | n/a | # did some cleanup of the interfaces - some APIs have changed |
---|
55 | n/a | # 0.5.5 - fixed another type in the MacOS code... should have |
---|
56 | n/a | # used more coffee today ;-) |
---|
57 | n/a | # 0.5.4 - fixed a few typos in the MacOS code |
---|
58 | n/a | # 0.5.3 - added experimental MacOS support; added better popen() |
---|
59 | n/a | # workarounds in _syscmd_ver() -- still not 100% elegant |
---|
60 | n/a | # though |
---|
61 | n/a | # 0.5.2 - fixed uname() to return '' instead of 'unknown' in all |
---|
62 | n/a | # return values (the system uname command tends to return |
---|
63 | n/a | # 'unknown' instead of just leaving the field empty) |
---|
64 | n/a | # 0.5.1 - included code for slackware dist; added exception handlers |
---|
65 | n/a | # to cover up situations where platforms don't have os.popen |
---|
66 | n/a | # (e.g. Mac) or fail on socket.gethostname(); fixed libc |
---|
67 | n/a | # detection RE |
---|
68 | n/a | # 0.5.0 - changed the API names referring to system commands to *syscmd*; |
---|
69 | n/a | # added java_ver(); made syscmd_ver() a private |
---|
70 | n/a | # API (was system_ver() in previous versions) -- use uname() |
---|
71 | n/a | # instead; extended the win32_ver() to also return processor |
---|
72 | n/a | # type information |
---|
73 | n/a | # 0.4.0 - added win32_ver() and modified the platform() output for WinXX |
---|
74 | n/a | # 0.3.4 - fixed a bug in _follow_symlinks() |
---|
75 | n/a | # 0.3.3 - fixed popen() and "file" command invokation bugs |
---|
76 | n/a | # 0.3.2 - added architecture() API and support for it in platform() |
---|
77 | n/a | # 0.3.1 - fixed syscmd_ver() RE to support Windows NT |
---|
78 | n/a | # 0.3.0 - added system alias support |
---|
79 | n/a | # 0.2.3 - removed 'wince' again... oh well. |
---|
80 | n/a | # 0.2.2 - added 'wince' to syscmd_ver() supported platforms |
---|
81 | n/a | # 0.2.1 - added cache logic and changed the platform string format |
---|
82 | n/a | # 0.2.0 - changed the API to use functions instead of module globals |
---|
83 | n/a | # since some action take too long to be run on module import |
---|
84 | n/a | # 0.1.0 - first release |
---|
85 | n/a | # |
---|
86 | n/a | # You can always get the latest version of this module at: |
---|
87 | n/a | # |
---|
88 | n/a | # http://www.egenix.com/files/python/platform.py |
---|
89 | n/a | # |
---|
90 | n/a | # If that URL should fail, try contacting the author. |
---|
91 | n/a | |
---|
92 | n/a | __copyright__ = """ |
---|
93 | n/a | Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com |
---|
94 | n/a | Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com |
---|
95 | n/a | |
---|
96 | n/a | Permission to use, copy, modify, and distribute this software and its |
---|
97 | n/a | documentation for any purpose and without fee or royalty is hereby granted, |
---|
98 | n/a | provided that the above copyright notice appear in all copies and that |
---|
99 | n/a | both that copyright notice and this permission notice appear in |
---|
100 | n/a | supporting documentation or portions thereof, including modifications, |
---|
101 | n/a | that you make. |
---|
102 | n/a | |
---|
103 | n/a | EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO |
---|
104 | n/a | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
---|
105 | n/a | FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, |
---|
106 | n/a | INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING |
---|
107 | n/a | FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
---|
108 | n/a | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION |
---|
109 | n/a | WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! |
---|
110 | n/a | |
---|
111 | n/a | """ |
---|
112 | n/a | |
---|
113 | n/a | __version__ = '1.0.7' |
---|
114 | n/a | |
---|
115 | n/a | import collections |
---|
116 | n/a | import sys, os, re, subprocess |
---|
117 | n/a | |
---|
118 | n/a | import warnings |
---|
119 | n/a | |
---|
120 | n/a | ### Globals & Constants |
---|
121 | n/a | |
---|
122 | n/a | # Determine the platform's /dev/null device |
---|
123 | n/a | try: |
---|
124 | n/a | DEV_NULL = os.devnull |
---|
125 | n/a | except AttributeError: |
---|
126 | n/a | # os.devnull was added in Python 2.4, so emulate it for earlier |
---|
127 | n/a | # Python versions |
---|
128 | n/a | if sys.platform in ('dos', 'win32', 'win16'): |
---|
129 | n/a | # Use the old CP/M NUL as device name |
---|
130 | n/a | DEV_NULL = 'NUL' |
---|
131 | n/a | else: |
---|
132 | n/a | # Standard Unix uses /dev/null |
---|
133 | n/a | DEV_NULL = '/dev/null' |
---|
134 | n/a | |
---|
135 | n/a | # Directory to search for configuration information on Unix. |
---|
136 | n/a | # Constant used by test_platform to test linux_distribution(). |
---|
137 | n/a | _UNIXCONFDIR = '/etc' |
---|
138 | n/a | |
---|
139 | n/a | ### Platform specific APIs |
---|
140 | n/a | |
---|
141 | n/a | _libc_search = re.compile(b'(__libc_init)' |
---|
142 | n/a | b'|' |
---|
143 | n/a | b'(GLIBC_([0-9.]+))' |
---|
144 | n/a | b'|' |
---|
145 | n/a | br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII) |
---|
146 | n/a | |
---|
147 | n/a | def libc_ver(executable=sys.executable, lib='', version='', |
---|
148 | n/a | |
---|
149 | n/a | chunksize=16384): |
---|
150 | n/a | |
---|
151 | n/a | """ Tries to determine the libc version that the file executable |
---|
152 | n/a | (which defaults to the Python interpreter) is linked against. |
---|
153 | n/a | |
---|
154 | n/a | Returns a tuple of strings (lib,version) which default to the |
---|
155 | n/a | given parameters in case the lookup fails. |
---|
156 | n/a | |
---|
157 | n/a | Note that the function has intimate knowledge of how different |
---|
158 | n/a | libc versions add symbols to the executable and thus is probably |
---|
159 | n/a | only useable for executables compiled using gcc. |
---|
160 | n/a | |
---|
161 | n/a | The file is read and scanned in chunks of chunksize bytes. |
---|
162 | n/a | |
---|
163 | n/a | """ |
---|
164 | n/a | if hasattr(os.path, 'realpath'): |
---|
165 | n/a | # Python 2.2 introduced os.path.realpath(); it is used |
---|
166 | n/a | # here to work around problems with Cygwin not being |
---|
167 | n/a | # able to open symlinks for reading |
---|
168 | n/a | executable = os.path.realpath(executable) |
---|
169 | n/a | with open(executable, 'rb') as f: |
---|
170 | n/a | binary = f.read(chunksize) |
---|
171 | n/a | pos = 0 |
---|
172 | n/a | while 1: |
---|
173 | n/a | if b'libc' in binary or b'GLIBC' in binary: |
---|
174 | n/a | m = _libc_search.search(binary, pos) |
---|
175 | n/a | else: |
---|
176 | n/a | m = None |
---|
177 | n/a | if not m: |
---|
178 | n/a | binary = f.read(chunksize) |
---|
179 | n/a | if not binary: |
---|
180 | n/a | break |
---|
181 | n/a | pos = 0 |
---|
182 | n/a | continue |
---|
183 | n/a | libcinit, glibc, glibcversion, so, threads, soversion = [ |
---|
184 | n/a | s.decode('latin1') if s is not None else s |
---|
185 | n/a | for s in m.groups()] |
---|
186 | n/a | if libcinit and not lib: |
---|
187 | n/a | lib = 'libc' |
---|
188 | n/a | elif glibc: |
---|
189 | n/a | if lib != 'glibc': |
---|
190 | n/a | lib = 'glibc' |
---|
191 | n/a | version = glibcversion |
---|
192 | n/a | elif glibcversion > version: |
---|
193 | n/a | version = glibcversion |
---|
194 | n/a | elif so: |
---|
195 | n/a | if lib != 'glibc': |
---|
196 | n/a | lib = 'libc' |
---|
197 | n/a | if soversion and soversion > version: |
---|
198 | n/a | version = soversion |
---|
199 | n/a | if threads and version[-len(threads):] != threads: |
---|
200 | n/a | version = version + threads |
---|
201 | n/a | pos = m.end() |
---|
202 | n/a | return lib, version |
---|
203 | n/a | |
---|
204 | n/a | def _dist_try_harder(distname, version, id): |
---|
205 | n/a | |
---|
206 | n/a | """ Tries some special tricks to get the distribution |
---|
207 | n/a | information in case the default method fails. |
---|
208 | n/a | |
---|
209 | n/a | Currently supports older SuSE Linux, Caldera OpenLinux and |
---|
210 | n/a | Slackware Linux distributions. |
---|
211 | n/a | |
---|
212 | n/a | """ |
---|
213 | n/a | if os.path.exists('/var/adm/inst-log/info'): |
---|
214 | n/a | # SuSE Linux stores distribution information in that file |
---|
215 | n/a | distname = 'SuSE' |
---|
216 | n/a | for line in open('/var/adm/inst-log/info'): |
---|
217 | n/a | tv = line.split() |
---|
218 | n/a | if len(tv) == 2: |
---|
219 | n/a | tag, value = tv |
---|
220 | n/a | else: |
---|
221 | n/a | continue |
---|
222 | n/a | if tag == 'MIN_DIST_VERSION': |
---|
223 | n/a | version = value.strip() |
---|
224 | n/a | elif tag == 'DIST_IDENT': |
---|
225 | n/a | values = value.split('-') |
---|
226 | n/a | id = values[2] |
---|
227 | n/a | return distname, version, id |
---|
228 | n/a | |
---|
229 | n/a | if os.path.exists('/etc/.installed'): |
---|
230 | n/a | # Caldera OpenLinux has some infos in that file (thanks to Colin Kong) |
---|
231 | n/a | for line in open('/etc/.installed'): |
---|
232 | n/a | pkg = line.split('-') |
---|
233 | n/a | if len(pkg) >= 2 and pkg[0] == 'OpenLinux': |
---|
234 | n/a | # XXX does Caldera support non Intel platforms ? If yes, |
---|
235 | n/a | # where can we find the needed id ? |
---|
236 | n/a | return 'OpenLinux', pkg[1], id |
---|
237 | n/a | |
---|
238 | n/a | if os.path.isdir('/usr/lib/setup'): |
---|
239 | n/a | # Check for slackware version tag file (thanks to Greg Andruk) |
---|
240 | n/a | verfiles = os.listdir('/usr/lib/setup') |
---|
241 | n/a | for n in range(len(verfiles)-1, -1, -1): |
---|
242 | n/a | if verfiles[n][:14] != 'slack-version-': |
---|
243 | n/a | del verfiles[n] |
---|
244 | n/a | if verfiles: |
---|
245 | n/a | verfiles.sort() |
---|
246 | n/a | distname = 'slackware' |
---|
247 | n/a | version = verfiles[-1][14:] |
---|
248 | n/a | return distname, version, id |
---|
249 | n/a | |
---|
250 | n/a | return distname, version, id |
---|
251 | n/a | |
---|
252 | n/a | _release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII) |
---|
253 | n/a | _lsb_release_version = re.compile(r'(.+)' |
---|
254 | n/a | r' release ' |
---|
255 | n/a | r'([\d.]+)' |
---|
256 | n/a | r'[^(]*(?:\((.+)\))?', re.ASCII) |
---|
257 | n/a | _release_version = re.compile(r'([^0-9]+)' |
---|
258 | n/a | r'(?: release )?' |
---|
259 | n/a | r'([\d.]+)' |
---|
260 | n/a | r'[^(]*(?:\((.+)\))?', re.ASCII) |
---|
261 | n/a | |
---|
262 | n/a | # See also http://www.novell.com/coolsolutions/feature/11251.html |
---|
263 | n/a | # and http://linuxmafia.com/faq/Admin/release-files.html |
---|
264 | n/a | # and http://data.linux-ntfs.org/rpm/whichrpm |
---|
265 | n/a | # and http://www.die.net/doc/linux/man/man1/lsb_release.1.html |
---|
266 | n/a | |
---|
267 | n/a | _supported_dists = ( |
---|
268 | n/a | 'SuSE', 'debian', 'fedora', 'redhat', 'centos', |
---|
269 | n/a | 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo', |
---|
270 | n/a | 'UnitedLinux', 'turbolinux', 'arch', 'mageia') |
---|
271 | n/a | |
---|
272 | n/a | def _parse_release_file(firstline): |
---|
273 | n/a | |
---|
274 | n/a | # Default to empty 'version' and 'id' strings. Both defaults are used |
---|
275 | n/a | # when 'firstline' is empty. 'id' defaults to empty when an id can not |
---|
276 | n/a | # be deduced. |
---|
277 | n/a | version = '' |
---|
278 | n/a | id = '' |
---|
279 | n/a | |
---|
280 | n/a | # Parse the first line |
---|
281 | n/a | m = _lsb_release_version.match(firstline) |
---|
282 | n/a | if m is not None: |
---|
283 | n/a | # LSB format: "distro release x.x (codename)" |
---|
284 | n/a | return tuple(m.groups()) |
---|
285 | n/a | |
---|
286 | n/a | # Pre-LSB format: "distro x.x (codename)" |
---|
287 | n/a | m = _release_version.match(firstline) |
---|
288 | n/a | if m is not None: |
---|
289 | n/a | return tuple(m.groups()) |
---|
290 | n/a | |
---|
291 | n/a | # Unknown format... take the first two words |
---|
292 | n/a | l = firstline.strip().split() |
---|
293 | n/a | if l: |
---|
294 | n/a | version = l[0] |
---|
295 | n/a | if len(l) > 1: |
---|
296 | n/a | id = l[1] |
---|
297 | n/a | return '', version, id |
---|
298 | n/a | |
---|
299 | n/a | def linux_distribution(distname='', version='', id='', |
---|
300 | n/a | |
---|
301 | n/a | supported_dists=_supported_dists, |
---|
302 | n/a | full_distribution_name=1): |
---|
303 | n/a | import warnings |
---|
304 | n/a | warnings.warn("dist() and linux_distribution() functions are deprecated " |
---|
305 | n/a | "in Python 3.5", PendingDeprecationWarning, stacklevel=2) |
---|
306 | n/a | return _linux_distribution(distname, version, id, supported_dists, |
---|
307 | n/a | full_distribution_name) |
---|
308 | n/a | |
---|
309 | n/a | def _linux_distribution(distname, version, id, supported_dists, |
---|
310 | n/a | full_distribution_name): |
---|
311 | n/a | |
---|
312 | n/a | """ Tries to determine the name of the Linux OS distribution name. |
---|
313 | n/a | |
---|
314 | n/a | The function first looks for a distribution release file in |
---|
315 | n/a | /etc and then reverts to _dist_try_harder() in case no |
---|
316 | n/a | suitable files are found. |
---|
317 | n/a | |
---|
318 | n/a | supported_dists may be given to define the set of Linux |
---|
319 | n/a | distributions to look for. It defaults to a list of currently |
---|
320 | n/a | supported Linux distributions identified by their release file |
---|
321 | n/a | name. |
---|
322 | n/a | |
---|
323 | n/a | If full_distribution_name is true (default), the full |
---|
324 | n/a | distribution read from the OS is returned. Otherwise the short |
---|
325 | n/a | name taken from supported_dists is used. |
---|
326 | n/a | |
---|
327 | n/a | Returns a tuple (distname, version, id) which default to the |
---|
328 | n/a | args given as parameters. |
---|
329 | n/a | |
---|
330 | n/a | """ |
---|
331 | n/a | try: |
---|
332 | n/a | etc = os.listdir(_UNIXCONFDIR) |
---|
333 | n/a | except OSError: |
---|
334 | n/a | # Probably not a Unix system |
---|
335 | n/a | return distname, version, id |
---|
336 | n/a | etc.sort() |
---|
337 | n/a | for file in etc: |
---|
338 | n/a | m = _release_filename.match(file) |
---|
339 | n/a | if m is not None: |
---|
340 | n/a | _distname, dummy = m.groups() |
---|
341 | n/a | if _distname in supported_dists: |
---|
342 | n/a | distname = _distname |
---|
343 | n/a | break |
---|
344 | n/a | else: |
---|
345 | n/a | return _dist_try_harder(distname, version, id) |
---|
346 | n/a | |
---|
347 | n/a | # Read the first line |
---|
348 | n/a | with open(os.path.join(_UNIXCONFDIR, file), 'r', |
---|
349 | n/a | encoding='utf-8', errors='surrogateescape') as f: |
---|
350 | n/a | firstline = f.readline() |
---|
351 | n/a | _distname, _version, _id = _parse_release_file(firstline) |
---|
352 | n/a | |
---|
353 | n/a | if _distname and full_distribution_name: |
---|
354 | n/a | distname = _distname |
---|
355 | n/a | if _version: |
---|
356 | n/a | version = _version |
---|
357 | n/a | if _id: |
---|
358 | n/a | id = _id |
---|
359 | n/a | return distname, version, id |
---|
360 | n/a | |
---|
361 | n/a | # To maintain backwards compatibility: |
---|
362 | n/a | |
---|
363 | n/a | def dist(distname='', version='', id='', |
---|
364 | n/a | |
---|
365 | n/a | supported_dists=_supported_dists): |
---|
366 | n/a | |
---|
367 | n/a | """ Tries to determine the name of the Linux OS distribution name. |
---|
368 | n/a | |
---|
369 | n/a | The function first looks for a distribution release file in |
---|
370 | n/a | /etc and then reverts to _dist_try_harder() in case no |
---|
371 | n/a | suitable files are found. |
---|
372 | n/a | |
---|
373 | n/a | Returns a tuple (distname, version, id) which default to the |
---|
374 | n/a | args given as parameters. |
---|
375 | n/a | |
---|
376 | n/a | """ |
---|
377 | n/a | import warnings |
---|
378 | n/a | warnings.warn("dist() and linux_distribution() functions are deprecated " |
---|
379 | n/a | "in Python 3.5", PendingDeprecationWarning, stacklevel=2) |
---|
380 | n/a | return _linux_distribution(distname, version, id, |
---|
381 | n/a | supported_dists=supported_dists, |
---|
382 | n/a | full_distribution_name=0) |
---|
383 | n/a | |
---|
384 | n/a | def popen(cmd, mode='r', bufsize=-1): |
---|
385 | n/a | |
---|
386 | n/a | """ Portable popen() interface. |
---|
387 | n/a | """ |
---|
388 | n/a | import warnings |
---|
389 | n/a | warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2) |
---|
390 | n/a | return os.popen(cmd, mode, bufsize) |
---|
391 | n/a | |
---|
392 | n/a | def _norm_version(version, build=''): |
---|
393 | n/a | |
---|
394 | n/a | """ Normalize the version and build strings and return a single |
---|
395 | n/a | version string using the format major.minor.build (or patchlevel). |
---|
396 | n/a | """ |
---|
397 | n/a | l = version.split('.') |
---|
398 | n/a | if build: |
---|
399 | n/a | l.append(build) |
---|
400 | n/a | try: |
---|
401 | n/a | ints = map(int, l) |
---|
402 | n/a | except ValueError: |
---|
403 | n/a | strings = l |
---|
404 | n/a | else: |
---|
405 | n/a | strings = list(map(str, ints)) |
---|
406 | n/a | version = '.'.join(strings[:3]) |
---|
407 | n/a | return version |
---|
408 | n/a | |
---|
409 | n/a | _ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) ' |
---|
410 | n/a | r'.*' |
---|
411 | n/a | r'\[.* ([\d.]+)\])') |
---|
412 | n/a | |
---|
413 | n/a | # Examples of VER command output: |
---|
414 | n/a | # |
---|
415 | n/a | # Windows 2000: Microsoft Windows 2000 [Version 5.00.2195] |
---|
416 | n/a | # Windows XP: Microsoft Windows XP [Version 5.1.2600] |
---|
417 | n/a | # Windows Vista: Microsoft Windows [Version 6.0.6002] |
---|
418 | n/a | # |
---|
419 | n/a | # Note that the "Version" string gets localized on different |
---|
420 | n/a | # Windows versions. |
---|
421 | n/a | |
---|
422 | n/a | def _syscmd_ver(system='', release='', version='', |
---|
423 | n/a | |
---|
424 | n/a | supported_platforms=('win32', 'win16', 'dos')): |
---|
425 | n/a | |
---|
426 | n/a | """ Tries to figure out the OS version used and returns |
---|
427 | n/a | a tuple (system, release, version). |
---|
428 | n/a | |
---|
429 | n/a | It uses the "ver" shell command for this which is known |
---|
430 | n/a | to exists on Windows, DOS. XXX Others too ? |
---|
431 | n/a | |
---|
432 | n/a | In case this fails, the given parameters are used as |
---|
433 | n/a | defaults. |
---|
434 | n/a | |
---|
435 | n/a | """ |
---|
436 | n/a | if sys.platform not in supported_platforms: |
---|
437 | n/a | return system, release, version |
---|
438 | n/a | |
---|
439 | n/a | # Try some common cmd strings |
---|
440 | n/a | for cmd in ('ver', 'command /c ver', 'cmd /c ver'): |
---|
441 | n/a | try: |
---|
442 | n/a | pipe = os.popen(cmd) |
---|
443 | n/a | info = pipe.read() |
---|
444 | n/a | if pipe.close(): |
---|
445 | n/a | raise OSError('command failed') |
---|
446 | n/a | # XXX How can I suppress shell errors from being written |
---|
447 | n/a | # to stderr ? |
---|
448 | n/a | except OSError as why: |
---|
449 | n/a | #print 'Command %s failed: %s' % (cmd, why) |
---|
450 | n/a | continue |
---|
451 | n/a | else: |
---|
452 | n/a | break |
---|
453 | n/a | else: |
---|
454 | n/a | return system, release, version |
---|
455 | n/a | |
---|
456 | n/a | # Parse the output |
---|
457 | n/a | info = info.strip() |
---|
458 | n/a | m = _ver_output.match(info) |
---|
459 | n/a | if m is not None: |
---|
460 | n/a | system, release, version = m.groups() |
---|
461 | n/a | # Strip trailing dots from version and release |
---|
462 | n/a | if release[-1] == '.': |
---|
463 | n/a | release = release[:-1] |
---|
464 | n/a | if version[-1] == '.': |
---|
465 | n/a | version = version[:-1] |
---|
466 | n/a | # Normalize the version and build strings (eliminating additional |
---|
467 | n/a | # zeros) |
---|
468 | n/a | version = _norm_version(version) |
---|
469 | n/a | return system, release, version |
---|
470 | n/a | |
---|
471 | n/a | _WIN32_CLIENT_RELEASES = { |
---|
472 | n/a | (5, 0): "2000", |
---|
473 | n/a | (5, 1): "XP", |
---|
474 | n/a | # Strictly, 5.2 client is XP 64-bit, but platform.py historically |
---|
475 | n/a | # has always called it 2003 Server |
---|
476 | n/a | (5, 2): "2003Server", |
---|
477 | n/a | (5, None): "post2003", |
---|
478 | n/a | |
---|
479 | n/a | (6, 0): "Vista", |
---|
480 | n/a | (6, 1): "7", |
---|
481 | n/a | (6, 2): "8", |
---|
482 | n/a | (6, 3): "8.1", |
---|
483 | n/a | (6, None): "post8.1", |
---|
484 | n/a | |
---|
485 | n/a | (10, 0): "10", |
---|
486 | n/a | (10, None): "post10", |
---|
487 | n/a | } |
---|
488 | n/a | |
---|
489 | n/a | # Server release name lookup will default to client names if necessary |
---|
490 | n/a | _WIN32_SERVER_RELEASES = { |
---|
491 | n/a | (5, 2): "2003Server", |
---|
492 | n/a | |
---|
493 | n/a | (6, 0): "2008Server", |
---|
494 | n/a | (6, 1): "2008ServerR2", |
---|
495 | n/a | (6, 2): "2012Server", |
---|
496 | n/a | (6, 3): "2012ServerR2", |
---|
497 | n/a | (6, None): "post2012ServerR2", |
---|
498 | n/a | } |
---|
499 | n/a | |
---|
500 | n/a | def win32_ver(release='', version='', csd='', ptype=''): |
---|
501 | n/a | try: |
---|
502 | n/a | from sys import getwindowsversion |
---|
503 | n/a | except ImportError: |
---|
504 | n/a | return release, version, csd, ptype |
---|
505 | n/a | try: |
---|
506 | n/a | from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE |
---|
507 | n/a | except ImportError: |
---|
508 | n/a | from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE |
---|
509 | n/a | |
---|
510 | n/a | winver = getwindowsversion() |
---|
511 | n/a | maj, min, build = winver.platform_version or winver[:3] |
---|
512 | n/a | version = '{0}.{1}.{2}'.format(maj, min, build) |
---|
513 | n/a | |
---|
514 | n/a | release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or |
---|
515 | n/a | _WIN32_CLIENT_RELEASES.get((maj, None)) or |
---|
516 | n/a | release) |
---|
517 | n/a | |
---|
518 | n/a | # getwindowsversion() reflect the compatibility mode Python is |
---|
519 | n/a | # running under, and so the service pack value is only going to be |
---|
520 | n/a | # valid if the versions match. |
---|
521 | n/a | if winver[:2] == (maj, min): |
---|
522 | n/a | try: |
---|
523 | n/a | csd = 'SP{}'.format(winver.service_pack_major) |
---|
524 | n/a | except AttributeError: |
---|
525 | n/a | if csd[:13] == 'Service Pack ': |
---|
526 | n/a | csd = 'SP' + csd[13:] |
---|
527 | n/a | |
---|
528 | n/a | # VER_NT_SERVER = 3 |
---|
529 | n/a | if getattr(winver, 'product_type', None) == 3: |
---|
530 | n/a | release = (_WIN32_SERVER_RELEASES.get((maj, min)) or |
---|
531 | n/a | _WIN32_SERVER_RELEASES.get((maj, None)) or |
---|
532 | n/a | release) |
---|
533 | n/a | |
---|
534 | n/a | key = None |
---|
535 | n/a | try: |
---|
536 | n/a | key = OpenKeyEx(HKEY_LOCAL_MACHINE, |
---|
537 | n/a | r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') |
---|
538 | n/a | ptype = QueryValueEx(key, 'CurrentType')[0] |
---|
539 | n/a | except: |
---|
540 | n/a | pass |
---|
541 | n/a | finally: |
---|
542 | n/a | if key: |
---|
543 | n/a | CloseKey(key) |
---|
544 | n/a | |
---|
545 | n/a | return release, version, csd, ptype |
---|
546 | n/a | |
---|
547 | n/a | |
---|
548 | n/a | def _mac_ver_xml(): |
---|
549 | n/a | fn = '/System/Library/CoreServices/SystemVersion.plist' |
---|
550 | n/a | if not os.path.exists(fn): |
---|
551 | n/a | return None |
---|
552 | n/a | |
---|
553 | n/a | try: |
---|
554 | n/a | import plistlib |
---|
555 | n/a | except ImportError: |
---|
556 | n/a | return None |
---|
557 | n/a | |
---|
558 | n/a | with open(fn, 'rb') as f: |
---|
559 | n/a | pl = plistlib.load(f) |
---|
560 | n/a | release = pl['ProductVersion'] |
---|
561 | n/a | versioninfo = ('', '', '') |
---|
562 | n/a | machine = os.uname().machine |
---|
563 | n/a | if machine in ('ppc', 'Power Macintosh'): |
---|
564 | n/a | # Canonical name |
---|
565 | n/a | machine = 'PowerPC' |
---|
566 | n/a | |
---|
567 | n/a | return release, versioninfo, machine |
---|
568 | n/a | |
---|
569 | n/a | |
---|
570 | n/a | def mac_ver(release='', versioninfo=('', '', ''), machine=''): |
---|
571 | n/a | |
---|
572 | n/a | """ Get MacOS version information and return it as tuple (release, |
---|
573 | n/a | versioninfo, machine) with versioninfo being a tuple (version, |
---|
574 | n/a | dev_stage, non_release_version). |
---|
575 | n/a | |
---|
576 | n/a | Entries which cannot be determined are set to the parameter values |
---|
577 | n/a | which default to ''. All tuple entries are strings. |
---|
578 | n/a | """ |
---|
579 | n/a | |
---|
580 | n/a | # First try reading the information from an XML file which should |
---|
581 | n/a | # always be present |
---|
582 | n/a | info = _mac_ver_xml() |
---|
583 | n/a | if info is not None: |
---|
584 | n/a | return info |
---|
585 | n/a | |
---|
586 | n/a | # If that also doesn't work return the default values |
---|
587 | n/a | return release, versioninfo, machine |
---|
588 | n/a | |
---|
589 | n/a | def _java_getprop(name, default): |
---|
590 | n/a | |
---|
591 | n/a | from java.lang import System |
---|
592 | n/a | try: |
---|
593 | n/a | value = System.getProperty(name) |
---|
594 | n/a | if value is None: |
---|
595 | n/a | return default |
---|
596 | n/a | return value |
---|
597 | n/a | except AttributeError: |
---|
598 | n/a | return default |
---|
599 | n/a | |
---|
600 | n/a | def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')): |
---|
601 | n/a | |
---|
602 | n/a | """ Version interface for Jython. |
---|
603 | n/a | |
---|
604 | n/a | Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being |
---|
605 | n/a | a tuple (vm_name, vm_release, vm_vendor) and osinfo being a |
---|
606 | n/a | tuple (os_name, os_version, os_arch). |
---|
607 | n/a | |
---|
608 | n/a | Values which cannot be determined are set to the defaults |
---|
609 | n/a | given as parameters (which all default to ''). |
---|
610 | n/a | |
---|
611 | n/a | """ |
---|
612 | n/a | # Import the needed APIs |
---|
613 | n/a | try: |
---|
614 | n/a | import java.lang |
---|
615 | n/a | except ImportError: |
---|
616 | n/a | return release, vendor, vminfo, osinfo |
---|
617 | n/a | |
---|
618 | n/a | vendor = _java_getprop('java.vendor', vendor) |
---|
619 | n/a | release = _java_getprop('java.version', release) |
---|
620 | n/a | vm_name, vm_release, vm_vendor = vminfo |
---|
621 | n/a | vm_name = _java_getprop('java.vm.name', vm_name) |
---|
622 | n/a | vm_vendor = _java_getprop('java.vm.vendor', vm_vendor) |
---|
623 | n/a | vm_release = _java_getprop('java.vm.version', vm_release) |
---|
624 | n/a | vminfo = vm_name, vm_release, vm_vendor |
---|
625 | n/a | os_name, os_version, os_arch = osinfo |
---|
626 | n/a | os_arch = _java_getprop('java.os.arch', os_arch) |
---|
627 | n/a | os_name = _java_getprop('java.os.name', os_name) |
---|
628 | n/a | os_version = _java_getprop('java.os.version', os_version) |
---|
629 | n/a | osinfo = os_name, os_version, os_arch |
---|
630 | n/a | |
---|
631 | n/a | return release, vendor, vminfo, osinfo |
---|
632 | n/a | |
---|
633 | n/a | ### System name aliasing |
---|
634 | n/a | |
---|
635 | n/a | def system_alias(system, release, version): |
---|
636 | n/a | |
---|
637 | n/a | """ Returns (system, release, version) aliased to common |
---|
638 | n/a | marketing names used for some systems. |
---|
639 | n/a | |
---|
640 | n/a | It also does some reordering of the information in some cases |
---|
641 | n/a | where it would otherwise cause confusion. |
---|
642 | n/a | |
---|
643 | n/a | """ |
---|
644 | n/a | if system == 'Rhapsody': |
---|
645 | n/a | # Apple's BSD derivative |
---|
646 | n/a | # XXX How can we determine the marketing release number ? |
---|
647 | n/a | return 'MacOS X Server', system+release, version |
---|
648 | n/a | |
---|
649 | n/a | elif system == 'SunOS': |
---|
650 | n/a | # Sun's OS |
---|
651 | n/a | if release < '5': |
---|
652 | n/a | # These releases use the old name SunOS |
---|
653 | n/a | return system, release, version |
---|
654 | n/a | # Modify release (marketing release = SunOS release - 3) |
---|
655 | n/a | l = release.split('.') |
---|
656 | n/a | if l: |
---|
657 | n/a | try: |
---|
658 | n/a | major = int(l[0]) |
---|
659 | n/a | except ValueError: |
---|
660 | n/a | pass |
---|
661 | n/a | else: |
---|
662 | n/a | major = major - 3 |
---|
663 | n/a | l[0] = str(major) |
---|
664 | n/a | release = '.'.join(l) |
---|
665 | n/a | if release < '6': |
---|
666 | n/a | system = 'Solaris' |
---|
667 | n/a | else: |
---|
668 | n/a | # XXX Whatever the new SunOS marketing name is... |
---|
669 | n/a | system = 'Solaris' |
---|
670 | n/a | |
---|
671 | n/a | elif system == 'IRIX64': |
---|
672 | n/a | # IRIX reports IRIX64 on platforms with 64-bit support; yet it |
---|
673 | n/a | # is really a version and not a different platform, since 32-bit |
---|
674 | n/a | # apps are also supported.. |
---|
675 | n/a | system = 'IRIX' |
---|
676 | n/a | if version: |
---|
677 | n/a | version = version + ' (64bit)' |
---|
678 | n/a | else: |
---|
679 | n/a | version = '64bit' |
---|
680 | n/a | |
---|
681 | n/a | elif system in ('win32', 'win16'): |
---|
682 | n/a | # In case one of the other tricks |
---|
683 | n/a | system = 'Windows' |
---|
684 | n/a | |
---|
685 | n/a | return system, release, version |
---|
686 | n/a | |
---|
687 | n/a | ### Various internal helpers |
---|
688 | n/a | |
---|
689 | n/a | def _platform(*args): |
---|
690 | n/a | |
---|
691 | n/a | """ Helper to format the platform string in a filename |
---|
692 | n/a | compatible format e.g. "system-version-machine". |
---|
693 | n/a | """ |
---|
694 | n/a | # Format the platform string |
---|
695 | n/a | platform = '-'.join(x.strip() for x in filter(len, args)) |
---|
696 | n/a | |
---|
697 | n/a | # Cleanup some possible filename obstacles... |
---|
698 | n/a | platform = platform.replace(' ', '_') |
---|
699 | n/a | platform = platform.replace('/', '-') |
---|
700 | n/a | platform = platform.replace('\\', '-') |
---|
701 | n/a | platform = platform.replace(':', '-') |
---|
702 | n/a | platform = platform.replace(';', '-') |
---|
703 | n/a | platform = platform.replace('"', '-') |
---|
704 | n/a | platform = platform.replace('(', '-') |
---|
705 | n/a | platform = platform.replace(')', '-') |
---|
706 | n/a | |
---|
707 | n/a | # No need to report 'unknown' information... |
---|
708 | n/a | platform = platform.replace('unknown', '') |
---|
709 | n/a | |
---|
710 | n/a | # Fold '--'s and remove trailing '-' |
---|
711 | n/a | while 1: |
---|
712 | n/a | cleaned = platform.replace('--', '-') |
---|
713 | n/a | if cleaned == platform: |
---|
714 | n/a | break |
---|
715 | n/a | platform = cleaned |
---|
716 | n/a | while platform[-1] == '-': |
---|
717 | n/a | platform = platform[:-1] |
---|
718 | n/a | |
---|
719 | n/a | return platform |
---|
720 | n/a | |
---|
721 | n/a | def _node(default=''): |
---|
722 | n/a | |
---|
723 | n/a | """ Helper to determine the node name of this machine. |
---|
724 | n/a | """ |
---|
725 | n/a | try: |
---|
726 | n/a | import socket |
---|
727 | n/a | except ImportError: |
---|
728 | n/a | # No sockets... |
---|
729 | n/a | return default |
---|
730 | n/a | try: |
---|
731 | n/a | return socket.gethostname() |
---|
732 | n/a | except OSError: |
---|
733 | n/a | # Still not working... |
---|
734 | n/a | return default |
---|
735 | n/a | |
---|
736 | n/a | def _follow_symlinks(filepath): |
---|
737 | n/a | |
---|
738 | n/a | """ In case filepath is a symlink, follow it until a |
---|
739 | n/a | real file is reached. |
---|
740 | n/a | """ |
---|
741 | n/a | filepath = os.path.abspath(filepath) |
---|
742 | n/a | while os.path.islink(filepath): |
---|
743 | n/a | filepath = os.path.normpath( |
---|
744 | n/a | os.path.join(os.path.dirname(filepath), os.readlink(filepath))) |
---|
745 | n/a | return filepath |
---|
746 | n/a | |
---|
747 | n/a | def _syscmd_uname(option, default=''): |
---|
748 | n/a | |
---|
749 | n/a | """ Interface to the system's uname command. |
---|
750 | n/a | """ |
---|
751 | n/a | if sys.platform in ('dos', 'win32', 'win16'): |
---|
752 | n/a | # XXX Others too ? |
---|
753 | n/a | return default |
---|
754 | n/a | try: |
---|
755 | n/a | f = os.popen('uname %s 2> %s' % (option, DEV_NULL)) |
---|
756 | n/a | except (AttributeError, OSError): |
---|
757 | n/a | return default |
---|
758 | n/a | output = f.read().strip() |
---|
759 | n/a | rc = f.close() |
---|
760 | n/a | if not output or rc: |
---|
761 | n/a | return default |
---|
762 | n/a | else: |
---|
763 | n/a | return output |
---|
764 | n/a | |
---|
765 | n/a | def _syscmd_file(target, default=''): |
---|
766 | n/a | |
---|
767 | n/a | """ Interface to the system's file command. |
---|
768 | n/a | |
---|
769 | n/a | The function uses the -b option of the file command to have it |
---|
770 | n/a | omit the filename in its output. Follow the symlinks. It returns |
---|
771 | n/a | default in case the command should fail. |
---|
772 | n/a | |
---|
773 | n/a | """ |
---|
774 | n/a | if sys.platform in ('dos', 'win32', 'win16'): |
---|
775 | n/a | # XXX Others too ? |
---|
776 | n/a | return default |
---|
777 | n/a | target = _follow_symlinks(target) |
---|
778 | n/a | try: |
---|
779 | n/a | proc = subprocess.Popen(['file', target], |
---|
780 | n/a | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
---|
781 | n/a | |
---|
782 | n/a | except (AttributeError, OSError): |
---|
783 | n/a | return default |
---|
784 | n/a | output = proc.communicate()[0].decode('latin-1') |
---|
785 | n/a | rc = proc.wait() |
---|
786 | n/a | if not output or rc: |
---|
787 | n/a | return default |
---|
788 | n/a | else: |
---|
789 | n/a | return output |
---|
790 | n/a | |
---|
791 | n/a | ### Information about the used architecture |
---|
792 | n/a | |
---|
793 | n/a | # Default values for architecture; non-empty strings override the |
---|
794 | n/a | # defaults given as parameters |
---|
795 | n/a | _default_architecture = { |
---|
796 | n/a | 'win32': ('', 'WindowsPE'), |
---|
797 | n/a | 'win16': ('', 'Windows'), |
---|
798 | n/a | 'dos': ('', 'MSDOS'), |
---|
799 | n/a | } |
---|
800 | n/a | |
---|
801 | n/a | def architecture(executable=sys.executable, bits='', linkage=''): |
---|
802 | n/a | |
---|
803 | n/a | """ Queries the given executable (defaults to the Python interpreter |
---|
804 | n/a | binary) for various architecture information. |
---|
805 | n/a | |
---|
806 | n/a | Returns a tuple (bits, linkage) which contains information about |
---|
807 | n/a | the bit architecture and the linkage format used for the |
---|
808 | n/a | executable. Both values are returned as strings. |
---|
809 | n/a | |
---|
810 | n/a | Values that cannot be determined are returned as given by the |
---|
811 | n/a | parameter presets. If bits is given as '', the sizeof(pointer) |
---|
812 | n/a | (or sizeof(long) on Python version < 1.5.2) is used as |
---|
813 | n/a | indicator for the supported pointer size. |
---|
814 | n/a | |
---|
815 | n/a | The function relies on the system's "file" command to do the |
---|
816 | n/a | actual work. This is available on most if not all Unix |
---|
817 | n/a | platforms. On some non-Unix platforms where the "file" command |
---|
818 | n/a | does not exist and the executable is set to the Python interpreter |
---|
819 | n/a | binary defaults from _default_architecture are used. |
---|
820 | n/a | |
---|
821 | n/a | """ |
---|
822 | n/a | # Use the sizeof(pointer) as default number of bits if nothing |
---|
823 | n/a | # else is given as default. |
---|
824 | n/a | if not bits: |
---|
825 | n/a | import struct |
---|
826 | n/a | try: |
---|
827 | n/a | size = struct.calcsize('P') |
---|
828 | n/a | except struct.error: |
---|
829 | n/a | # Older installations can only query longs |
---|
830 | n/a | size = struct.calcsize('l') |
---|
831 | n/a | bits = str(size*8) + 'bit' |
---|
832 | n/a | |
---|
833 | n/a | # Get data from the 'file' system command |
---|
834 | n/a | if executable: |
---|
835 | n/a | fileout = _syscmd_file(executable, '') |
---|
836 | n/a | else: |
---|
837 | n/a | fileout = '' |
---|
838 | n/a | |
---|
839 | n/a | if not fileout and \ |
---|
840 | n/a | executable == sys.executable: |
---|
841 | n/a | # "file" command did not return anything; we'll try to provide |
---|
842 | n/a | # some sensible defaults then... |
---|
843 | n/a | if sys.platform in _default_architecture: |
---|
844 | n/a | b, l = _default_architecture[sys.platform] |
---|
845 | n/a | if b: |
---|
846 | n/a | bits = b |
---|
847 | n/a | if l: |
---|
848 | n/a | linkage = l |
---|
849 | n/a | return bits, linkage |
---|
850 | n/a | |
---|
851 | n/a | if 'executable' not in fileout: |
---|
852 | n/a | # Format not supported |
---|
853 | n/a | return bits, linkage |
---|
854 | n/a | |
---|
855 | n/a | # Bits |
---|
856 | n/a | if '32-bit' in fileout: |
---|
857 | n/a | bits = '32bit' |
---|
858 | n/a | elif 'N32' in fileout: |
---|
859 | n/a | # On Irix only |
---|
860 | n/a | bits = 'n32bit' |
---|
861 | n/a | elif '64-bit' in fileout: |
---|
862 | n/a | bits = '64bit' |
---|
863 | n/a | |
---|
864 | n/a | # Linkage |
---|
865 | n/a | if 'ELF' in fileout: |
---|
866 | n/a | linkage = 'ELF' |
---|
867 | n/a | elif 'PE' in fileout: |
---|
868 | n/a | # E.g. Windows uses this format |
---|
869 | n/a | if 'Windows' in fileout: |
---|
870 | n/a | linkage = 'WindowsPE' |
---|
871 | n/a | else: |
---|
872 | n/a | linkage = 'PE' |
---|
873 | n/a | elif 'COFF' in fileout: |
---|
874 | n/a | linkage = 'COFF' |
---|
875 | n/a | elif 'MS-DOS' in fileout: |
---|
876 | n/a | linkage = 'MSDOS' |
---|
877 | n/a | else: |
---|
878 | n/a | # XXX the A.OUT format also falls under this class... |
---|
879 | n/a | pass |
---|
880 | n/a | |
---|
881 | n/a | return bits, linkage |
---|
882 | n/a | |
---|
883 | n/a | ### Portable uname() interface |
---|
884 | n/a | |
---|
885 | n/a | uname_result = collections.namedtuple("uname_result", |
---|
886 | n/a | "system node release version machine processor") |
---|
887 | n/a | |
---|
888 | n/a | _uname_cache = None |
---|
889 | n/a | |
---|
890 | n/a | def uname(): |
---|
891 | n/a | |
---|
892 | n/a | """ Fairly portable uname interface. Returns a tuple |
---|
893 | n/a | of strings (system, node, release, version, machine, processor) |
---|
894 | n/a | identifying the underlying platform. |
---|
895 | n/a | |
---|
896 | n/a | Note that unlike the os.uname function this also returns |
---|
897 | n/a | possible processor information as an additional tuple entry. |
---|
898 | n/a | |
---|
899 | n/a | Entries which cannot be determined are set to ''. |
---|
900 | n/a | |
---|
901 | n/a | """ |
---|
902 | n/a | global _uname_cache |
---|
903 | n/a | no_os_uname = 0 |
---|
904 | n/a | |
---|
905 | n/a | if _uname_cache is not None: |
---|
906 | n/a | return _uname_cache |
---|
907 | n/a | |
---|
908 | n/a | processor = '' |
---|
909 | n/a | |
---|
910 | n/a | # Get some infos from the builtin os.uname API... |
---|
911 | n/a | try: |
---|
912 | n/a | system, node, release, version, machine = os.uname() |
---|
913 | n/a | except AttributeError: |
---|
914 | n/a | no_os_uname = 1 |
---|
915 | n/a | |
---|
916 | n/a | if no_os_uname or not list(filter(None, (system, node, release, version, machine))): |
---|
917 | n/a | # Hmm, no there is either no uname or uname has returned |
---|
918 | n/a | #'unknowns'... we'll have to poke around the system then. |
---|
919 | n/a | if no_os_uname: |
---|
920 | n/a | system = sys.platform |
---|
921 | n/a | release = '' |
---|
922 | n/a | version = '' |
---|
923 | n/a | node = _node() |
---|
924 | n/a | machine = '' |
---|
925 | n/a | |
---|
926 | n/a | use_syscmd_ver = 1 |
---|
927 | n/a | |
---|
928 | n/a | # Try win32_ver() on win32 platforms |
---|
929 | n/a | if system == 'win32': |
---|
930 | n/a | release, version, csd, ptype = win32_ver() |
---|
931 | n/a | if release and version: |
---|
932 | n/a | use_syscmd_ver = 0 |
---|
933 | n/a | # Try to use the PROCESSOR_* environment variables |
---|
934 | n/a | # available on Win XP and later; see |
---|
935 | n/a | # http://support.microsoft.com/kb/888731 and |
---|
936 | n/a | # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM |
---|
937 | n/a | if not machine: |
---|
938 | n/a | # WOW64 processes mask the native architecture |
---|
939 | n/a | if "PROCESSOR_ARCHITEW6432" in os.environ: |
---|
940 | n/a | machine = os.environ.get("PROCESSOR_ARCHITEW6432", '') |
---|
941 | n/a | else: |
---|
942 | n/a | machine = os.environ.get('PROCESSOR_ARCHITECTURE', '') |
---|
943 | n/a | if not processor: |
---|
944 | n/a | processor = os.environ.get('PROCESSOR_IDENTIFIER', machine) |
---|
945 | n/a | |
---|
946 | n/a | # Try the 'ver' system command available on some |
---|
947 | n/a | # platforms |
---|
948 | n/a | if use_syscmd_ver: |
---|
949 | n/a | system, release, version = _syscmd_ver(system) |
---|
950 | n/a | # Normalize system to what win32_ver() normally returns |
---|
951 | n/a | # (_syscmd_ver() tends to return the vendor name as well) |
---|
952 | n/a | if system == 'Microsoft Windows': |
---|
953 | n/a | system = 'Windows' |
---|
954 | n/a | elif system == 'Microsoft' and release == 'Windows': |
---|
955 | n/a | # Under Windows Vista and Windows Server 2008, |
---|
956 | n/a | # Microsoft changed the output of the ver command. The |
---|
957 | n/a | # release is no longer printed. This causes the |
---|
958 | n/a | # system and release to be misidentified. |
---|
959 | n/a | system = 'Windows' |
---|
960 | n/a | if '6.0' == version[:3]: |
---|
961 | n/a | release = 'Vista' |
---|
962 | n/a | else: |
---|
963 | n/a | release = '' |
---|
964 | n/a | |
---|
965 | n/a | # In case we still don't know anything useful, we'll try to |
---|
966 | n/a | # help ourselves |
---|
967 | n/a | if system in ('win32', 'win16'): |
---|
968 | n/a | if not version: |
---|
969 | n/a | if system == 'win32': |
---|
970 | n/a | version = '32bit' |
---|
971 | n/a | else: |
---|
972 | n/a | version = '16bit' |
---|
973 | n/a | system = 'Windows' |
---|
974 | n/a | |
---|
975 | n/a | elif system[:4] == 'java': |
---|
976 | n/a | release, vendor, vminfo, osinfo = java_ver() |
---|
977 | n/a | system = 'Java' |
---|
978 | n/a | version = ', '.join(vminfo) |
---|
979 | n/a | if not version: |
---|
980 | n/a | version = vendor |
---|
981 | n/a | |
---|
982 | n/a | # System specific extensions |
---|
983 | n/a | if system == 'OpenVMS': |
---|
984 | n/a | # OpenVMS seems to have release and version mixed up |
---|
985 | n/a | if not release or release == '0': |
---|
986 | n/a | release = version |
---|
987 | n/a | version = '' |
---|
988 | n/a | # Get processor information |
---|
989 | n/a | try: |
---|
990 | n/a | import vms_lib |
---|
991 | n/a | except ImportError: |
---|
992 | n/a | pass |
---|
993 | n/a | else: |
---|
994 | n/a | csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0) |
---|
995 | n/a | if (cpu_number >= 128): |
---|
996 | n/a | processor = 'Alpha' |
---|
997 | n/a | else: |
---|
998 | n/a | processor = 'VAX' |
---|
999 | n/a | if not processor: |
---|
1000 | n/a | # Get processor information from the uname system command |
---|
1001 | n/a | processor = _syscmd_uname('-p', '') |
---|
1002 | n/a | |
---|
1003 | n/a | #If any unknowns still exist, replace them with ''s, which are more portable |
---|
1004 | n/a | if system == 'unknown': |
---|
1005 | n/a | system = '' |
---|
1006 | n/a | if node == 'unknown': |
---|
1007 | n/a | node = '' |
---|
1008 | n/a | if release == 'unknown': |
---|
1009 | n/a | release = '' |
---|
1010 | n/a | if version == 'unknown': |
---|
1011 | n/a | version = '' |
---|
1012 | n/a | if machine == 'unknown': |
---|
1013 | n/a | machine = '' |
---|
1014 | n/a | if processor == 'unknown': |
---|
1015 | n/a | processor = '' |
---|
1016 | n/a | |
---|
1017 | n/a | # normalize name |
---|
1018 | n/a | if system == 'Microsoft' and release == 'Windows': |
---|
1019 | n/a | system = 'Windows' |
---|
1020 | n/a | release = 'Vista' |
---|
1021 | n/a | |
---|
1022 | n/a | _uname_cache = uname_result(system, node, release, version, |
---|
1023 | n/a | machine, processor) |
---|
1024 | n/a | return _uname_cache |
---|
1025 | n/a | |
---|
1026 | n/a | ### Direct interfaces to some of the uname() return values |
---|
1027 | n/a | |
---|
1028 | n/a | def system(): |
---|
1029 | n/a | |
---|
1030 | n/a | """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'. |
---|
1031 | n/a | |
---|
1032 | n/a | An empty string is returned if the value cannot be determined. |
---|
1033 | n/a | |
---|
1034 | n/a | """ |
---|
1035 | n/a | return uname().system |
---|
1036 | n/a | |
---|
1037 | n/a | def node(): |
---|
1038 | n/a | |
---|
1039 | n/a | """ Returns the computer's network name (which may not be fully |
---|
1040 | n/a | qualified) |
---|
1041 | n/a | |
---|
1042 | n/a | An empty string is returned if the value cannot be determined. |
---|
1043 | n/a | |
---|
1044 | n/a | """ |
---|
1045 | n/a | return uname().node |
---|
1046 | n/a | |
---|
1047 | n/a | def release(): |
---|
1048 | n/a | |
---|
1049 | n/a | """ Returns the system's release, e.g. '2.2.0' or 'NT' |
---|
1050 | n/a | |
---|
1051 | n/a | An empty string is returned if the value cannot be determined. |
---|
1052 | n/a | |
---|
1053 | n/a | """ |
---|
1054 | n/a | return uname().release |
---|
1055 | n/a | |
---|
1056 | n/a | def version(): |
---|
1057 | n/a | |
---|
1058 | n/a | """ Returns the system's release version, e.g. '#3 on degas' |
---|
1059 | n/a | |
---|
1060 | n/a | An empty string is returned if the value cannot be determined. |
---|
1061 | n/a | |
---|
1062 | n/a | """ |
---|
1063 | n/a | return uname().version |
---|
1064 | n/a | |
---|
1065 | n/a | def machine(): |
---|
1066 | n/a | |
---|
1067 | n/a | """ Returns the machine type, e.g. 'i386' |
---|
1068 | n/a | |
---|
1069 | n/a | An empty string is returned if the value cannot be determined. |
---|
1070 | n/a | |
---|
1071 | n/a | """ |
---|
1072 | n/a | return uname().machine |
---|
1073 | n/a | |
---|
1074 | n/a | def processor(): |
---|
1075 | n/a | |
---|
1076 | n/a | """ Returns the (true) processor name, e.g. 'amdk6' |
---|
1077 | n/a | |
---|
1078 | n/a | An empty string is returned if the value cannot be |
---|
1079 | n/a | determined. Note that many platforms do not provide this |
---|
1080 | n/a | information or simply return the same value as for machine(), |
---|
1081 | n/a | e.g. NetBSD does this. |
---|
1082 | n/a | |
---|
1083 | n/a | """ |
---|
1084 | n/a | return uname().processor |
---|
1085 | n/a | |
---|
1086 | n/a | ### Various APIs for extracting information from sys.version |
---|
1087 | n/a | |
---|
1088 | n/a | _sys_version_parser = re.compile( |
---|
1089 | n/a | r'([\w.+]+)\s*' # "version<space>" |
---|
1090 | n/a | r'\(#?([^,]+)' # "(#buildno" |
---|
1091 | n/a | r'(?:,\s*([\w ]*)' # ", builddate" |
---|
1092 | n/a | r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>" |
---|
1093 | n/a | r'\[([^\]]+)\]?', re.ASCII) # "[compiler]" |
---|
1094 | n/a | |
---|
1095 | n/a | _ironpython_sys_version_parser = re.compile( |
---|
1096 | n/a | r'IronPython\s*' |
---|
1097 | n/a | r'([\d\.]+)' |
---|
1098 | n/a | r'(?: \(([\d\.]+)\))?' |
---|
1099 | n/a | r' on (.NET [\d\.]+)', re.ASCII) |
---|
1100 | n/a | |
---|
1101 | n/a | # IronPython covering 2.6 and 2.7 |
---|
1102 | n/a | _ironpython26_sys_version_parser = re.compile( |
---|
1103 | n/a | r'([\d.]+)\s*' |
---|
1104 | n/a | r'\(IronPython\s*' |
---|
1105 | n/a | r'[\d.]+\s*' |
---|
1106 | n/a | r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)' |
---|
1107 | n/a | ) |
---|
1108 | n/a | |
---|
1109 | n/a | _pypy_sys_version_parser = re.compile( |
---|
1110 | n/a | r'([\w.+]+)\s*' |
---|
1111 | n/a | r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*' |
---|
1112 | n/a | r'\[PyPy [^\]]+\]?') |
---|
1113 | n/a | |
---|
1114 | n/a | _sys_version_cache = {} |
---|
1115 | n/a | |
---|
1116 | n/a | def _sys_version(sys_version=None): |
---|
1117 | n/a | |
---|
1118 | n/a | """ Returns a parsed version of Python's sys.version as tuple |
---|
1119 | n/a | (name, version, branch, revision, buildno, builddate, compiler) |
---|
1120 | n/a | referring to the Python implementation name, version, branch, |
---|
1121 | n/a | revision, build number, build date/time as string and the compiler |
---|
1122 | n/a | identification string. |
---|
1123 | n/a | |
---|
1124 | n/a | Note that unlike the Python sys.version, the returned value |
---|
1125 | n/a | for the Python version will always include the patchlevel (it |
---|
1126 | n/a | defaults to '.0'). |
---|
1127 | n/a | |
---|
1128 | n/a | The function returns empty strings for tuple entries that |
---|
1129 | n/a | cannot be determined. |
---|
1130 | n/a | |
---|
1131 | n/a | sys_version may be given to parse an alternative version |
---|
1132 | n/a | string, e.g. if the version was read from a different Python |
---|
1133 | n/a | interpreter. |
---|
1134 | n/a | |
---|
1135 | n/a | """ |
---|
1136 | n/a | # Get the Python version |
---|
1137 | n/a | if sys_version is None: |
---|
1138 | n/a | sys_version = sys.version |
---|
1139 | n/a | |
---|
1140 | n/a | # Try the cache first |
---|
1141 | n/a | result = _sys_version_cache.get(sys_version, None) |
---|
1142 | n/a | if result is not None: |
---|
1143 | n/a | return result |
---|
1144 | n/a | |
---|
1145 | n/a | # Parse it |
---|
1146 | n/a | if 'IronPython' in sys_version: |
---|
1147 | n/a | # IronPython |
---|
1148 | n/a | name = 'IronPython' |
---|
1149 | n/a | if sys_version.startswith('IronPython'): |
---|
1150 | n/a | match = _ironpython_sys_version_parser.match(sys_version) |
---|
1151 | n/a | else: |
---|
1152 | n/a | match = _ironpython26_sys_version_parser.match(sys_version) |
---|
1153 | n/a | |
---|
1154 | n/a | if match is None: |
---|
1155 | n/a | raise ValueError( |
---|
1156 | n/a | 'failed to parse IronPython sys.version: %s' % |
---|
1157 | n/a | repr(sys_version)) |
---|
1158 | n/a | |
---|
1159 | n/a | version, alt_version, compiler = match.groups() |
---|
1160 | n/a | buildno = '' |
---|
1161 | n/a | builddate = '' |
---|
1162 | n/a | |
---|
1163 | n/a | elif sys.platform.startswith('java'): |
---|
1164 | n/a | # Jython |
---|
1165 | n/a | name = 'Jython' |
---|
1166 | n/a | match = _sys_version_parser.match(sys_version) |
---|
1167 | n/a | if match is None: |
---|
1168 | n/a | raise ValueError( |
---|
1169 | n/a | 'failed to parse Jython sys.version: %s' % |
---|
1170 | n/a | repr(sys_version)) |
---|
1171 | n/a | version, buildno, builddate, buildtime, _ = match.groups() |
---|
1172 | n/a | if builddate is None: |
---|
1173 | n/a | builddate = '' |
---|
1174 | n/a | compiler = sys.platform |
---|
1175 | n/a | |
---|
1176 | n/a | elif "PyPy" in sys_version: |
---|
1177 | n/a | # PyPy |
---|
1178 | n/a | name = "PyPy" |
---|
1179 | n/a | match = _pypy_sys_version_parser.match(sys_version) |
---|
1180 | n/a | if match is None: |
---|
1181 | n/a | raise ValueError("failed to parse PyPy sys.version: %s" % |
---|
1182 | n/a | repr(sys_version)) |
---|
1183 | n/a | version, buildno, builddate, buildtime = match.groups() |
---|
1184 | n/a | compiler = "" |
---|
1185 | n/a | |
---|
1186 | n/a | else: |
---|
1187 | n/a | # CPython |
---|
1188 | n/a | match = _sys_version_parser.match(sys_version) |
---|
1189 | n/a | if match is None: |
---|
1190 | n/a | raise ValueError( |
---|
1191 | n/a | 'failed to parse CPython sys.version: %s' % |
---|
1192 | n/a | repr(sys_version)) |
---|
1193 | n/a | version, buildno, builddate, buildtime, compiler = \ |
---|
1194 | n/a | match.groups() |
---|
1195 | n/a | name = 'CPython' |
---|
1196 | n/a | if builddate is None: |
---|
1197 | n/a | builddate = '' |
---|
1198 | n/a | elif buildtime: |
---|
1199 | n/a | builddate = builddate + ' ' + buildtime |
---|
1200 | n/a | |
---|
1201 | n/a | if hasattr(sys, '_mercurial'): |
---|
1202 | n/a | _, branch, revision = sys._mercurial |
---|
1203 | n/a | elif hasattr(sys, 'subversion'): |
---|
1204 | n/a | # sys.subversion was added in Python 2.5 |
---|
1205 | n/a | _, branch, revision = sys.subversion |
---|
1206 | n/a | else: |
---|
1207 | n/a | branch = '' |
---|
1208 | n/a | revision = '' |
---|
1209 | n/a | |
---|
1210 | n/a | # Add the patchlevel version if missing |
---|
1211 | n/a | l = version.split('.') |
---|
1212 | n/a | if len(l) == 2: |
---|
1213 | n/a | l.append('0') |
---|
1214 | n/a | version = '.'.join(l) |
---|
1215 | n/a | |
---|
1216 | n/a | # Build and cache the result |
---|
1217 | n/a | result = (name, version, branch, revision, buildno, builddate, compiler) |
---|
1218 | n/a | _sys_version_cache[sys_version] = result |
---|
1219 | n/a | return result |
---|
1220 | n/a | |
---|
1221 | n/a | def python_implementation(): |
---|
1222 | n/a | |
---|
1223 | n/a | """ Returns a string identifying the Python implementation. |
---|
1224 | n/a | |
---|
1225 | n/a | Currently, the following implementations are identified: |
---|
1226 | n/a | 'CPython' (C implementation of Python), |
---|
1227 | n/a | 'IronPython' (.NET implementation of Python), |
---|
1228 | n/a | 'Jython' (Java implementation of Python), |
---|
1229 | n/a | 'PyPy' (Python implementation of Python). |
---|
1230 | n/a | |
---|
1231 | n/a | """ |
---|
1232 | n/a | return _sys_version()[0] |
---|
1233 | n/a | |
---|
1234 | n/a | def python_version(): |
---|
1235 | n/a | |
---|
1236 | n/a | """ Returns the Python version as string 'major.minor.patchlevel' |
---|
1237 | n/a | |
---|
1238 | n/a | Note that unlike the Python sys.version, the returned value |
---|
1239 | n/a | will always include the patchlevel (it defaults to 0). |
---|
1240 | n/a | |
---|
1241 | n/a | """ |
---|
1242 | n/a | return _sys_version()[1] |
---|
1243 | n/a | |
---|
1244 | n/a | def python_version_tuple(): |
---|
1245 | n/a | |
---|
1246 | n/a | """ Returns the Python version as tuple (major, minor, patchlevel) |
---|
1247 | n/a | of strings. |
---|
1248 | n/a | |
---|
1249 | n/a | Note that unlike the Python sys.version, the returned value |
---|
1250 | n/a | will always include the patchlevel (it defaults to 0). |
---|
1251 | n/a | |
---|
1252 | n/a | """ |
---|
1253 | n/a | return tuple(_sys_version()[1].split('.')) |
---|
1254 | n/a | |
---|
1255 | n/a | def python_branch(): |
---|
1256 | n/a | |
---|
1257 | n/a | """ Returns a string identifying the Python implementation |
---|
1258 | n/a | branch. |
---|
1259 | n/a | |
---|
1260 | n/a | For CPython this is the Subversion branch from which the |
---|
1261 | n/a | Python binary was built. |
---|
1262 | n/a | |
---|
1263 | n/a | If not available, an empty string is returned. |
---|
1264 | n/a | |
---|
1265 | n/a | """ |
---|
1266 | n/a | |
---|
1267 | n/a | return _sys_version()[2] |
---|
1268 | n/a | |
---|
1269 | n/a | def python_revision(): |
---|
1270 | n/a | |
---|
1271 | n/a | """ Returns a string identifying the Python implementation |
---|
1272 | n/a | revision. |
---|
1273 | n/a | |
---|
1274 | n/a | For CPython this is the Subversion revision from which the |
---|
1275 | n/a | Python binary was built. |
---|
1276 | n/a | |
---|
1277 | n/a | If not available, an empty string is returned. |
---|
1278 | n/a | |
---|
1279 | n/a | """ |
---|
1280 | n/a | return _sys_version()[3] |
---|
1281 | n/a | |
---|
1282 | n/a | def python_build(): |
---|
1283 | n/a | |
---|
1284 | n/a | """ Returns a tuple (buildno, builddate) stating the Python |
---|
1285 | n/a | build number and date as strings. |
---|
1286 | n/a | |
---|
1287 | n/a | """ |
---|
1288 | n/a | return _sys_version()[4:6] |
---|
1289 | n/a | |
---|
1290 | n/a | def python_compiler(): |
---|
1291 | n/a | |
---|
1292 | n/a | """ Returns a string identifying the compiler used for compiling |
---|
1293 | n/a | Python. |
---|
1294 | n/a | |
---|
1295 | n/a | """ |
---|
1296 | n/a | return _sys_version()[6] |
---|
1297 | n/a | |
---|
1298 | n/a | ### The Opus Magnum of platform strings :-) |
---|
1299 | n/a | |
---|
1300 | n/a | _platform_cache = {} |
---|
1301 | n/a | |
---|
1302 | n/a | def platform(aliased=0, terse=0): |
---|
1303 | n/a | |
---|
1304 | n/a | """ Returns a single string identifying the underlying platform |
---|
1305 | n/a | with as much useful information as possible (but no more :). |
---|
1306 | n/a | |
---|
1307 | n/a | The output is intended to be human readable rather than |
---|
1308 | n/a | machine parseable. It may look different on different |
---|
1309 | n/a | platforms and this is intended. |
---|
1310 | n/a | |
---|
1311 | n/a | If "aliased" is true, the function will use aliases for |
---|
1312 | n/a | various platforms that report system names which differ from |
---|
1313 | n/a | their common names, e.g. SunOS will be reported as |
---|
1314 | n/a | Solaris. The system_alias() function is used to implement |
---|
1315 | n/a | this. |
---|
1316 | n/a | |
---|
1317 | n/a | Setting terse to true causes the function to return only the |
---|
1318 | n/a | absolute minimum information needed to identify the platform. |
---|
1319 | n/a | |
---|
1320 | n/a | """ |
---|
1321 | n/a | result = _platform_cache.get((aliased, terse), None) |
---|
1322 | n/a | if result is not None: |
---|
1323 | n/a | return result |
---|
1324 | n/a | |
---|
1325 | n/a | # Get uname information and then apply platform specific cosmetics |
---|
1326 | n/a | # to it... |
---|
1327 | n/a | system, node, release, version, machine, processor = uname() |
---|
1328 | n/a | if machine == processor: |
---|
1329 | n/a | processor = '' |
---|
1330 | n/a | if aliased: |
---|
1331 | n/a | system, release, version = system_alias(system, release, version) |
---|
1332 | n/a | |
---|
1333 | n/a | if system == 'Windows': |
---|
1334 | n/a | # MS platforms |
---|
1335 | n/a | rel, vers, csd, ptype = win32_ver(version) |
---|
1336 | n/a | if terse: |
---|
1337 | n/a | platform = _platform(system, release) |
---|
1338 | n/a | else: |
---|
1339 | n/a | platform = _platform(system, release, version, csd) |
---|
1340 | n/a | |
---|
1341 | n/a | elif system in ('Linux',): |
---|
1342 | n/a | # Linux based systems |
---|
1343 | n/a | with warnings.catch_warnings(): |
---|
1344 | n/a | # see issue #1322 for more information |
---|
1345 | n/a | warnings.filterwarnings( |
---|
1346 | n/a | 'ignore', |
---|
1347 | n/a | r'dist\(\) and linux_distribution\(\) ' |
---|
1348 | n/a | 'functions are deprecated .*', |
---|
1349 | n/a | PendingDeprecationWarning, |
---|
1350 | n/a | ) |
---|
1351 | n/a | distname, distversion, distid = dist('') |
---|
1352 | n/a | if distname and not terse: |
---|
1353 | n/a | platform = _platform(system, release, machine, processor, |
---|
1354 | n/a | 'with', |
---|
1355 | n/a | distname, distversion, distid) |
---|
1356 | n/a | else: |
---|
1357 | n/a | # If the distribution name is unknown check for libc vs. glibc |
---|
1358 | n/a | libcname, libcversion = libc_ver(sys.executable) |
---|
1359 | n/a | platform = _platform(system, release, machine, processor, |
---|
1360 | n/a | 'with', |
---|
1361 | n/a | libcname+libcversion) |
---|
1362 | n/a | elif system == 'Java': |
---|
1363 | n/a | # Java platforms |
---|
1364 | n/a | r, v, vminfo, (os_name, os_version, os_arch) = java_ver() |
---|
1365 | n/a | if terse or not os_name: |
---|
1366 | n/a | platform = _platform(system, release, version) |
---|
1367 | n/a | else: |
---|
1368 | n/a | platform = _platform(system, release, version, |
---|
1369 | n/a | 'on', |
---|
1370 | n/a | os_name, os_version, os_arch) |
---|
1371 | n/a | |
---|
1372 | n/a | elif system == 'MacOS': |
---|
1373 | n/a | # MacOS platforms |
---|
1374 | n/a | if terse: |
---|
1375 | n/a | platform = _platform(system, release) |
---|
1376 | n/a | else: |
---|
1377 | n/a | platform = _platform(system, release, machine) |
---|
1378 | n/a | |
---|
1379 | n/a | else: |
---|
1380 | n/a | # Generic handler |
---|
1381 | n/a | if terse: |
---|
1382 | n/a | platform = _platform(system, release) |
---|
1383 | n/a | else: |
---|
1384 | n/a | bits, linkage = architecture(sys.executable) |
---|
1385 | n/a | platform = _platform(system, release, machine, |
---|
1386 | n/a | processor, bits, linkage) |
---|
1387 | n/a | |
---|
1388 | n/a | _platform_cache[(aliased, terse)] = platform |
---|
1389 | n/a | return platform |
---|
1390 | n/a | |
---|
1391 | n/a | ### Command line interface |
---|
1392 | n/a | |
---|
1393 | n/a | if __name__ == '__main__': |
---|
1394 | n/a | # Default is to print the aliased verbose platform string |
---|
1395 | n/a | terse = ('terse' in sys.argv or '--terse' in sys.argv) |
---|
1396 | n/a | aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv) |
---|
1397 | n/a | print(platform(aliased, terse)) |
---|
1398 | n/a | sys.exit(0) |
---|