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 bug tracker (http://bugs.python.org) 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.7 - added DEV_NULL
38 # 1.0.6 - added linux_distribution()
39 # 1.0.5 - fixed Java support to allow running the module on Jython
40 # 1.0.4 - added IronPython support
41 # 1.0.3 - added normalization of Windows system name
42 # 1.0.2 - added more Windows support
43 # 1.0.1 - reformatted to make doc.py happy
44 # 1.0.0 - reformatted a bit and checked into Python CVS
45 # 0.8.0 - added sys.version parser and various new access
46 # APIs (python_version(), python_compiler(), etc.)
47 # 0.7.2 - fixed architecture() to use sizeof(pointer) where available
48 # 0.7.1 - added support for Caldera OpenLinux
49 # 0.7.0 - some fixes for WinCE; untabified the source file
50 # 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
51 # vms_lib.getsyi() configured
52 # 0.6.1 - added code to prevent 'uname -p' on platforms which are
53 # known not to support it
54 # 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
55 # did some cleanup of the interfaces - some APIs have changed
56 # 0.5.5 - fixed another type in the MacOS code... should have
57 # used more coffee today ;-)
58 # 0.5.4 - fixed a few typos in the MacOS code
59 # 0.5.3 - added experimental MacOS support; added better popen()
60 # workarounds in _syscmd_ver() -- still not 100% elegant
62 # 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
63 # return values (the system uname command tends to return
64 # 'unknown' instead of just leaving the field emtpy)
65 # 0.5.1 - included code for slackware dist; added exception handlers
66 # to cover up situations where platforms don't have os.popen
67 # (e.g. Mac) or fail on socket.gethostname(); fixed libc
69 # 0.5.0 - changed the API names referring to system commands to *syscmd*;
70 # added java_ver(); made syscmd_ver() a private
71 # API (was system_ver() in previous versions) -- use uname()
72 # instead; extended the win32_ver() to also return processor
74 # 0.4.0 - added win32_ver() and modified the platform() output for WinXX
75 # 0.3.4 - fixed a bug in _follow_symlinks()
76 # 0.3.3 - fixed popen() and "file" command invokation bugs
77 # 0.3.2 - added architecture() API and support for it in platform()
78 # 0.3.1 - fixed syscmd_ver() RE to support Windows NT
79 # 0.3.0 - added system alias support
80 # 0.2.3 - removed 'wince' again... oh well.
81 # 0.2.2 - added 'wince' to syscmd_ver() supported platforms
82 # 0.2.1 - added cache logic and changed the platform string format
83 # 0.2.0 - changed the API to use functions instead of module globals
84 # since some action take too long to be run on module import
85 # 0.1.0 - first release
87 # You can always get the latest version of this module at:
89 # http://www.egenix.com/files/python/platform.py
91 # If that URL should fail, try contacting the author.
94 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
95 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
97 Permission to use, copy, modify, and distribute this software and its
98 documentation for any purpose and without fee or royalty is hereby granted,
99 provided that the above copyright notice appear in all copies and that
100 both that copyright notice and this permission notice appear in
101 supporting documentation or portions thereof, including modifications,
104 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
105 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
106 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
107 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
108 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
109 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
110 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
114 __version__
= '1.0.7'
116 import sys
,string
,os
,re
118 ### Globals & Constants
120 # Determine the platform's /dev/null device
122 DEV_NULL
= os
.devnull
123 except AttributeError:
124 # os.devnull was added in Python 2.4, so emulate it for earlier
126 if sys
.platform
in ('dos','win32','win16','os2'):
127 # Use the old CP/M NUL as device name
130 # Standard Unix uses /dev/null
131 DEV_NULL
= '/dev/null'
133 ### Platform specific APIs
135 _libc_search
= re
.compile(r
'(__libc_init)'
139 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
141 def libc_ver(executable
=sys
.executable
,lib
='',version
='',
145 """ Tries to determine the libc version that the file executable
146 (which defaults to the Python interpreter) is linked against.
148 Returns a tuple of strings (lib,version) which default to the
149 given parameters in case the lookup fails.
151 Note that the function has intimate knowledge of how different
152 libc versions add symbols to the executable and thus is probably
153 only useable for executables compiled using gcc.
155 The file is read and scanned in chunks of chunksize bytes.
158 if hasattr(os
.path
, 'realpath'):
159 # Python 2.2 introduced os.path.realpath(); it is used
160 # here to work around problems with Cygwin not being
161 # able to open symlinks for reading
162 executable
= os
.path
.realpath(executable
)
163 f
= open(executable
,'rb')
164 binary
= f
.read(chunksize
)
167 m
= _libc_search
.search(binary
,pos
)
169 binary
= f
.read(chunksize
)
174 libcinit
,glibc
,glibcversion
,so
,threads
,soversion
= m
.groups()
175 if libcinit
and not lib
:
180 version
= glibcversion
181 elif glibcversion
> version
:
182 version
= glibcversion
186 if soversion
and soversion
> version
:
188 if threads
and version
[-len(threads
):] != threads
:
189 version
= version
+ threads
194 def _dist_try_harder(distname
,version
,id):
196 """ Tries some special tricks to get the distribution
197 information in case the default method fails.
199 Currently supports older SuSE Linux, Caldera OpenLinux and
200 Slackware Linux distributions.
203 if os
.path
.exists('/var/adm/inst-log/info'):
204 # SuSE Linux stores distribution information in that file
205 info
= open('/var/adm/inst-log/info').readlines()
208 tv
= string
.split(line
)
213 if tag
== 'MIN_DIST_VERSION':
214 version
= string
.strip(value
)
215 elif tag
== 'DIST_IDENT':
216 values
= string
.split(value
,'-')
218 return distname
,version
,id
220 if os
.path
.exists('/etc/.installed'):
221 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
222 info
= open('/etc/.installed').readlines()
224 pkg
= string
.split(line
,'-')
225 if len(pkg
) >= 2 and pkg
[0] == 'OpenLinux':
226 # XXX does Caldera support non Intel platforms ? If yes,
227 # where can we find the needed id ?
228 return 'OpenLinux',pkg
[1],id
230 if os
.path
.isdir('/usr/lib/setup'):
231 # Check for slackware version tag file (thanks to Greg Andruk)
232 verfiles
= os
.listdir('/usr/lib/setup')
233 for n
in range(len(verfiles
)-1, -1, -1):
234 if verfiles
[n
][:14] != 'slack-version-':
238 distname
= 'slackware'
239 version
= verfiles
[-1][14:]
240 return distname
,version
,id
242 return distname
,version
,id
244 _release_filename
= re
.compile(r
'(\w+)[-_](release|version)')
245 _lsb_release_version
= re
.compile(r
'(.+)'
248 '[^(]*(?:\((.+)\))?')
249 _release_version
= re
.compile(r
'([^0-9]+)'
252 '[^(]*(?:\((.+)\))?')
254 # See also http://www.novell.com/coolsolutions/feature/11251.html
255 # and http://linuxmafia.com/faq/Admin/release-files.html
256 # and http://data.linux-ntfs.org/rpm/whichrpm
257 # and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
260 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
261 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
262 'UnitedLinux', 'turbolinux')
264 def _parse_release_file(firstline
):
266 # Default to empty 'version' and 'id' strings. Both defaults are used
267 # when 'firstline' is empty. 'id' defaults to empty when an id can not
272 # Parse the first line
273 m
= _lsb_release_version
.match(firstline
)
275 # LSB format: "distro release x.x (codename)"
276 return tuple(m
.groups())
278 # Pre-LSB format: "distro x.x (codename)"
279 m
= _release_version
.match(firstline
)
281 return tuple(m
.groups())
283 # Unknown format... take the first two words
284 l
= string
.split(string
.strip(firstline
))
289 return '', version
, id
291 def linux_distribution(distname
='', version
='', id='',
293 supported_dists
=_supported_dists
,
294 full_distribution_name
=1):
296 """ Tries to determine the name of the Linux OS distribution name.
298 The function first looks for a distribution release file in
299 /etc and then reverts to _dist_try_harder() in case no
300 suitable files are found.
302 supported_dists may be given to define the set of Linux
303 distributions to look for. It defaults to a list of currently
304 supported Linux distributions identified by their release file
307 If full_distribution_name is true (default), the full
308 distribution read from the OS is returned. Otherwise the short
309 name taken from supported_dists is used.
311 Returns a tuple (distname,version,id) which default to the
312 args given as parameters.
316 etc
= os
.listdir('/etc')
318 # Probably not a Unix system
319 return distname
,version
,id
322 m
= _release_filename
.match(file)
324 _distname
,dummy
= m
.groups()
325 if _distname
in supported_dists
:
329 return _dist_try_harder(distname
,version
,id)
331 # Read the first line
332 f
= open('/etc/'+file, 'r')
333 firstline
= f
.readline()
335 _distname
, _version
, _id
= _parse_release_file(firstline
)
337 if _distname
and full_distribution_name
:
343 return distname
, version
, id
345 # To maintain backwards compatibility:
347 def dist(distname
='',version
='',id='',
349 supported_dists
=_supported_dists
):
351 """ Tries to determine the name of the Linux OS distribution name.
353 The function first looks for a distribution release file in
354 /etc and then reverts to _dist_try_harder() in case no
355 suitable files are found.
357 Returns a tuple (distname,version,id) which default to the
358 args given as parameters.
361 return linux_distribution(distname
, version
, id,
362 supported_dists
=supported_dists
,
363 full_distribution_name
=0)
367 """ Fairly portable (alternative) popen implementation.
369 This is mostly needed in case os.popen() is not available, or
370 doesn't work as advertised, e.g. in Win9X GUI programs like
373 Writing to the pipe is currently not supported.
381 def __init__(self
,cmd
,mode
='r',bufsize
=None):
384 raise ValueError,'popen()-emulation only supports read mode'
386 self
.tmpfile
= tmpfile
= tempfile
.mktemp()
387 os
.system(cmd
+ ' > %s' % tmpfile
)
388 self
.pipe
= open(tmpfile
,'rb')
389 self
.bufsize
= bufsize
394 return self
.pipe
.read()
398 if self
.bufsize
is not None:
399 return self
.pipe
.readlines()
403 remove
=os
.unlink
,error
=os
.error
):
406 rc
= self
.pipe
.close()
419 def popen(cmd
, mode
='r', bufsize
=None):
421 """ Portable popen() interface.
423 # Find a working popen implementation preferring win32pipe.popen
424 # over os.popen over _popen
426 if os
.environ
.get('OS','') == 'Windows_NT':
427 # On NT win32pipe should work; on Win9x it hangs due to bugs
428 # in the MS C lib (see MS KnowledgeBase article Q150956)
434 popen
= win32pipe
.popen
436 if hasattr(os
,'popen'):
438 # Check whether it works... it doesn't in GUI programs
439 # on Windows platforms
440 if sys
.platform
== 'win32': # XXX Others too ?
448 return popen(cmd
,mode
)
450 return popen(cmd
,mode
,bufsize
)
452 def _norm_version(version
, build
=''):
454 """ Normalize the version and build strings and return a single
455 version string using the format major.minor.build (or patchlevel).
457 l
= string
.split(version
,'.')
465 strings
= map(str,ints
)
466 version
= string
.join(strings
[:3],'.')
469 _ver_output
= re
.compile(r
'(?:([\w ]+) ([\w.]+) '
473 # Examples of VER command output:
475 # Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
476 # Windows XP: Microsoft Windows XP [Version 5.1.2600]
477 # Windows Vista: Microsoft Windows [Version 6.0.6002]
479 # Note that the "Version" string gets localized on different
482 def _syscmd_ver(system
='', release
='', version
='',
484 supported_platforms
=('win32','win16','dos','os2')):
486 """ Tries to figure out the OS version used and returns
487 a tuple (system,release,version).
489 It uses the "ver" shell command for this which is known
490 to exists on Windows, DOS and OS/2. XXX Others too ?
492 In case this fails, the given parameters are used as
496 if sys
.platform
not in supported_platforms
:
497 return system
,release
,version
499 # Try some common cmd strings
500 for cmd
in ('ver','command /c ver','cmd /c ver'):
505 raise os
.error
,'command failed'
506 # XXX How can I suppress shell errors from being written
509 #print 'Command %s failed: %s' % (cmd,why)
512 #print 'Command %s failed: %s' % (cmd,why)
517 return system
,release
,version
520 info
= string
.strip(info
)
521 m
= _ver_output
.match(info
)
523 system
,release
,version
= m
.groups()
524 # Strip trailing dots from version and release
525 if release
[-1] == '.':
526 release
= release
[:-1]
527 if version
[-1] == '.':
528 version
= version
[:-1]
529 # Normalize the version and build strings (eliminating additional
531 version
= _norm_version(version
)
532 return system
,release
,version
534 def _win32_getvalue(key
,name
,default
=''):
536 """ Read a value for name from the registry key.
538 In case this fails, default is returned.
542 # Use win32api if available
543 from win32api
import RegQueryValueEx
545 # On Python 2.0 and later, emulate using _winreg
547 RegQueryValueEx
= _winreg
.QueryValueEx
549 return RegQueryValueEx(key
,name
)
553 def win32_ver(release
='',version
='',csd
='',ptype
=''):
555 """ Get additional version information from the Windows Registry
556 and return a tuple (version,csd,ptype) referring to version
557 number, CSD level (service pack), and OS type (multi/single
560 As a hint: ptype returns 'Uniprocessor Free' on single
561 processor NT machines and 'Multiprocessor Free' on multi
562 processor machines. The 'Free' refers to the OS version being
563 free of debugging code. It could also state 'Checked' which
564 means the OS version uses debugging code, i.e. code that
565 checks arguments, ranges, etc. (Thomas Heller).
567 Note: this function works best with Mark Hammond's win32
568 package installed, but also on Python 2.3 and later. It
569 obviously only runs on Win32 compatible platforms.
572 # XXX Is there any way to find out the processor type on WinXX ?
573 # XXX Is win32 available on Windows CE ?
575 # Adapted from code posted by Karl Putland to comp.lang.python.
577 # The mappings between reg. values and release names can be found
578 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
580 # Import the needed APIs
583 from win32api
import RegQueryValueEx
, RegOpenKeyEx
, \
584 RegCloseKey
, GetVersionEx
585 from win32con
import HKEY_LOCAL_MACHINE
, VER_PLATFORM_WIN32_NT
, \
586 VER_PLATFORM_WIN32_WINDOWS
, VER_NT_WORKSTATION
588 # Emulate the win32api module using Python APIs
590 sys
.getwindowsversion
591 except AttributeError:
592 # No emulation possible, so return the defaults...
593 return release
,version
,csd
,ptype
595 # Emulation using _winreg (added in Python 2.0) and
596 # sys.getwindowsversion() (added in Python 2.3)
598 GetVersionEx
= sys
.getwindowsversion
599 RegQueryValueEx
= _winreg
.QueryValueEx
600 RegOpenKeyEx
= _winreg
.OpenKeyEx
601 RegCloseKey
= _winreg
.CloseKey
602 HKEY_LOCAL_MACHINE
= _winreg
.HKEY_LOCAL_MACHINE
603 VER_PLATFORM_WIN32_WINDOWS
= 1
604 VER_PLATFORM_WIN32_NT
= 2
605 VER_NT_WORKSTATION
= 1
609 # Find out the registry key and some general version infos
610 winver
= GetVersionEx()
611 maj
,min,buildno
,plat
,csd
= winver
612 version
= '%i.%i.%i' % (maj
,min,buildno
& 0xFFFF)
613 if hasattr(winver
, "service_pack"):
614 if winver
.service_pack
!= "":
615 csd
= 'SP%s' % winver
.service_pack_major
617 if csd
[:13] == 'Service Pack ':
618 csd
= 'SP' + csd
[13:]
620 if plat
== VER_PLATFORM_WIN32_WINDOWS
:
621 regkey
= 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
622 # Try to guess the release name
635 elif plat
== VER_PLATFORM_WIN32_NT
:
636 regkey
= 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
645 release
= '2003Server'
649 if hasattr(winver
, "product_type"):
650 product_type
= winver
.product_type
652 product_type
= VER_NT_WORKSTATION
653 # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
654 # or help from the registry, we cannot properly identify
655 # non-workstation versions.
657 key
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, regkey
)
658 name
, type = RegQueryValueEx(key
, "ProductName")
659 # Discard any type that isn't REG_SZ
660 if type == REG_SZ
and name
.find("Server") != -1:
661 product_type
= VER_NT_SERVER
663 # Use default of VER_NT_WORKSTATION
667 if product_type
== VER_NT_WORKSTATION
:
670 release
= '2008Server'
672 if product_type
== VER_NT_WORKSTATION
:
675 release
= '2008ServerR2'
677 if product_type
== VER_NT_WORKSTATION
:
680 release
= '2012Server'
682 release
= 'post2012Server'
686 # E.g. Win3.1 with win32s
687 release
= '%i.%i' % (maj
,min)
688 return release
,version
,csd
,ptype
690 # Open the registry key
692 keyCurVer
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, regkey
)
693 # Get a value to make sure the key exists...
694 RegQueryValueEx(keyCurVer
, 'SystemRoot')
696 return release
,version
,csd
,ptype
699 #subversion = _win32_getvalue(keyCurVer,
700 # 'SubVersionNumber',
703 # release = release + subversion # 95a, 95b, etc.
704 build
= _win32_getvalue(keyCurVer
,
705 'CurrentBuildNumber',
707 ptype
= _win32_getvalue(keyCurVer
,
712 version
= _norm_version(version
,build
)
715 RegCloseKey(keyCurVer
)
716 return release
,version
,csd
,ptype
718 def _mac_ver_lookup(selectors
,default
=None):
720 from gestalt
import gestalt
724 for selector
in selectors
:
726 append(gestalt(selector
))
727 except (RuntimeError, MacOS
.Error
):
735 def _mac_ver_gestalt():
737 Thanks to Mark R. Levinson for mailing documentation links and
738 code examples for this function. Documentation for the
739 gestalt() API is available online at:
741 http://www.rgaros.nl/gestalt/
743 # Check whether the version info module is available
750 sysv
,sysa
= _mac_ver_lookup(('sysv','sysa'))
753 major
= (sysv
& 0xFF00) >> 8
754 minor
= (sysv
& 0x00F0) >> 4
755 patch
= (sysv
& 0x000F)
757 if (major
, minor
) >= (10, 4):
758 # the 'sysv' gestald cannot return patchlevels
759 # higher than 9. Apple introduced 3 new
760 # gestalt codes in 10.4 to deal with this
761 # issue (needed because patch levels can
762 # run higher than 9, such as 10.4.11)
763 major
,minor
,patch
= _mac_ver_lookup(('sys1','sys2','sys3'))
764 release
= '%i.%i.%i' %(major
, minor
, patch
)
766 release
= '%s.%i.%i' % (_bcd2str(major
),minor
,patch
)
769 machine
= {0x1: '68k',
771 0xa: 'i386'}.get(sysa
,'')
773 versioninfo
=('', '', '')
774 return release
,versioninfo
,machine
777 fn
= '/System/Library/CoreServices/SystemVersion.plist'
778 if not os
.path
.exists(fn
):
786 pl
= plistlib
.readPlist(fn
)
787 release
= pl
['ProductVersion']
788 versioninfo
=('', '', '')
789 machine
= os
.uname()[4]
790 if machine
in ('ppc', 'Power Macintosh'):
791 # for compatibility with the gestalt based code
794 return release
,versioninfo
,machine
797 def mac_ver(release
='',versioninfo
=('','',''),machine
=''):
799 """ Get MacOS version information and return it as tuple (release,
800 versioninfo, machine) with versioninfo being a tuple (version,
801 dev_stage, non_release_version).
803 Entries which cannot be determined are set to the parameter values
804 which default to ''. All tuple entries are strings.
807 # First try reading the information from an XML file which should
809 info
= _mac_ver_xml()
813 # If that doesn't work for some reason fall back to reading the
814 # information using gestalt calls.
815 info
= _mac_ver_gestalt()
819 # If that also doesn't work return the default values
820 return release
,versioninfo
,machine
822 def _java_getprop(name
,default
):
824 from java
.lang
import System
826 value
= System
.getProperty(name
)
830 except AttributeError:
833 def java_ver(release
='',vendor
='',vminfo
=('','',''),osinfo
=('','','')):
835 """ Version interface for Jython.
837 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
838 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
839 tuple (os_name,os_version,os_arch).
841 Values which cannot be determined are set to the defaults
842 given as parameters (which all default to '').
845 # Import the needed APIs
849 return release
,vendor
,vminfo
,osinfo
851 vendor
= _java_getprop('java.vendor', vendor
)
852 release
= _java_getprop('java.version', release
)
853 vm_name
, vm_release
, vm_vendor
= vminfo
854 vm_name
= _java_getprop('java.vm.name', vm_name
)
855 vm_vendor
= _java_getprop('java.vm.vendor', vm_vendor
)
856 vm_release
= _java_getprop('java.vm.version', vm_release
)
857 vminfo
= vm_name
, vm_release
, vm_vendor
858 os_name
, os_version
, os_arch
= osinfo
859 os_arch
= _java_getprop('java.os.arch', os_arch
)
860 os_name
= _java_getprop('java.os.name', os_name
)
861 os_version
= _java_getprop('java.os.version', os_version
)
862 osinfo
= os_name
, os_version
, os_arch
864 return release
, vendor
, vminfo
, osinfo
866 ### System name aliasing
868 def system_alias(system
,release
,version
):
870 """ Returns (system,release,version) aliased to common
871 marketing names used for some systems.
873 It also does some reordering of the information in some cases
874 where it would otherwise cause confusion.
877 if system
== 'Rhapsody':
878 # Apple's BSD derivative
879 # XXX How can we determine the marketing release number ?
880 return 'MacOS X Server',system
+release
,version
882 elif system
== 'SunOS':
885 # These releases use the old name SunOS
886 return system
,release
,version
887 # Modify release (marketing release = SunOS release - 3)
888 l
= string
.split(release
,'.')
897 release
= string
.join(l
,'.')
901 # XXX Whatever the new SunOS marketing name is...
904 elif system
== 'IRIX64':
905 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
906 # is really a version and not a different platform, since 32-bit
907 # apps are also supported..
910 version
= version
+ ' (64bit)'
914 elif system
in ('win32','win16'):
915 # In case one of the other tricks
918 return system
,release
,version
920 ### Various internal helpers
922 def _platform(*args
):
924 """ Helper to format the platform string in a filename
925 compatible format e.g. "system-version-machine".
927 # Format the platform string
928 platform
= string
.join(
933 # Cleanup some possible filename obstacles...
934 replace
= string
.replace
935 platform
= replace(platform
,' ','_')
936 platform
= replace(platform
,'/','-')
937 platform
= replace(platform
,'\\','-')
938 platform
= replace(platform
,':','-')
939 platform
= replace(platform
,';','-')
940 platform
= replace(platform
,'"','-')
941 platform
= replace(platform
,'(','-')
942 platform
= replace(platform
,')','-')
944 # No need to report 'unknown' information...
945 platform
= replace(platform
,'unknown','')
947 # Fold '--'s and remove trailing '-'
949 cleaned
= replace(platform
,'--','-')
950 if cleaned
== platform
:
953 while platform
[-1] == '-':
954 platform
= platform
[:-1]
958 def _node(default
=''):
960 """ Helper to determine the node name of this machine.
968 return socket
.gethostname()
970 # Still not working...
973 # os.path.abspath is new in Python 1.5.2:
974 if not hasattr(os
.path
,'abspath'):
978 isabs
=os
.path
.isabs
,join
=os
.path
.join
,getcwd
=os
.getcwd
,
979 normpath
=os
.path
.normpath
):
982 path
= join(getcwd(), path
)
983 return normpath(path
)
987 _abspath
= os
.path
.abspath
989 def _follow_symlinks(filepath
):
991 """ In case filepath is a symlink, follow it until a
992 real file is reached.
994 filepath
= _abspath(filepath
)
995 while os
.path
.islink(filepath
):
996 filepath
= os
.path
.normpath(
997 os
.path
.join(os
.path
.dirname(filepath
),os
.readlink(filepath
)))
1000 def _syscmd_uname(option
,default
=''):
1002 """ Interface to the system's uname command.
1004 if sys
.platform
in ('dos','win32','win16','os2'):
1008 f
= os
.popen('uname %s 2> %s' % (option
, DEV_NULL
))
1009 except (AttributeError,os
.error
):
1011 output
= string
.strip(f
.read())
1013 if not output
or rc
:
1018 def _syscmd_file(target
,default
=''):
1020 """ Interface to the system's file command.
1022 The function uses the -b option of the file command to have it
1023 ommit the filename in its output and if possible the -L option
1024 to have the command follow symlinks. It returns default in
1025 case the command should fail.
1029 # We do the import here to avoid a bootstrap issue.
1030 # See c73b90b6dadd changeset.
1033 # ranlib libpython2.7.a
1035 # Modules/python.o \
1036 # libpython2.7.a -lsocket -lnsl -ldl -lm
1037 # Traceback (most recent call last):
1038 # File "./setup.py", line 8, in <module>
1039 # from platform import machine as platform_machine
1040 # File "[..]/build/Lib/platform.py", line 116, in <module>
1041 # import sys,string,os,re,subprocess
1042 # File "[..]/build/Lib/subprocess.py", line 429, in <module>
1044 # ImportError: No module named select
1048 if sys
.platform
in ('dos','win32','win16','os2'):
1051 target
= _follow_symlinks(target
)
1053 proc
= subprocess
.Popen(['file', target
],
1054 stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
1056 except (AttributeError,os
.error
):
1058 output
= proc
.communicate()[0]
1060 if not output
or rc
:
1065 ### Information about the used architecture
1067 # Default values for architecture; non-empty strings override the
1068 # defaults given as parameters
1069 _default_architecture
= {
1070 'win32': ('','WindowsPE'),
1071 'win16': ('','Windows'),
1072 'dos': ('','MSDOS'),
1075 _architecture_split
= re
.compile(r
'[\s,]').split
1077 def architecture(executable
=sys
.executable
,bits
='',linkage
=''):
1079 """ Queries the given executable (defaults to the Python interpreter
1080 binary) for various architecture information.
1082 Returns a tuple (bits,linkage) which contains information about
1083 the bit architecture and the linkage format used for the
1084 executable. Both values are returned as strings.
1086 Values that cannot be determined are returned as given by the
1087 parameter presets. If bits is given as '', the sizeof(pointer)
1088 (or sizeof(long) on Python version < 1.5.2) is used as
1089 indicator for the supported pointer size.
1091 The function relies on the system's "file" command to do the
1092 actual work. This is available on most if not all Unix
1093 platforms. On some non-Unix platforms where the "file" command
1094 does not exist and the executable is set to the Python interpreter
1095 binary defaults from _default_architecture are used.
1098 # Use the sizeof(pointer) as default number of bits if nothing
1099 # else is given as default.
1103 size
= struct
.calcsize('P')
1104 except struct
.error
:
1105 # Older installations can only query longs
1106 size
= struct
.calcsize('l')
1107 bits
= str(size
*8) + 'bit'
1109 # Get data from the 'file' system command
1111 output
= _syscmd_file(executable
, '')
1116 executable
== sys
.executable
:
1117 # "file" command did not return anything; we'll try to provide
1118 # some sensible defaults then...
1119 if sys
.platform
in _default_architecture
:
1120 b
, l
= _default_architecture
[sys
.platform
]
1125 return bits
, linkage
1127 # Split the output into a list of strings omitting the filename
1128 fileout
= _architecture_split(output
)[1:]
1130 if 'executable' not in fileout
:
1131 # Format not supported
1135 if '32-bit' in fileout
:
1137 elif 'N32' in fileout
:
1140 elif '64-bit' in fileout
:
1144 if 'ELF' in fileout
:
1146 elif 'PE' in fileout
:
1147 # E.g. Windows uses this format
1148 if 'Windows' in fileout
:
1149 linkage
= 'WindowsPE'
1152 elif 'COFF' in fileout
:
1154 elif 'MS-DOS' in fileout
:
1157 # XXX the A.OUT format also falls under this class...
1162 ### Portable uname() interface
1168 """ Fairly portable uname interface. Returns a tuple
1169 of strings (system,node,release,version,machine,processor)
1170 identifying the underlying platform.
1172 Note that unlike the os.uname function this also returns
1173 possible processor information as an additional tuple entry.
1175 Entries which cannot be determined are set to ''.
1181 if _uname_cache
is not None:
1186 # Get some infos from the builtin os.uname API...
1188 system
,node
,release
,version
,machine
= os
.uname()
1189 except AttributeError:
1192 if no_os_uname
or not filter(None, (system
, node
, release
, version
, machine
)):
1193 # Hmm, no there is either no uname or uname has returned
1194 #'unknowns'... we'll have to poke around the system then.
1196 system
= sys
.platform
1204 # Try win32_ver() on win32 platforms
1205 if system
== 'win32':
1206 release
,version
,csd
,ptype
= win32_ver()
1207 if release
and version
:
1209 # Try to use the PROCESSOR_* environment variables
1210 # available on Win XP and later; see
1211 # http://support.microsoft.com/kb/888731 and
1212 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
1214 # WOW64 processes mask the native architecture
1215 if "PROCESSOR_ARCHITEW6432" in os
.environ
:
1216 machine
= os
.environ
.get("PROCESSOR_ARCHITEW6432", '')
1218 machine
= os
.environ
.get('PROCESSOR_ARCHITECTURE', '')
1220 processor
= os
.environ
.get('PROCESSOR_IDENTIFIER', machine
)
1222 # Try the 'ver' system command available on some
1225 system
,release
,version
= _syscmd_ver(system
)
1226 # Normalize system to what win32_ver() normally returns
1227 # (_syscmd_ver() tends to return the vendor name as well)
1228 if system
== 'Microsoft Windows':
1230 elif system
== 'Microsoft' and release
== 'Windows':
1231 # Under Windows Vista and Windows Server 2008,
1232 # Microsoft changed the output of the ver command. The
1233 # release is no longer printed. This causes the
1234 # system and release to be misidentified.
1236 if '6.0' == version
[:3]:
1241 # In case we still don't know anything useful, we'll try to
1243 if system
in ('win32','win16'):
1245 if system
== 'win32':
1251 elif system
[:4] == 'java':
1252 release
,vendor
,vminfo
,osinfo
= java_ver()
1254 version
= string
.join(vminfo
,', ')
1258 # System specific extensions
1259 if system
== 'OpenVMS':
1260 # OpenVMS seems to have release and version mixed up
1261 if not release
or release
== '0':
1264 # Get processor information
1270 csid
, cpu_number
= vms_lib
.getsyi('SYI$_CPU',0)
1271 if (cpu_number
>= 128):
1276 # Get processor information from the uname system command
1277 processor
= _syscmd_uname('-p','')
1279 #If any unknowns still exist, replace them with ''s, which are more portable
1280 if system
== 'unknown':
1282 if node
== 'unknown':
1284 if release
== 'unknown':
1286 if version
== 'unknown':
1288 if machine
== 'unknown':
1290 if processor
== 'unknown':
1294 if system
== 'Microsoft' and release
== 'Windows':
1298 _uname_cache
= system
,node
,release
,version
,machine
,processor
1301 ### Direct interfaces to some of the uname() return values
1305 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1307 An empty string is returned if the value cannot be determined.
1314 """ Returns the computer's network name (which may not be fully
1317 An empty string is returned if the value cannot be determined.
1324 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1326 An empty string is returned if the value cannot be determined.
1333 """ Returns the system's release version, e.g. '#3 on degas'
1335 An empty string is returned if the value cannot be determined.
1342 """ Returns the machine type, e.g. 'i386'
1344 An empty string is returned if the value cannot be determined.
1351 """ Returns the (true) processor name, e.g. 'amdk6'
1353 An empty string is returned if the value cannot be
1354 determined. Note that many platforms do not provide this
1355 information or simply return the same value as for machine(),
1356 e.g. NetBSD does this.
1361 ### Various APIs for extracting information from sys.version
1363 _sys_version_parser
= re
.compile(
1365 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1368 _ironpython_sys_version_parser
= re
.compile(
1371 '(?: \(([\d\.]+)\))?'
1372 ' on (.NET [\d\.]+)')
1374 # IronPython covering 2.6 and 2.7
1375 _ironpython26_sys_version_parser
= re
.compile(
1379 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1382 _pypy_sys_version_parser
= re
.compile(
1384 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1387 _sys_version_cache
= {}
1389 def _sys_version(sys_version
=None):
1391 """ Returns a parsed version of Python's sys.version as tuple
1392 (name, version, branch, revision, buildno, builddate, compiler)
1393 referring to the Python implementation name, version, branch,
1394 revision, build number, build date/time as string and the compiler
1395 identification string.
1397 Note that unlike the Python sys.version, the returned value
1398 for the Python version will always include the patchlevel (it
1401 The function returns empty strings for tuple entries that
1402 cannot be determined.
1404 sys_version may be given to parse an alternative version
1405 string, e.g. if the version was read from a different Python
1409 # Get the Python version
1410 if sys_version
is None:
1411 sys_version
= sys
.version
1413 # Try the cache first
1414 result
= _sys_version_cache
.get(sys_version
, None)
1415 if result
is not None:
1419 if 'IronPython' in sys_version
:
1422 if sys_version
.startswith('IronPython'):
1423 match
= _ironpython_sys_version_parser
.match(sys_version
)
1425 match
= _ironpython26_sys_version_parser
.match(sys_version
)
1429 'failed to parse IronPython sys.version: %s' %
1432 version
, alt_version
, compiler
= match
.groups()
1436 elif sys
.platform
.startswith('java'):
1439 match
= _sys_version_parser
.match(sys_version
)
1442 'failed to parse Jython sys.version: %s' %
1444 version
, buildno
, builddate
, buildtime
, _
= match
.groups()
1445 compiler
= sys
.platform
1447 elif "PyPy" in sys_version
:
1450 match
= _pypy_sys_version_parser
.match(sys_version
)
1452 raise ValueError("failed to parse PyPy sys.version: %s" %
1454 version
, buildno
, builddate
, buildtime
= match
.groups()
1459 match
= _sys_version_parser
.match(sys_version
)
1462 'failed to parse CPython sys.version: %s' %
1464 version
, buildno
, builddate
, buildtime
, compiler
= \
1467 builddate
= builddate
+ ' ' + buildtime
1469 if hasattr(sys
, 'subversion'):
1470 # sys.subversion was added in Python 2.5
1471 _
, branch
, revision
= sys
.subversion
1476 # Add the patchlevel version if missing
1477 l
= string
.split(version
, '.')
1480 version
= string
.join(l
, '.')
1482 # Build and cache the result
1483 result
= (name
, version
, branch
, revision
, buildno
, builddate
, compiler
)
1484 _sys_version_cache
[sys_version
] = result
1487 def python_implementation():
1489 """ Returns a string identifying the Python implementation.
1491 Currently, the following implementations are identified:
1492 'CPython' (C implementation of Python),
1493 'IronPython' (.NET implementation of Python),
1494 'Jython' (Java implementation of Python),
1495 'PyPy' (Python implementation of Python).
1498 return _sys_version()[0]
1500 def python_version():
1502 """ Returns the Python version as string 'major.minor.patchlevel'
1504 Note that unlike the Python sys.version, the returned value
1505 will always include the patchlevel (it defaults to 0).
1508 return _sys_version()[1]
1510 def python_version_tuple():
1512 """ Returns the Python version as tuple (major, minor, patchlevel)
1515 Note that unlike the Python sys.version, the returned value
1516 will always include the patchlevel (it defaults to 0).
1519 return tuple(string
.split(_sys_version()[1], '.'))
1521 def python_branch():
1523 """ Returns a string identifying the Python implementation
1526 For CPython this is the Subversion branch from which the
1527 Python binary was built.
1529 If not available, an empty string is returned.
1533 return _sys_version()[2]
1535 def python_revision():
1537 """ Returns a string identifying the Python implementation
1540 For CPython this is the Subversion revision from which the
1541 Python binary was built.
1543 If not available, an empty string is returned.
1546 return _sys_version()[3]
1550 """ Returns a tuple (buildno, builddate) stating the Python
1551 build number and date as strings.
1554 return _sys_version()[4:6]
1556 def python_compiler():
1558 """ Returns a string identifying the compiler used for compiling
1562 return _sys_version()[6]
1564 ### The Opus Magnum of platform strings :-)
1566 _platform_cache
= {}
1568 def platform(aliased
=0, terse
=0):
1570 """ Returns a single string identifying the underlying platform
1571 with as much useful information as possible (but no more :).
1573 The output is intended to be human readable rather than
1574 machine parseable. It may look different on different
1575 platforms and this is intended.
1577 If "aliased" is true, the function will use aliases for
1578 various platforms that report system names which differ from
1579 their common names, e.g. SunOS will be reported as
1580 Solaris. The system_alias() function is used to implement
1583 Setting terse to true causes the function to return only the
1584 absolute minimum information needed to identify the platform.
1587 result
= _platform_cache
.get((aliased
, terse
), None)
1588 if result
is not None:
1591 # Get uname information and then apply platform specific cosmetics
1593 system
,node
,release
,version
,machine
,processor
= uname()
1594 if machine
== processor
:
1597 system
,release
,version
= system_alias(system
,release
,version
)
1599 if system
== 'Windows':
1601 rel
,vers
,csd
,ptype
= win32_ver(version
)
1603 platform
= _platform(system
,release
)
1605 platform
= _platform(system
,release
,version
,csd
)
1607 elif system
in ('Linux',):
1608 # Linux based systems
1609 distname
,distversion
,distid
= dist('')
1610 if distname
and not terse
:
1611 platform
= _platform(system
,release
,machine
,processor
,
1613 distname
,distversion
,distid
)
1615 # If the distribution name is unknown check for libc vs. glibc
1616 libcname
,libcversion
= libc_ver(sys
.executable
)
1617 platform
= _platform(system
,release
,machine
,processor
,
1619 libcname
+libcversion
)
1620 elif system
== 'Java':
1622 r
,v
,vminfo
,(os_name
,os_version
,os_arch
) = java_ver()
1623 if terse
or not os_name
:
1624 platform
= _platform(system
,release
,version
)
1626 platform
= _platform(system
,release
,version
,
1628 os_name
,os_version
,os_arch
)
1630 elif system
== 'MacOS':
1633 platform
= _platform(system
,release
)
1635 platform
= _platform(system
,release
,machine
)
1640 platform
= _platform(system
,release
)
1642 bits
,linkage
= architecture(sys
.executable
)
1643 platform
= _platform(system
,release
,machine
,processor
,bits
,linkage
)
1645 _platform_cache
[(aliased
, terse
)] = platform
1648 ### Command line interface
1650 if __name__
== '__main__':
1651 # Default is to print the aliased verbose platform string
1652 terse
= ('terse' in sys
.argv
or '--terse' in sys
.argv
)
1653 aliased
= (not 'nonaliased' in sys
.argv
and not '--nonaliased' in sys
.argv
)
1654 print platform(aliased
,terse
)