3 """ This module tries to retrieve as much platform-identifying data as
4 possible. It makes this information available via function APIs.
6 If called from the command line, it prints the platform
7 information concatenated as single string to stdout. The output
8 format is useable as part of a filename.
11 # This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
12 # If you find problems, please submit bug reports/patches via the
13 # Python SourceForge Project Page and assign them to "lemburg".
15 # Note: Please keep this module compatible to Python 1.5.2.
18 # * more support for WinCE
19 # * support for MS-DOS (PythonDX ?)
20 # * support for Amiga and other still unsupported platforms running Python
21 # * support for additional Linux distributions
23 # Many thanks to all those who helped adding platform-specific
24 # checks (in no particular order):
26 # Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
27 # Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
28 # Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
29 # Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
30 # Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
31 # Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
35 # <see CVS and SVN checkin messages for history>
37 # 1.0.6 - added linux_distribution()
38 # 1.0.5 - fixed Java support to allow running the module on Jython
39 # 1.0.4 - added IronPython support
40 # 1.0.3 - added normalization of Windows system name
41 # 1.0.2 - added more Windows support
42 # 1.0.1 - reformatted to make doc.py happy
43 # 1.0.0 - reformatted a bit and checked into Python CVS
44 # 0.8.0 - added sys.version parser and various new access
45 # APIs (python_version(), python_compiler(), etc.)
46 # 0.7.2 - fixed architecture() to use sizeof(pointer) where available
47 # 0.7.1 - added support for Caldera OpenLinux
48 # 0.7.0 - some fixes for WinCE; untabified the source file
49 # 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
50 # vms_lib.getsyi() configured
51 # 0.6.1 - added code to prevent 'uname -p' on platforms which are
52 # known not to support it
53 # 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
54 # did some cleanup of the interfaces - some APIs have changed
55 # 0.5.5 - fixed another type in the MacOS code... should have
56 # used more coffee today ;-)
57 # 0.5.4 - fixed a few typos in the MacOS code
58 # 0.5.3 - added experimental MacOS support; added better popen()
59 # workarounds in _syscmd_ver() -- still not 100% elegant
61 # 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
62 # return values (the system uname command tends to return
63 # 'unknown' instead of just leaving the field emtpy)
64 # 0.5.1 - included code for slackware dist; added exception handlers
65 # to cover up situations where platforms don't have os.popen
66 # (e.g. Mac) or fail on socket.gethostname(); fixed libc
68 # 0.5.0 - changed the API names referring to system commands to *syscmd*;
69 # added java_ver(); made syscmd_ver() a private
70 # API (was system_ver() in previous versions) -- use uname()
71 # instead; extended the win32_ver() to also return processor
73 # 0.4.0 - added win32_ver() and modified the platform() output for WinXX
74 # 0.3.4 - fixed a bug in _follow_symlinks()
75 # 0.3.3 - fixed popen() and "file" command invokation bugs
76 # 0.3.2 - added architecture() API and support for it in platform()
77 # 0.3.1 - fixed syscmd_ver() RE to support Windows NT
78 # 0.3.0 - added system alias support
79 # 0.2.3 - removed 'wince' again... oh well.
80 # 0.2.2 - added 'wince' to syscmd_ver() supported platforms
81 # 0.2.1 - added cache logic and changed the platform string format
82 # 0.2.0 - changed the API to use functions instead of module globals
83 # since some action take too long to be run on module import
84 # 0.1.0 - first release
86 # You can always get the latest version of this module at:
88 # http://www.egenix.com/files/python/platform.py
90 # If that URL should fail, try contacting the author.
93 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
94 Copyright (c) 2000-2008, eGenix.com Software GmbH; mailto:info@egenix.com
96 Permission to use, copy, modify, and distribute this software and its
97 documentation for any purpose and without fee or royalty is hereby granted,
98 provided that the above copyright notice appear in all copies and that
99 both that copyright notice and this permission notice appear in
100 supporting documentation or portions thereof, including modifications,
103 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
104 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
105 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
106 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
107 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
108 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
109 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
113 __version__
= '1.0.6'
115 import sys
,string
,os
,re
117 ### Platform specific APIs
119 _libc_search
= re
.compile(r
'(__libc_init)'
123 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
125 def libc_ver(executable
=sys
.executable
,lib
='',version
='',
129 """ Tries to determine the libc version that the file executable
130 (which defaults to the Python interpreter) is linked against.
132 Returns a tuple of strings (lib,version) which default to the
133 given parameters in case the lookup fails.
135 Note that the function has intimate knowledge of how different
136 libc versions add symbols to the executable and thus is probably
137 only useable for executables compiled using gcc.
139 The file is read and scanned in chunks of chunksize bytes.
142 if hasattr(os
.path
, 'realpath'):
143 # Python 2.2 introduced os.path.realpath(); it is used
144 # here to work around problems with Cygwin not being
145 # able to open symlinks for reading
146 executable
= os
.path
.realpath(executable
)
147 f
= open(executable
,'rb')
148 binary
= f
.read(chunksize
)
151 m
= _libc_search
.search(binary
,pos
)
153 binary
= f
.read(chunksize
)
158 libcinit
,glibc
,glibcversion
,so
,threads
,soversion
= m
.groups()
159 if libcinit
and not lib
:
164 version
= glibcversion
165 elif glibcversion
> version
:
166 version
= glibcversion
170 if soversion
> version
:
172 if threads
and version
[-len(threads
):] != threads
:
173 version
= version
+ threads
178 def _dist_try_harder(distname
,version
,id):
180 """ Tries some special tricks to get the distribution
181 information in case the default method fails.
183 Currently supports older SuSE Linux, Caldera OpenLinux and
184 Slackware Linux distributions.
187 if os
.path
.exists('/var/adm/inst-log/info'):
188 # SuSE Linux stores distribution information in that file
189 info
= open('/var/adm/inst-log/info').readlines()
192 tv
= string
.split(line
)
197 if tag
== 'MIN_DIST_VERSION':
198 version
= string
.strip(value
)
199 elif tag
== 'DIST_IDENT':
200 values
= string
.split(value
,'-')
202 return distname
,version
,id
204 if os
.path
.exists('/etc/.installed'):
205 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
206 info
= open('/etc/.installed').readlines()
208 pkg
= string
.split(line
,'-')
209 if len(pkg
) >= 2 and pkg
[0] == 'OpenLinux':
210 # XXX does Caldera support non Intel platforms ? If yes,
211 # where can we find the needed id ?
212 return 'OpenLinux',pkg
[1],id
214 if os
.path
.isdir('/usr/lib/setup'):
215 # Check for slackware verson tag file (thanks to Greg Andruk)
216 verfiles
= os
.listdir('/usr/lib/setup')
217 for n
in range(len(verfiles
)-1, -1, -1):
218 if verfiles
[n
][:14] != 'slack-version-':
222 distname
= 'slackware'
223 version
= verfiles
[-1][14:]
224 return distname
,version
,id
226 return distname
,version
,id
228 _release_filename
= re
.compile(r
'(\w+)[-_](release|version)')
229 _lsb_release_version
= re
.compile(r
'(.+)'
232 '[^(]*(?:\((.+)\))?')
233 _release_version
= re
.compile(r
'([^0-9]+)'
236 '[^(]*(?:\((.+)\))?')
238 # See also http://www.novell.com/coolsolutions/feature/11251.html
239 # and http://linuxmafia.com/faq/Admin/release-files.html
240 # and http://data.linux-ntfs.org/rpm/whichrpm
241 # and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
244 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
245 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
246 'UnitedLinux', 'turbolinux')
248 def _parse_release_file(firstline
):
250 # Parse the first line
251 m
= _lsb_release_version
.match(firstline
)
253 # LSB format: "distro release x.x (codename)"
254 return tuple(m
.groups())
256 # Pre-LSB format: "distro x.x (codename)"
257 m
= _release_version
.match(firstline
)
259 return tuple(m
.groups())
261 # Unkown format... take the first two words
262 l
= string
.split(string
.strip(firstline
))
269 return '', version
, id
271 def linux_distribution(distname
='', version
='', id='',
273 supported_dists
=_supported_dists
,
274 full_distribution_name
=1):
276 """ Tries to determine the name of the Linux OS distribution name.
278 The function first looks for a distribution release file in
279 /etc and then reverts to _dist_try_harder() in case no
280 suitable files are found.
282 supported_dists may be given to define the set of Linux
283 distributions to look for. It defaults to a list of currently
284 supported Linux distributions identified by their release file
287 If full_distribution_name is true (default), the full
288 distribution read from the OS is returned. Otherwise the short
289 name taken from supported_dists is used.
291 Returns a tuple (distname,version,id) which default to the
292 args given as parameters.
296 etc
= os
.listdir('/etc')
298 # Probably not a Unix system
299 return distname
,version
,id
302 m
= _release_filename
.match(file)
304 _distname
,dummy
= m
.groups()
305 if _distname
in supported_dists
:
309 return _dist_try_harder(distname
,version
,id)
311 # Read the first line
312 f
= open('/etc/'+file, 'r')
313 firstline
= f
.readline()
315 _distname
, _version
, _id
= _parse_release_file(firstline
)
317 if _distname
and full_distribution_name
:
323 return distname
, version
, id
325 # To maintain backwards compatibility:
327 def dist(distname
='',version
='',id='',
329 supported_dists
=_supported_dists
):
331 """ Tries to determine the name of the Linux OS distribution name.
333 The function first looks for a distribution release file in
334 /etc and then reverts to _dist_try_harder() in case no
335 suitable files are found.
337 Returns a tuple (distname,version,id) which default to the
338 args given as parameters.
341 return linux_distribution(distname
, version
, id,
342 supported_dists
=supported_dists
,
343 full_distribution_name
=0)
347 """ Fairly portable (alternative) popen implementation.
349 This is mostly needed in case os.popen() is not available, or
350 doesn't work as advertised, e.g. in Win9X GUI programs like
353 Writing to the pipe is currently not supported.
361 def __init__(self
,cmd
,mode
='r',bufsize
=None):
364 raise ValueError,'popen()-emulation only supports read mode'
366 self
.tmpfile
= tmpfile
= tempfile
.mktemp()
367 os
.system(cmd
+ ' > %s' % tmpfile
)
368 self
.pipe
= open(tmpfile
,'rb')
369 self
.bufsize
= bufsize
374 return self
.pipe
.read()
378 if self
.bufsize
is not None:
379 return self
.pipe
.readlines()
383 remove
=os
.unlink
,error
=os
.error
):
386 rc
= self
.pipe
.close()
399 def popen(cmd
, mode
='r', bufsize
=None):
401 """ Portable popen() interface.
403 # Find a working popen implementation preferring win32pipe.popen
404 # over os.popen over _popen
406 if os
.environ
.get('OS','') == 'Windows_NT':
407 # On NT win32pipe should work; on Win9x it hangs due to bugs
408 # in the MS C lib (see MS KnowledgeBase article Q150956)
414 popen
= win32pipe
.popen
416 if hasattr(os
,'popen'):
418 # Check whether it works... it doesn't in GUI programs
419 # on Windows platforms
420 if sys
.platform
== 'win32': # XXX Others too ?
428 return popen(cmd
,mode
)
430 return popen(cmd
,mode
,bufsize
)
432 def _norm_version(version
, build
=''):
434 """ Normalize the version and build strings and return a single
435 version string using the format major.minor.build (or patchlevel).
437 l
= string
.split(version
,'.')
445 strings
= map(str,ints
)
446 version
= string
.join(strings
[:3],'.')
449 _ver_output
= re
.compile(r
'(?:([\w ]+) ([\w.]+) '
453 def _syscmd_ver(system
='', release
='', version
='',
455 supported_platforms
=('win32','win16','dos','os2')):
457 """ Tries to figure out the OS version used and returns
458 a tuple (system,release,version).
460 It uses the "ver" shell command for this which is known
461 to exists on Windows, DOS and OS/2. XXX Others too ?
463 In case this fails, the given parameters are used as
467 if sys
.platform
not in supported_platforms
:
468 return system
,release
,version
470 # Try some common cmd strings
471 for cmd
in ('ver','command /c ver','cmd /c ver'):
476 raise os
.error
,'command failed'
477 # XXX How can I supress shell errors from being written
480 #print 'Command %s failed: %s' % (cmd,why)
483 #print 'Command %s failed: %s' % (cmd,why)
488 return system
,release
,version
491 info
= string
.strip(info
)
492 m
= _ver_output
.match(info
)
494 system
,release
,version
= m
.groups()
495 # Strip trailing dots from version and release
496 if release
[-1] == '.':
497 release
= release
[:-1]
498 if version
[-1] == '.':
499 version
= version
[:-1]
500 # Normalize the version and build strings (eliminating additional
502 version
= _norm_version(version
)
503 return system
,release
,version
505 def _win32_getvalue(key
,name
,default
=''):
507 """ Read a value for name from the registry key.
509 In case this fails, default is returned.
513 # Use win32api if available
514 from win32api
import RegQueryValueEx
516 # On Python 2.0 and later, emulate using _winreg
518 RegQueryValueEx
= _winreg
.QueryValueEx
520 return RegQueryValueEx(key
,name
)
524 def win32_ver(release
='',version
='',csd
='',ptype
=''):
526 """ Get additional version information from the Windows Registry
527 and return a tuple (version,csd,ptype) referring to version
528 number, CSD level and OS type (multi/single
531 As a hint: ptype returns 'Uniprocessor Free' on single
532 processor NT machines and 'Multiprocessor Free' on multi
533 processor machines. The 'Free' refers to the OS version being
534 free of debugging code. It could also state 'Checked' which
535 means the OS version uses debugging code, i.e. code that
536 checks arguments, ranges, etc. (Thomas Heller).
538 Note: this function works best with Mark Hammond's win32
539 package installed, but also on Python 2.3 and later. It
540 obviously only runs on Win32 compatible platforms.
543 # XXX Is there any way to find out the processor type on WinXX ?
544 # XXX Is win32 available on Windows CE ?
546 # Adapted from code posted by Karl Putland to comp.lang.python.
548 # The mappings between reg. values and release names can be found
549 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
551 # Import the needed APIs
554 from win32api
import RegQueryValueEx
, RegOpenKeyEx
, \
555 RegCloseKey
, GetVersionEx
556 from win32con
import HKEY_LOCAL_MACHINE
, VER_PLATFORM_WIN32_NT
, \
557 VER_PLATFORM_WIN32_WINDOWS
, VER_NT_WORKSTATION
559 # Emulate the win32api module using Python APIs
561 sys
.getwindowsversion
562 except AttributeError:
563 # No emulation possible, so return the defaults...
564 return release
,version
,csd
,ptype
566 # Emulation using _winreg (added in Python 2.0) and
567 # sys.getwindowsversion() (added in Python 2.3)
569 GetVersionEx
= sys
.getwindowsversion
570 RegQueryValueEx
= _winreg
.QueryValueEx
571 RegOpenKeyEx
= _winreg
.OpenKeyEx
572 RegCloseKey
= _winreg
.CloseKey
573 HKEY_LOCAL_MACHINE
= _winreg
.HKEY_LOCAL_MACHINE
574 VER_PLATFORM_WIN32_WINDOWS
= 1
575 VER_PLATFORM_WIN32_NT
= 2
576 VER_NT_WORKSTATION
= 1
578 # Find out the registry key and some general version infos
579 maj
,min,buildno
,plat
,csd
= GetVersionEx()
580 version
= '%i.%i.%i' % (maj
,min,buildno
& 0xFFFF)
581 if csd
[:13] == 'Service Pack ':
582 csd
= 'SP' + csd
[13:]
583 if plat
== VER_PLATFORM_WIN32_WINDOWS
:
584 regkey
= 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
585 # Try to guess the release name
597 elif plat
== VER_PLATFORM_WIN32_NT
:
598 regkey
= 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
607 release
= '2003Server'
612 # Per http://msdn2.microsoft.com/en-us/library/ms724429.aspx
614 productType
= GetVersionEx(1)[8]
616 # sys.getwindowsversion() doesn't take any arguments, so
617 # we cannot detect 2008 Server that way.
618 # XXX Add some other means of detecting 2008 Server ?!
621 if productType
== VER_NT_WORKSTATION
:
624 release
= '2008Server'
626 release
= 'post2008Server'
629 # E.g. Win3.1 with win32s
630 release
= '%i.%i' % (maj
,min)
631 return release
,version
,csd
,ptype
633 # Open the registry key
635 keyCurVer
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, regkey
)
636 # Get a value to make sure the key exists...
637 RegQueryValueEx(keyCurVer
, 'SystemRoot')
639 return release
,version
,csd
,ptype
642 #subversion = _win32_getvalue(keyCurVer,
643 # 'SubVersionNumber',
646 # release = release + subversion # 95a, 95b, etc.
647 build
= _win32_getvalue(keyCurVer
,
648 'CurrentBuildNumber',
650 ptype
= _win32_getvalue(keyCurVer
,
655 version
= _norm_version(version
,build
)
658 RegCloseKey(keyCurVer
)
659 return release
,version
,csd
,ptype
661 def _mac_ver_lookup(selectors
,default
=None):
663 from gestalt
import gestalt
667 for selector
in selectors
:
669 append(gestalt(selector
))
670 except (RuntimeError, MacOS
.Error
):
678 def mac_ver(release
='',versioninfo
=('','',''),machine
=''):
680 """ Get MacOS version information and return it as tuple (release,
681 versioninfo, machine) with versioninfo being a tuple (version,
682 dev_stage, non_release_version).
684 Entries which cannot be determined are set to the paramter values
685 which default to ''. All tuple entries are strings.
687 Thanks to Mark R. Levinson for mailing documentation links and
688 code examples for this function. Documentation for the
689 gestalt() API is available online at:
691 http://www.rgaros.nl/gestalt/
694 # Check whether the version info module is available
699 return release
,versioninfo
,machine
701 sysv
,sysu
,sysa
= _mac_ver_lookup(('sysv','sysu','sysa'))
704 major
= (sysv
& 0xFF00) >> 8
705 minor
= (sysv
& 0x00F0) >> 4
706 patch
= (sysv
& 0x000F)
708 if (major
, minor
) >= (10, 4):
709 # the 'sysv' gestald cannot return patchlevels
710 # higher than 9. Apple introduced 3 new
711 # gestalt codes in 10.4 to deal with this
712 # issue (needed because patch levels can
713 # run higher than 9, such as 10.4.11)
714 major
,minor
,patch
= _mac_ver_lookup(('sys1','sys2','sys3'))
715 release
= '%i.%i.%i' %(major
, minor
, patch
)
717 release
= '%s.%i.%i' % (_bcd2str(major
),minor
,patch
)
720 # NOTE: this block is left as documentation of the
721 # intention of this function, the 'sysu' gestalt is no
722 # longer available and there are no alternatives.
723 major
= int((sysu
& 0xFF000000L
) >> 24)
724 minor
= (sysu
& 0x00F00000) >> 20
725 bugfix
= (sysu
& 0x000F0000) >> 16
726 stage
= (sysu
& 0x0000FF00) >> 8
727 nonrel
= (sysu
& 0x000000FF)
728 version
= '%s.%i.%i' % (_bcd2str(major
),minor
,bugfix
)
729 nonrel
= _bcd2str(nonrel
)
730 stage
= {0x20:'development',
733 0x80:'final'}.get(stage
,'')
734 versioninfo
= (version
,stage
,nonrel
)
738 machine
= {0x1: '68k',
740 0xa: 'i386'}.get(sysa
,'')
741 return release
,versioninfo
,machine
743 def _java_getprop(name
,default
):
745 from java
.lang
import System
747 value
= System
.getProperty(name
)
751 except AttributeError:
754 def java_ver(release
='',vendor
='',vminfo
=('','',''),osinfo
=('','','')):
756 """ Version interface for Jython.
758 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
759 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
760 tuple (os_name,os_version,os_arch).
762 Values which cannot be determined are set to the defaults
763 given as parameters (which all default to '').
766 # Import the needed APIs
770 return release
,vendor
,vminfo
,osinfo
772 vendor
= _java_getprop('java.vendor', vendor
)
773 release
= _java_getprop('java.version', release
)
774 vm_name
, vm_release
, vm_vendor
= vminfo
775 vm_name
= _java_getprop('java.vm.name', vm_name
)
776 vm_vendor
= _java_getprop('java.vm.vendor', vm_vendor
)
777 vm_release
= _java_getprop('java.vm.version', vm_release
)
778 vminfo
= vm_name
, vm_release
, vm_vendor
779 os_name
, os_version
, os_arch
= osinfo
780 os_arch
= _java_getprop('java.os.arch', os_arch
)
781 os_name
= _java_getprop('java.os.name', os_name
)
782 os_version
= _java_getprop('java.os.version', os_version
)
783 osinfo
= os_name
, os_version
, os_arch
785 return release
, vendor
, vminfo
, osinfo
787 ### System name aliasing
789 def system_alias(system
,release
,version
):
791 """ Returns (system,release,version) aliased to common
792 marketing names used for some systems.
794 It also does some reordering of the information in some cases
795 where it would otherwise cause confusion.
798 if system
== 'Rhapsody':
799 # Apple's BSD derivative
800 # XXX How can we determine the marketing release number ?
801 return 'MacOS X Server',system
+release
,version
803 elif system
== 'SunOS':
806 # These releases use the old name SunOS
807 return system
,release
,version
808 # Modify release (marketing release = SunOS release - 3)
809 l
= string
.split(release
,'.')
818 release
= string
.join(l
,'.')
822 # XXX Whatever the new SunOS marketing name is...
825 elif system
== 'IRIX64':
826 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
827 # is really a version and not a different platform, since 32-bit
828 # apps are also supported..
831 version
= version
+ ' (64bit)'
835 elif system
in ('win32','win16'):
836 # In case one of the other tricks
839 return system
,release
,version
841 ### Various internal helpers
843 def _platform(*args
):
845 """ Helper to format the platform string in a filename
846 compatible format e.g. "system-version-machine".
848 # Format the platform string
849 platform
= string
.join(
854 # Cleanup some possible filename obstacles...
855 replace
= string
.replace
856 platform
= replace(platform
,' ','_')
857 platform
= replace(platform
,'/','-')
858 platform
= replace(platform
,'\\','-')
859 platform
= replace(platform
,':','-')
860 platform
= replace(platform
,';','-')
861 platform
= replace(platform
,'"','-')
862 platform
= replace(platform
,'(','-')
863 platform
= replace(platform
,')','-')
865 # No need to report 'unknown' information...
866 platform
= replace(platform
,'unknown','')
868 # Fold '--'s and remove trailing '-'
870 cleaned
= replace(platform
,'--','-')
871 if cleaned
== platform
:
874 while platform
[-1] == '-':
875 platform
= platform
[:-1]
879 def _node(default
=''):
881 """ Helper to determine the node name of this machine.
889 return socket
.gethostname()
891 # Still not working...
894 # os.path.abspath is new in Python 1.5.2:
895 if not hasattr(os
.path
,'abspath'):
899 isabs
=os
.path
.isabs
,join
=os
.path
.join
,getcwd
=os
.getcwd
,
900 normpath
=os
.path
.normpath
):
903 path
= join(getcwd(), path
)
904 return normpath(path
)
908 _abspath
= os
.path
.abspath
910 def _follow_symlinks(filepath
):
912 """ In case filepath is a symlink, follow it until a
913 real file is reached.
915 filepath
= _abspath(filepath
)
916 while os
.path
.islink(filepath
):
917 filepath
= os
.path
.normpath(
918 os
.path
.join(os
.path
.dirname(filepath
),os
.readlink(filepath
)))
921 def _syscmd_uname(option
,default
=''):
923 """ Interface to the system's uname command.
925 if sys
.platform
in ('dos','win32','win16','os2'):
929 f
= os
.popen('uname %s 2> /dev/null' % option
)
930 except (AttributeError,os
.error
):
932 output
= string
.strip(f
.read())
939 def _syscmd_file(target
,default
=''):
941 """ Interface to the system's file command.
943 The function uses the -b option of the file command to have it
944 ommit the filename in its output and if possible the -L option
945 to have the command follow symlinks. It returns default in
946 case the command should fail.
949 if sys
.platform
in ('dos','win32','win16','os2'):
952 target
= _follow_symlinks(target
)
954 f
= os
.popen('file "%s" 2> /dev/null' % target
)
955 except (AttributeError,os
.error
):
957 output
= string
.strip(f
.read())
964 ### Information about the used architecture
966 # Default values for architecture; non-empty strings override the
967 # defaults given as parameters
968 _default_architecture
= {
969 'win32': ('','WindowsPE'),
970 'win16': ('','Windows'),
974 _architecture_split
= re
.compile(r
'[\s,]').split
976 def architecture(executable
=sys
.executable
,bits
='',linkage
=''):
978 """ Queries the given executable (defaults to the Python interpreter
979 binary) for various architecture information.
981 Returns a tuple (bits,linkage) which contains information about
982 the bit architecture and the linkage format used for the
983 executable. Both values are returned as strings.
985 Values that cannot be determined are returned as given by the
986 parameter presets. If bits is given as '', the sizeof(pointer)
987 (or sizeof(long) on Python version < 1.5.2) is used as
988 indicator for the supported pointer size.
990 The function relies on the system's "file" command to do the
991 actual work. This is available on most if not all Unix
992 platforms. On some non-Unix platforms where the "file" command
993 does not exist and the executable is set to the Python interpreter
994 binary defaults from _default_architecture are used.
997 # Use the sizeof(pointer) as default number of bits if nothing
998 # else is given as default.
1002 size
= struct
.calcsize('P')
1003 except struct
.error
:
1004 # Older installations can only query longs
1005 size
= struct
.calcsize('l')
1006 bits
= str(size
*8) + 'bit'
1008 # Get data from the 'file' system command
1010 output
= _syscmd_file(executable
, '')
1015 executable
== sys
.executable
:
1016 # "file" command did not return anything; we'll try to provide
1017 # some sensible defaults then...
1018 if _default_architecture
.has_key(sys
.platform
):
1019 b
,l
= _default_architecture
[sys
.platform
]
1026 # Split the output into a list of strings omitting the filename
1027 fileout
= _architecture_split(output
)[1:]
1029 if 'executable' not in fileout
:
1030 # Format not supported
1034 if '32-bit' in fileout
:
1036 elif 'N32' in fileout
:
1039 elif '64-bit' in fileout
:
1043 if 'ELF' in fileout
:
1045 elif 'PE' in fileout
:
1046 # E.g. Windows uses this format
1047 if 'Windows' in fileout
:
1048 linkage
= 'WindowsPE'
1051 elif 'COFF' in fileout
:
1053 elif 'MS-DOS' in fileout
:
1056 # XXX the A.OUT format also falls under this class...
1061 ### Portable uname() interface
1067 """ Fairly portable uname interface. Returns a tuple
1068 of strings (system,node,release,version,machine,processor)
1069 identifying the underlying platform.
1071 Note that unlike the os.uname function this also returns
1072 possible processor information as an additional tuple entry.
1074 Entries which cannot be determined are set to ''.
1080 if _uname_cache
is not None:
1085 # Get some infos from the builtin os.uname API...
1087 system
,node
,release
,version
,machine
= os
.uname()
1088 except AttributeError:
1091 if no_os_uname
or not filter(None, (system
, node
, release
, version
, machine
)):
1092 # Hmm, no there is either no uname or uname has returned
1093 #'unknowns'... we'll have to poke around the system then.
1095 system
= sys
.platform
1103 # Try win32_ver() on win32 platforms
1104 if system
== 'win32':
1105 release
,version
,csd
,ptype
= win32_ver()
1106 if release
and version
:
1108 # Try to use the PROCESSOR_* environment variables
1109 # available on Win XP and later; see
1110 # http://support.microsoft.com/kb/888731 and
1111 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
1113 machine
= os
.environ
.get('PROCESSOR_ARCHITECTURE', '')
1115 processor
= os
.environ
.get('PROCESSOR_IDENTIFIER', machine
)
1117 # Try the 'ver' system command available on some
1120 system
,release
,version
= _syscmd_ver(system
)
1121 # Normalize system to what win32_ver() normally returns
1122 # (_syscmd_ver() tends to return the vendor name as well)
1123 if system
== 'Microsoft Windows':
1125 elif system
== 'Microsoft' and release
== 'Windows':
1126 # Under Windows Vista and Windows Server 2008,
1127 # Microsoft changed the output of the ver command. The
1128 # release is no longer printed. This causes the
1129 # system and release to be misidentified.
1131 if '6.0' == version
[:3]:
1136 # In case we still don't know anything useful, we'll try to
1138 if system
in ('win32','win16'):
1140 if system
== 'win32':
1146 elif system
[:4] == 'java':
1147 release
,vendor
,vminfo
,osinfo
= java_ver()
1149 version
= string
.join(vminfo
,', ')
1153 elif os
.name
== 'mac':
1154 release
,(version
,stage
,nonrel
),machine
= mac_ver()
1157 # System specific extensions
1158 if system
== 'OpenVMS':
1159 # OpenVMS seems to have release and version mixed up
1160 if not release
or release
== '0':
1163 # Get processor information
1169 csid
, cpu_number
= vms_lib
.getsyi('SYI$_CPU',0)
1170 if (cpu_number
>= 128):
1175 # Get processor information from the uname system command
1176 processor
= _syscmd_uname('-p','')
1178 #If any unknowns still exist, replace them with ''s, which are more portable
1179 if system
== 'unknown':
1181 if node
== 'unknown':
1183 if release
== 'unknown':
1185 if version
== 'unknown':
1187 if machine
== 'unknown':
1189 if processor
== 'unknown':
1193 if system
== 'Microsoft' and release
== 'Windows':
1197 _uname_cache
= system
,node
,release
,version
,machine
,processor
1200 ### Direct interfaces to some of the uname() return values
1204 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1206 An empty string is returned if the value cannot be determined.
1213 """ Returns the computer's network name (which may not be fully
1216 An empty string is returned if the value cannot be determined.
1223 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1225 An empty string is returned if the value cannot be determined.
1232 """ Returns the system's release version, e.g. '#3 on degas'
1234 An empty string is returned if the value cannot be determined.
1241 """ Returns the machine type, e.g. 'i386'
1243 An empty string is returned if the value cannot be determined.
1250 """ Returns the (true) processor name, e.g. 'amdk6'
1252 An empty string is returned if the value cannot be
1253 determined. Note that many platforms do not provide this
1254 information or simply return the same value as for machine(),
1255 e.g. NetBSD does this.
1260 ### Various APIs for extracting information from sys.version
1262 _sys_version_parser
= re
.compile(
1264 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1267 _jython_sys_version_parser
= re
.compile(
1270 _ironpython_sys_version_parser
= re
.compile(
1273 '(?: \(([\d\.]+)\))?'
1274 ' on (.NET [\d\.]+)')
1276 _sys_version_cache
= {}
1278 def _sys_version(sys_version
=None):
1280 """ Returns a parsed version of Python's sys.version as tuple
1281 (name, version, branch, revision, buildno, builddate, compiler)
1282 referring to the Python implementation name, version, branch,
1283 revision, build number, build date/time as string and the compiler
1284 identification string.
1286 Note that unlike the Python sys.version, the returned value
1287 for the Python version will always include the patchlevel (it
1290 The function returns empty strings for tuple entries that
1291 cannot be determined.
1293 sys_version may be given to parse an alternative version
1294 string, e.g. if the version was read from a different Python
1298 # Get the Python version
1299 if sys_version
is None:
1300 sys_version
= sys
.version
1302 # Try the cache first
1303 result
= _sys_version_cache
.get(sys_version
, None)
1304 if result
is not None:
1308 if sys_version
[:10] == 'IronPython':
1311 match
= _ironpython_sys_version_parser
.match(sys_version
)
1314 'failed to parse IronPython sys.version: %s' %
1316 version
, alt_version
, compiler
= match
.groups()
1322 elif sys
.platform
[:4] == 'java':
1325 match
= _jython_sys_version_parser
.match(sys_version
)
1328 'failed to parse Jython sys.version: %s' %
1330 version
, = match
.groups()
1333 compiler
= sys
.platform
1339 match
= _sys_version_parser
.match(sys_version
)
1342 'failed to parse CPython sys.version: %s' %
1344 version
, buildno
, builddate
, buildtime
, compiler
= \
1346 if hasattr(sys
, 'subversion'):
1347 # sys.subversion was added in Python 2.5
1348 name
, branch
, revision
= sys
.subversion
1353 builddate
= builddate
+ ' ' + buildtime
1355 # Add the patchlevel version if missing
1356 l
= string
.split(version
, '.')
1359 version
= string
.join(l
, '.')
1361 # Build and cache the result
1362 result
= (name
, version
, branch
, revision
, buildno
, builddate
, compiler
)
1363 _sys_version_cache
[sys_version
] = result
1366 def python_implementation():
1368 """ Returns a string identifying the Python implementation.
1370 Currently, the following implementations are identified:
1371 'CPython' (C implementation of Python),
1372 'IronPython' (.NET implementation of Python),
1373 'Jython' (Java implementation of Python).
1376 return _sys_version()[0]
1378 def python_version():
1380 """ Returns the Python version as string 'major.minor.patchlevel'
1382 Note that unlike the Python sys.version, the returned value
1383 will always include the patchlevel (it defaults to 0).
1386 if hasattr(sys
, 'version_info'):
1387 return '%i.%i.%i' % sys
.version_info
[:3]
1388 return _sys_version()[1]
1390 def python_version_tuple():
1392 """ Returns the Python version as tuple (major, minor, patchlevel)
1395 Note that unlike the Python sys.version, the returned value
1396 will always include the patchlevel (it defaults to 0).
1399 if hasattr(sys
, 'version_info'):
1400 return sys
.version_info
[:3]
1401 return tuple(string
.split(_sys_version()[1], '.'))
1403 def python_branch():
1405 """ Returns a string identifying the Python implementation
1408 For CPython this is the Subversion branch from which the
1409 Python binary was built.
1411 If not available, an empty string is returned.
1415 return _sys_version()[2]
1417 def python_revision():
1419 """ Returns a string identifying the Python implementation
1422 For CPython this is the Subversion revision from which the
1423 Python binary was built.
1425 If not available, an empty string is returned.
1428 return _sys_version()[3]
1432 """ Returns a tuple (buildno, builddate) stating the Python
1433 build number and date as strings.
1436 return _sys_version()[4:6]
1438 def python_compiler():
1440 """ Returns a string identifying the compiler used for compiling
1444 return _sys_version()[6]
1446 ### The Opus Magnum of platform strings :-)
1448 _platform_cache
= {}
1450 def platform(aliased
=0, terse
=0):
1452 """ Returns a single string identifying the underlying platform
1453 with as much useful information as possible (but no more :).
1455 The output is intended to be human readable rather than
1456 machine parseable. It may look different on different
1457 platforms and this is intended.
1459 If "aliased" is true, the function will use aliases for
1460 various platforms that report system names which differ from
1461 their common names, e.g. SunOS will be reported as
1462 Solaris. The system_alias() function is used to implement
1465 Setting terse to true causes the function to return only the
1466 absolute minimum information needed to identify the platform.
1469 result
= _platform_cache
.get((aliased
, terse
), None)
1470 if result
is not None:
1473 # Get uname information and then apply platform specific cosmetics
1475 system
,node
,release
,version
,machine
,processor
= uname()
1476 if machine
== processor
:
1479 system
,release
,version
= system_alias(system
,release
,version
)
1481 if system
== 'Windows':
1483 rel
,vers
,csd
,ptype
= win32_ver(version
)
1485 platform
= _platform(system
,release
)
1487 platform
= _platform(system
,release
,version
,csd
)
1489 elif system
in ('Linux',):
1490 # Linux based systems
1491 distname
,distversion
,distid
= dist('')
1492 if distname
and not terse
:
1493 platform
= _platform(system
,release
,machine
,processor
,
1495 distname
,distversion
,distid
)
1497 # If the distribution name is unknown check for libc vs. glibc
1498 libcname
,libcversion
= libc_ver(sys
.executable
)
1499 platform
= _platform(system
,release
,machine
,processor
,
1501 libcname
+libcversion
)
1502 elif system
== 'Java':
1504 r
,v
,vminfo
,(os_name
,os_version
,os_arch
) = java_ver()
1505 if terse
or not os_name
:
1506 platform
= _platform(system
,release
,version
)
1508 platform
= _platform(system
,release
,version
,
1510 os_name
,os_version
,os_arch
)
1512 elif system
== 'MacOS':
1515 platform
= _platform(system
,release
)
1517 platform
= _platform(system
,release
,machine
)
1522 platform
= _platform(system
,release
)
1524 bits
,linkage
= architecture(sys
.executable
)
1525 platform
= _platform(system
,release
,machine
,processor
,bits
,linkage
)
1527 _platform_cache
[(aliased
, terse
)] = platform
1530 ### Command line interface
1532 if __name__
== '__main__':
1533 # Default is to print the aliased verbose platform string
1534 terse
= ('terse' in sys
.argv
or '--terse' in sys
.argv
)
1535 aliased
= (not 'nonaliased' in sys
.argv
and not '--nonaliased' in sys
.argv
)
1536 print platform(aliased
,terse
)