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