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
35 # <see CVS and SVN checkin messages for history>
37 # 1.0.3 - added normalization of Windows system name
38 # 1.0.2 - added more Windows support
39 # 1.0.1 - reformatted to make doc.py happy
40 # 1.0.0 - reformatted a bit and checked into Python CVS
41 # 0.8.0 - added sys.version parser and various new access
42 # APIs (python_version(), python_compiler(), etc.)
43 # 0.7.2 - fixed architecture() to use sizeof(pointer) where available
44 # 0.7.1 - added support for Caldera OpenLinux
45 # 0.7.0 - some fixes for WinCE; untabified the source file
46 # 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
47 # vms_lib.getsyi() configured
48 # 0.6.1 - added code to prevent 'uname -p' on platforms which are
49 # known not to support it
50 # 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
51 # did some cleanup of the interfaces - some APIs have changed
52 # 0.5.5 - fixed another type in the MacOS code... should have
53 # used more coffee today ;-)
54 # 0.5.4 - fixed a few typos in the MacOS code
55 # 0.5.3 - added experimental MacOS support; added better popen()
56 # workarounds in _syscmd_ver() -- still not 100% elegant
58 # 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
59 # return values (the system uname command tends to return
60 # 'unknown' instead of just leaving the field emtpy)
61 # 0.5.1 - included code for slackware dist; added exception handlers
62 # to cover up situations where platforms don't have os.popen
63 # (e.g. Mac) or fail on socket.gethostname(); fixed libc
65 # 0.5.0 - changed the API names referring to system commands to *syscmd*;
66 # added java_ver(); made syscmd_ver() a private
67 # API (was system_ver() in previous versions) -- use uname()
68 # instead; extended the win32_ver() to also return processor
70 # 0.4.0 - added win32_ver() and modified the platform() output for WinXX
71 # 0.3.4 - fixed a bug in _follow_symlinks()
72 # 0.3.3 - fixed popen() and "file" command invokation bugs
73 # 0.3.2 - added architecture() API and support for it in platform()
74 # 0.3.1 - fixed syscmd_ver() RE to support Windows NT
75 # 0.3.0 - added system alias support
76 # 0.2.3 - removed 'wince' again... oh well.
77 # 0.2.2 - added 'wince' to syscmd_ver() supported platforms
78 # 0.2.1 - added cache logic and changed the platform string format
79 # 0.2.0 - changed the API to use functions instead of module globals
80 # since some action take too long to be run on module import
81 # 0.1.0 - first release
83 # You can always get the latest version of this module at:
85 # http://www.egenix.com/files/python/platform.py
87 # If that URL should fail, try contacting the author.
90 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
91 Copyright (c) 2000-2003, eGenix.com Software GmbH; mailto:info@egenix.com
93 Permission to use, copy, modify, and distribute this software and its
94 documentation for any purpose and without fee or royalty is hereby granted,
95 provided that the above copyright notice appear in all copies and that
96 both that copyright notice and this permission notice appear in
97 supporting documentation or portions thereof, including modifications,
100 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
101 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
102 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
103 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
104 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
105 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
106 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
110 __version__
= '1.0.4'
112 import sys
,string
,os
,re
114 ### Platform specific APIs
116 _libc_search
= re
.compile(r
'(__libc_init)'
120 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
122 def libc_ver(executable
=sys
.executable
,lib
='',version
='',
126 """ Tries to determine the libc version that the file executable
127 (which defaults to the Python interpreter) is linked against.
129 Returns a tuple of strings (lib,version) which default to the
130 given parameters in case the lookup fails.
132 Note that the function has intimate knowledge of how different
133 libc versions add symbols to the executable and thus is probably
134 only useable for executables compiled using gcc.
136 The file is read and scanned in chunks of chunksize bytes.
139 f
= open(executable
,'rb')
140 binary
= f
.read(chunksize
)
143 m
= _libc_search
.search(binary
,pos
)
145 binary
= f
.read(chunksize
)
150 libcinit
,glibc
,glibcversion
,so
,threads
,soversion
= m
.groups()
151 if libcinit
and not lib
:
156 version
= glibcversion
157 elif glibcversion
> version
:
158 version
= glibcversion
162 if soversion
> version
:
164 if threads
and version
[-len(threads
):] != threads
:
165 version
= version
+ threads
170 def _dist_try_harder(distname
,version
,id):
172 """ Tries some special tricks to get the distribution
173 information in case the default method fails.
175 Currently supports older SuSE Linux, Caldera OpenLinux and
176 Slackware Linux distributions.
179 if os
.path
.exists('/var/adm/inst-log/info'):
180 # SuSE Linux stores distribution information in that file
181 info
= open('/var/adm/inst-log/info').readlines()
184 tv
= string
.split(line
)
189 if tag
== 'MIN_DIST_VERSION':
190 version
= string
.strip(value
)
191 elif tag
== 'DIST_IDENT':
192 values
= string
.split(value
,'-')
194 return distname
,version
,id
196 if os
.path
.exists('/etc/.installed'):
197 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
198 info
= open('/etc/.installed').readlines()
200 pkg
= string
.split(line
,'-')
201 if len(pkg
) >= 2 and pkg
[0] == 'OpenLinux':
202 # XXX does Caldera support non Intel platforms ? If yes,
203 # where can we find the needed id ?
204 return 'OpenLinux',pkg
[1],id
206 if os
.path
.isdir('/usr/lib/setup'):
207 # Check for slackware verson tag file (thanks to Greg Andruk)
208 verfiles
= os
.listdir('/usr/lib/setup')
209 for n
in range(len(verfiles
)-1, -1, -1):
210 if verfiles
[n
][:14] != 'slack-version-':
214 distname
= 'slackware'
215 version
= verfiles
[-1][14:]
216 return distname
,version
,id
218 return distname
,version
,id
220 _release_filename
= re
.compile(r
'(\w+)[-_](release|version)')
221 _release_version
= re
.compile(r
'([\d.]+)[^(]*(?:\((.+)\))?')
223 # Note:In supported_dists below we need 'fedora' before 'redhat' as in
224 # Fedora redhat-release is a link to fedora-release.
226 def dist(distname
='',version
='',id='',
228 supported_dists
=('SuSE', 'debian', 'fedora', 'redhat', 'mandrake')):
230 """ Tries to determine the name of the Linux OS distribution name.
232 The function first looks for a distribution release file in
233 /etc and then reverts to _dist_try_harder() in case no
234 suitable files are found.
236 Returns a tuple (distname,version,id) which default to the
237 args given as parameters.
241 etc
= os
.listdir('/etc')
243 # Probably not a Unix system
244 return distname
,version
,id
246 m
= _release_filename
.match(file)
248 _distname
,dummy
= m
.groups()
249 if _distname
in supported_dists
:
253 return _dist_try_harder(distname
,version
,id)
254 f
= open('/etc/'+file,'r')
255 firstline
= f
.readline()
257 m
= _release_version
.search(firstline
)
259 _version
,_id
= m
.groups()
265 # Unkown format... take the first two words
266 l
= string
.split(string
.strip(firstline
))
271 return distname
,version
,id
275 """ Fairly portable (alternative) popen implementation.
277 This is mostly needed in case os.popen() is not available, or
278 doesn't work as advertised, e.g. in Win9X GUI programs like
281 Writing to the pipe is currently not supported.
289 def __init__(self
,cmd
,mode
='r',bufsize
=None):
292 raise ValueError,'popen()-emulation only supports read mode'
294 self
.tmpfile
= tmpfile
= tempfile
.mktemp()
295 os
.system(cmd
+ ' > %s' % tmpfile
)
296 self
.pipe
= open(tmpfile
,'rb')
297 self
.bufsize
= bufsize
302 return self
.pipe
.read()
306 if self
.bufsize
is not None:
307 return self
.pipe
.readlines()
311 remove
=os
.unlink
,error
=os
.error
):
314 rc
= self
.pipe
.close()
327 def popen(cmd
, mode
='r', bufsize
=None):
329 """ Portable popen() interface.
331 # Find a working popen implementation preferring win32pipe.popen
332 # over os.popen over _popen
334 if os
.environ
.get('OS','') == 'Windows_NT':
335 # On NT win32pipe should work; on Win9x it hangs due to bugs
336 # in the MS C lib (see MS KnowledgeBase article Q150956)
342 popen
= win32pipe
.popen
344 if hasattr(os
,'popen'):
346 # Check whether it works... it doesn't in GUI programs
347 # on Windows platforms
348 if sys
.platform
== 'win32': # XXX Others too ?
356 return popen(cmd
,mode
)
358 return popen(cmd
,mode
,bufsize
)
360 def _norm_version(version
,build
=''):
362 """ Normalize the version and build strings and return a single
363 version string using the format major.minor.build (or patchlevel).
365 l
= string
.split(version
,'.')
373 strings
= map(str,ints
)
374 version
= string
.join(strings
[:3],'.')
377 _ver_output
= re
.compile(r
'(?:([\w ]+) ([\w.]+) '
381 def _syscmd_ver(system
='',release
='',version
='',
383 supported_platforms
=('win32','win16','dos','os2')):
385 """ Tries to figure out the OS version used and returns
386 a tuple (system,release,version).
388 It uses the "ver" shell command for this which is known
389 to exists on Windows, DOS and OS/2. XXX Others too ?
391 In case this fails, the given parameters are used as
395 if sys
.platform
not in supported_platforms
:
396 return system
,release
,version
398 # Try some common cmd strings
399 for cmd
in ('ver','command /c ver','cmd /c ver'):
404 raise os
.error
,'command failed'
405 # XXX How can I supress shell errors from being written
408 #print 'Command %s failed: %s' % (cmd,why)
411 #print 'Command %s failed: %s' % (cmd,why)
416 return system
,release
,version
419 info
= string
.strip(info
)
420 m
= _ver_output
.match(info
)
422 system
,release
,version
= m
.groups()
423 # Strip trailing dots from version and release
424 if release
[-1] == '.':
425 release
= release
[:-1]
426 if version
[-1] == '.':
427 version
= version
[:-1]
428 # Normalize the version and build strings (eliminating additional
430 version
= _norm_version(version
)
431 return system
,release
,version
433 def _win32_getvalue(key
,name
,default
=''):
435 """ Read a value for name from the registry key.
437 In case this fails, default is returned.
440 from win32api
import RegQueryValueEx
442 return RegQueryValueEx(key
,name
)
446 def win32_ver(release
='',version
='',csd
='',ptype
=''):
448 """ Get additional version information from the Windows Registry
449 and return a tuple (version,csd,ptype) referring to version
450 number, CSD level and OS type (multi/single
453 As a hint: ptype returns 'Uniprocessor Free' on single
454 processor NT machines and 'Multiprocessor Free' on multi
455 processor machines. The 'Free' refers to the OS version being
456 free of debugging code. It could also state 'Checked' which
457 means the OS version uses debugging code, i.e. code that
458 checks arguments, ranges, etc. (Thomas Heller).
460 Note: this function only works if Mark Hammond's win32
461 package is installed and obviously only runs on Win32
462 compatible platforms.
465 # XXX Is there any way to find out the processor type on WinXX ?
466 # XXX Is win32 available on Windows CE ?
468 # Adapted from code posted by Karl Putland to comp.lang.python.
470 # The mappings between reg. values and release names can be found
471 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
473 # Import the needed APIs
477 return release
,version
,csd
,ptype
478 from win32api
import RegQueryValueEx
,RegOpenKeyEx
,RegCloseKey
,GetVersionEx
479 from win32con
import HKEY_LOCAL_MACHINE
,VER_PLATFORM_WIN32_NT
,\
480 VER_PLATFORM_WIN32_WINDOWS
482 # Find out the registry key and some general version infos
483 maj
,min,buildno
,plat
,csd
= GetVersionEx()
484 version
= '%i.%i.%i' % (maj
,min,buildno
& 0xFFFF)
485 if csd
[:13] == 'Service Pack ':
486 csd
= 'SP' + csd
[13:]
487 if plat
== VER_PLATFORM_WIN32_WINDOWS
:
488 regkey
= 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
489 # Try to guess the release name
501 elif plat
== VER_PLATFORM_WIN32_NT
:
502 regkey
= 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
511 release
= '2003Server'
516 # E.g. Win3.1 with win32s
517 release
= '%i.%i' % (maj
,min)
518 return release
,version
,csd
,ptype
520 # Open the registry key
522 keyCurVer
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
,regkey
)
523 # Get a value to make sure the key exists...
524 RegQueryValueEx(keyCurVer
,'SystemRoot')
526 return release
,version
,csd
,ptype
529 #subversion = _win32_getvalue(keyCurVer,
530 # 'SubVersionNumber',
533 # release = release + subversion # 95a, 95b, etc.
534 build
= _win32_getvalue(keyCurVer
,
535 'CurrentBuildNumber',
537 ptype
= _win32_getvalue(keyCurVer
,
542 version
= _norm_version(version
,build
)
545 RegCloseKey(keyCurVer
)
546 return release
,version
,csd
,ptype
548 def _mac_ver_lookup(selectors
,default
=None):
550 from gestalt
import gestalt
554 for selector
in selectors
:
556 append(gestalt(selector
))
557 except (RuntimeError, MacOS
.Error
):
565 def mac_ver(release
='',versioninfo
=('','',''),machine
=''):
567 """ Get MacOS version information and return it as tuple (release,
568 versioninfo, machine) with versioninfo being a tuple (version,
569 dev_stage, non_release_version).
571 Entries which cannot be determined are set to the paramter values
572 which default to ''. All tuple entries are strings.
574 Thanks to Mark R. Levinson for mailing documentation links and
575 code examples for this function. Documentation for the
576 gestalt() API is available online at:
578 http://www.rgaros.nl/gestalt/
581 # Check whether the version info module is available
586 return release
,versioninfo
,machine
588 sysv
,sysu
,sysa
= _mac_ver_lookup(('sysv','sysu','sysa'))
591 major
= (sysv
& 0xFF00) >> 8
592 minor
= (sysv
& 0x00F0) >> 4
593 patch
= (sysv
& 0x000F)
594 release
= '%s.%i.%i' % (_bcd2str(major
),minor
,patch
)
596 major
= int((sysu
& 0xFF000000L
) >> 24)
597 minor
= (sysu
& 0x00F00000) >> 20
598 bugfix
= (sysu
& 0x000F0000) >> 16
599 stage
= (sysu
& 0x0000FF00) >> 8
600 nonrel
= (sysu
& 0x000000FF)
601 version
= '%s.%i.%i' % (_bcd2str(major
),minor
,bugfix
)
602 nonrel
= _bcd2str(nonrel
)
603 stage
= {0x20:'development',
606 0x80:'final'}.get(stage
,'')
607 versioninfo
= (version
,stage
,nonrel
)
609 machine
= {0x1: '68k',
610 0x2: 'PowerPC'}.get(sysa
,'')
611 return release
,versioninfo
,machine
613 def _java_getprop(name
,default
):
615 from java
.lang
import System
617 return System
.getProperty(name
)
621 def java_ver(release
='',vendor
='',vminfo
=('','',''),osinfo
=('','','')):
623 """ Version interface for Jython.
625 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
626 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
627 tuple (os_name,os_version,os_arch).
629 Values which cannot be determined are set to the defaults
630 given as parameters (which all default to '').
633 # Import the needed APIs
637 return release
,vendor
,vminfo
,osinfo
639 vendor
= _java_getprop('java.vendor',vendor
)
640 release
= _java_getprop('java.version',release
)
641 vm_name
,vm_release
,vm_vendor
= vminfo
642 vm_name
= _java_getprop('java.vm.name',vm_name
)
643 vm_vendor
= _java_getprop('java.vm.vendor',vm_vendor
)
644 vm_release
= _java_getprop('java.vm.version',vm_release
)
645 vminfo
= vm_name
,vm_release
,vm_vendor
646 os_name
,os_version
,os_arch
= osinfo
647 os_arch
= _java_getprop('java.os.arch',os_arch
)
648 os_name
= _java_getprop('java.os.name',os_name
)
649 os_version
= _java_getprop('java.os.version',os_version
)
650 osinfo
= os_name
,os_version
,os_arch
652 return release
,vendor
,vminfo
,osinfo
654 ### System name aliasing
656 def system_alias(system
,release
,version
):
658 """ Returns (system,release,version) aliased to common
659 marketing names used for some systems.
661 It also does some reordering of the information in some cases
662 where it would otherwise cause confusion.
665 if system
== 'Rhapsody':
666 # Apple's BSD derivative
667 # XXX How can we determine the marketing release number ?
668 return 'MacOS X Server',system
+release
,version
670 elif system
== 'SunOS':
673 # These releases use the old name SunOS
674 return system
,release
,version
675 # Modify release (marketing release = SunOS release - 3)
676 l
= string
.split(release
,'.')
685 release
= string
.join(l
,'.')
689 # XXX Whatever the new SunOS marketing name is...
692 elif system
== 'IRIX64':
693 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
694 # is really a version and not a different platform, since 32-bit
695 # apps are also supported..
698 version
= version
+ ' (64bit)'
702 elif system
in ('win32','win16'):
703 # In case one of the other tricks
706 return system
,release
,version
708 ### Various internal helpers
710 def _platform(*args
):
712 """ Helper to format the platform string in a filename
713 compatible format e.g. "system-version-machine".
715 # Format the platform string
716 platform
= string
.join(
721 # Cleanup some possible filename obstacles...
722 replace
= string
.replace
723 platform
= replace(platform
,' ','_')
724 platform
= replace(platform
,'/','-')
725 platform
= replace(platform
,'\\','-')
726 platform
= replace(platform
,':','-')
727 platform
= replace(platform
,';','-')
728 platform
= replace(platform
,'"','-')
729 platform
= replace(platform
,'(','-')
730 platform
= replace(platform
,')','-')
732 # No need to report 'unknown' information...
733 platform
= replace(platform
,'unknown','')
735 # Fold '--'s and remove trailing '-'
737 cleaned
= replace(platform
,'--','-')
738 if cleaned
== platform
:
741 while platform
[-1] == '-':
742 platform
= platform
[:-1]
746 def _node(default
=''):
748 """ Helper to determine the node name of this machine.
756 return socket
.gethostname()
758 # Still not working...
761 # os.path.abspath is new in Python 1.5.2:
762 if not hasattr(os
.path
,'abspath'):
766 isabs
=os
.path
.isabs
,join
=os
.path
.join
,getcwd
=os
.getcwd
,
767 normpath
=os
.path
.normpath
):
770 path
= join(getcwd(), path
)
771 return normpath(path
)
775 _abspath
= os
.path
.abspath
777 def _follow_symlinks(filepath
):
779 """ In case filepath is a symlink, follow it until a
780 real file is reached.
782 filepath
= _abspath(filepath
)
783 while os
.path
.islink(filepath
):
784 filepath
= os
.path
.normpath(
785 os
.path
.join(filepath
,os
.readlink(filepath
)))
788 def _syscmd_uname(option
,default
=''):
790 """ Interface to the system's uname command.
792 if sys
.platform
in ('dos','win32','win16','os2'):
796 f
= os
.popen('uname %s 2> /dev/null' % option
)
797 except (AttributeError,os
.error
):
799 output
= string
.strip(f
.read())
806 def _syscmd_file(target
,default
=''):
808 """ Interface to the system's file command.
810 The function uses the -b option of the file command to have it
811 ommit the filename in its output and if possible the -L option
812 to have the command follow symlinks. It returns default in
813 case the command should fail.
816 target
= _follow_symlinks(target
)
818 f
= os
.popen('file %s 2> /dev/null' % target
)
819 except (AttributeError,os
.error
):
821 output
= string
.strip(f
.read())
828 ### Information about the used architecture
830 # Default values for architecture; non-empty strings override the
831 # defaults given as parameters
832 _default_architecture
= {
833 'win32': ('','WindowsPE'),
834 'win16': ('','Windows'),
838 _architecture_split
= re
.compile(r
'[\s,]').split
840 def architecture(executable
=sys
.executable
,bits
='',linkage
=''):
842 """ Queries the given executable (defaults to the Python interpreter
843 binary) for various architecture information.
845 Returns a tuple (bits,linkage) which contains information about
846 the bit architecture and the linkage format used for the
847 executable. Both values are returned as strings.
849 Values that cannot be determined are returned as given by the
850 parameter presets. If bits is given as '', the sizeof(pointer)
851 (or sizeof(long) on Python version < 1.5.2) is used as
852 indicator for the supported pointer size.
854 The function relies on the system's "file" command to do the
855 actual work. This is available on most if not all Unix
856 platforms. On some non-Unix platforms where the "file" command
857 does not exist and the executable is set to the Python interpreter
858 binary defaults from _default_architecture are used.
861 # Use the sizeof(pointer) as default number of bits if nothing
862 # else is given as default.
866 size
= struct
.calcsize('P')
868 # Older installations can only query longs
869 size
= struct
.calcsize('l')
870 bits
= str(size
*8) + 'bit'
872 # Get data from the 'file' system command
873 output
= _syscmd_file(executable
,'')
876 executable
== sys
.executable
:
877 # "file" command did not return anything; we'll try to provide
878 # some sensible defaults then...
879 if _default_architecture
.has_key(sys
.platform
):
880 b
,l
= _default_architecture
[sys
.platform
]
887 # Split the output into a list of strings omitting the filename
888 fileout
= _architecture_split(output
)[1:]
890 if 'executable' not in fileout
:
891 # Format not supported
895 if '32-bit' in fileout
:
897 elif 'N32' in fileout
:
900 elif '64-bit' in fileout
:
906 elif 'PE' in fileout
:
907 # E.g. Windows uses this format
908 if 'Windows' in fileout
:
909 linkage
= 'WindowsPE'
912 elif 'COFF' in fileout
:
914 elif 'MS-DOS' in fileout
:
917 # XXX the A.OUT format also falls under this class...
922 ### Portable uname() interface
928 """ Fairly portable uname interface. Returns a tuple
929 of strings (system,node,release,version,machine,processor)
930 identifying the underlying platform.
932 Note that unlike the os.uname function this also returns
933 possible processor information as an additional tuple entry.
935 Entries which cannot be determined are set to ''.
940 if _uname_cache
is not None:
943 # Get some infos from the builtin os.uname API...
945 system
,node
,release
,version
,machine
= os
.uname()
947 except AttributeError:
948 # Hmm, no uname... we'll have to poke around the system then.
949 system
= sys
.platform
957 # Try win32_ver() on win32 platforms
958 if system
== 'win32':
959 release
,version
,csd
,ptype
= win32_ver()
960 if release
and version
:
963 # Try the 'ver' system command available on some
966 system
,release
,version
= _syscmd_ver(system
)
967 # Normalize system to what win32_ver() normally returns
968 # (_syscmd_ver() tends to return the vendor name as well)
969 if system
== 'Microsoft Windows':
972 # In case we still don't know anything useful, we'll try to
974 if system
in ('win32','win16'):
976 if system
== 'win32':
982 elif system
[:4] == 'java':
983 release
,vendor
,vminfo
,osinfo
= java_ver()
985 version
= string
.join(vminfo
,', ')
989 elif os
.name
== 'mac':
990 release
,(version
,stage
,nonrel
),machine
= mac_ver()
994 # System specific extensions
995 if system
== 'OpenVMS':
996 # OpenVMS seems to have release and version mixed up
997 if not release
or release
== '0':
1000 # Get processor information
1006 csid
, cpu_number
= vms_lib
.getsyi('SYI$_CPU',0)
1007 if (cpu_number
>= 128):
1012 # Get processor information from the uname system command
1013 processor
= _syscmd_uname('-p','')
1015 # 'unknown' is not really any useful as information; we'll convert
1016 # it to '' which is more portable
1017 if system
== 'unknown':
1019 if node
== 'unknown':
1021 if release
== 'unknown':
1023 if version
== 'unknown':
1025 if machine
== 'unknown':
1027 if processor
== 'unknown':
1029 _uname_cache
= system
,node
,release
,version
,machine
,processor
1032 ### Direct interfaces to some of the uname() return values
1036 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1038 An empty string is returned if the value cannot be determined.
1045 """ Returns the computer's network name (which may not be fully
1048 An empty string is returned if the value cannot be determined.
1055 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1057 An empty string is returned if the value cannot be determined.
1064 """ Returns the system's release version, e.g. '#3 on degas'
1066 An empty string is returned if the value cannot be determined.
1073 """ Returns the machine type, e.g. 'i386'
1075 An empty string is returned if the value cannot be determined.
1082 """ Returns the (true) processor name, e.g. 'amdk6'
1084 An empty string is returned if the value cannot be
1085 determined. Note that many platforms do not provide this
1086 information or simply return the same value as for machine(),
1087 e.g. NetBSD does this.
1092 ### Various APIs for extracting information from sys.version
1094 _sys_version_parser
= re
.compile(r
'([\w.+]+)\s*'
1095 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1097 _sys_version_cache
= None
1101 """ Returns a parsed version of Python's sys.version as tuple
1102 (version, buildno, builddate, compiler) referring to the Python
1103 version, build number, build date/time as string and the compiler
1104 identification string.
1106 Note that unlike the Python sys.version, the returned value
1107 for the Python version will always include the patchlevel (it
1111 global _sys_version_cache
1113 if _sys_version_cache
is not None:
1114 return _sys_version_cache
1115 version
, buildno
, builddate
, buildtime
, compiler
= \
1116 _sys_version_parser
.match(sys
.version
).groups()
1117 builddate
= builddate
+ ' ' + buildtime
1118 l
= string
.split(version
, '.')
1121 version
= string
.join(l
, '.')
1122 _sys_version_cache
= (version
, buildno
, builddate
, compiler
)
1123 return _sys_version_cache
1125 def python_version():
1127 """ Returns the Python version as string 'major.minor.patchlevel'
1129 Note that unlike the Python sys.version, the returned value
1130 will always include the patchlevel (it defaults to 0).
1133 return _sys_version()[0]
1135 def python_version_tuple():
1137 """ Returns the Python version as tuple (major, minor, patchlevel)
1140 Note that unlike the Python sys.version, the returned value
1141 will always include the patchlevel (it defaults to 0).
1144 return string
.split(_sys_version()[0], '.')
1148 """ Returns a tuple (buildno, builddate) stating the Python
1149 build number and date as strings.
1152 return _sys_version()[1:3]
1154 def python_compiler():
1156 """ Returns a string identifying the compiler used for compiling
1160 return _sys_version()[3]
1162 ### The Opus Magnum of platform strings :-)
1164 _platform_cache
= {}
1166 def platform(aliased
=0, terse
=0):
1168 """ Returns a single string identifying the underlying platform
1169 with as much useful information as possible (but no more :).
1171 The output is intended to be human readable rather than
1172 machine parseable. It may look different on different
1173 platforms and this is intended.
1175 If "aliased" is true, the function will use aliases for
1176 various platforms that report system names which differ from
1177 their common names, e.g. SunOS will be reported as
1178 Solaris. The system_alias() function is used to implement
1181 Setting terse to true causes the function to return only the
1182 absolute minimum information needed to identify the platform.
1185 result
= _platform_cache
.get((aliased
, terse
), None)
1186 if result
is not None:
1189 # Get uname information and then apply platform specific cosmetics
1191 system
,node
,release
,version
,machine
,processor
= uname()
1192 if machine
== processor
:
1195 system
,release
,version
= system_alias(system
,release
,version
)
1197 if system
== 'Windows':
1199 rel
,vers
,csd
,ptype
= win32_ver(version
)
1201 platform
= _platform(system
,release
)
1203 platform
= _platform(system
,release
,version
,csd
)
1205 elif system
in ('Linux',):
1206 # Linux based systems
1207 distname
,distversion
,distid
= dist('')
1208 if distname
and not terse
:
1209 platform
= _platform(system
,release
,machine
,processor
,
1211 distname
,distversion
,distid
)
1213 # If the distribution name is unknown check for libc vs. glibc
1214 libcname
,libcversion
= libc_ver(sys
.executable
)
1215 platform
= _platform(system
,release
,machine
,processor
,
1217 libcname
+libcversion
)
1218 elif system
== 'Java':
1220 r
,v
,vminfo
,(os_name
,os_version
,os_arch
) = java_ver()
1222 platform
= _platform(system
,release
,version
)
1224 platform
= _platform(system
,release
,version
,
1226 os_name
,os_version
,os_arch
)
1228 elif system
== 'MacOS':
1231 platform
= _platform(system
,release
)
1233 platform
= _platform(system
,release
,machine
)
1238 platform
= _platform(system
,release
)
1240 bits
,linkage
= architecture(sys
.executable
)
1241 platform
= _platform(system
,release
,machine
,processor
,bits
,linkage
)
1243 _platform_cache
[(aliased
, terse
)] = platform
1246 ### Command line interface
1248 if __name__
== '__main__':
1249 # Default is to print the aliased verbose platform string
1250 terse
= ('terse' in sys
.argv
or '--terse' in sys
.argv
)
1251 aliased
= (not 'nonaliased' in sys
.argv
and not '--nonaliased' in sys
.argv
)
1252 print platform(aliased
,terse
)