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".
16
# * more support for WinCE
17
# * support for MS-DOS (PythonDX ?)
18
# * support for Amiga and other still unsupported platforms running Python
19
# * support for additional Linux distributions
21
# Many thanks to all those who helped adding platform-specific
22
# checks (in no particular order):
24
# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
25
# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
26
# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
27
# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
28
# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
29
# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
33
# <see CVS and SVN checkin messages for history>
35
# 1.0.7 - added DEV_NULL
36
# 1.0.6 - added linux_distribution()
37
# 1.0.5 - fixed Java support to allow running the module on Jython
38
# 1.0.4 - added IronPython support
39
# 1.0.3 - added normalization of Windows system name
40
# 1.0.2 - added more Windows support
41
# 1.0.1 - reformatted to make doc.py happy
42
# 1.0.0 - reformatted a bit and checked into Python CVS
43
# 0.8.0 - added sys.version parser and various new access
44
# APIs (python_version(), python_compiler(), etc.)
45
# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
46
# 0.7.1 - added support for Caldera OpenLinux
47
# 0.7.0 - some fixes for WinCE; untabified the source file
48
# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
49
# vms_lib.getsyi() configured
50
# 0.6.1 - added code to prevent 'uname -p' on platforms which are
51
# known not to support it
52
# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
53
# did some cleanup of the interfaces - some APIs have changed
54
# 0.5.5 - fixed another type in the MacOS code... should have
55
# used more coffee today ;-)
56
# 0.5.4 - fixed a few typos in the MacOS code
57
# 0.5.3 - added experimental MacOS support; added better popen()
58
# workarounds in _syscmd_ver() -- still not 100% elegant
60
# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
61
# return values (the system uname command tends to return
62
# 'unknown' instead of just leaving the field emtpy)
63
# 0.5.1 - included code for slackware dist; added exception handlers
64
# to cover up situations where platforms don't have os.popen
65
# (e.g. Mac) or fail on socket.gethostname(); fixed libc
67
# 0.5.0 - changed the API names referring to system commands to *syscmd*;
68
# added java_ver(); made syscmd_ver() a private
69
# API (was system_ver() in previous versions) -- use uname()
70
# instead; extended the win32_ver() to also return processor
72
# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
73
# 0.3.4 - fixed a bug in _follow_symlinks()
74
# 0.3.3 - fixed popen() and "file" command invokation bugs
75
# 0.3.2 - added architecture() API and support for it in platform()
76
# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
77
# 0.3.0 - added system alias support
78
# 0.2.3 - removed 'wince' again... oh well.
79
# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
80
# 0.2.1 - added cache logic and changed the platform string format
81
# 0.2.0 - changed the API to use functions instead of module globals
82
# since some action take too long to be run on module import
83
# 0.1.0 - first release
85
# You can always get the latest version of this module at:
87
# http://www.egenix.com/files/python/platform.py
89
# If that URL should fail, try contacting the author.
92
Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
93
Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
95
Permission to use, copy, modify, and distribute this software and its
96
documentation for any purpose and without fee or royalty is hereby granted,
97
provided that the above copyright notice appear in all copies and that
98
both that copyright notice and this permission notice appear in
99
supporting documentation or portions thereof, including modifications,
102
EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
103
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
104
FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
105
INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
106
FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
107
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
108
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
112
__version__ = '1.0.7'
115
import sys, os, re, subprocess
117
### Globals & Constants
119
# Determine the platform's /dev/null device
121
DEV_NULL = os.devnull
122
except AttributeError:
123
# os.devnull was added in Python 2.4, so emulate it for earlier
125
if sys.platform in ('dos','win32','win16'):
126
# Use the old CP/M NUL as device name
129
# Standard Unix uses /dev/null
130
DEV_NULL = '/dev/null'
132
### Platform specific APIs
134
_libc_search = re.compile(b'(__libc_init)'
138
br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
140
def libc_ver(executable=sys.executable,lib='',version='',
144
""" Tries to determine the libc version that the file executable
145
(which defaults to the Python interpreter) is linked against.
147
Returns a tuple of strings (lib,version) which default to the
148
given parameters in case the lookup fails.
150
Note that the function has intimate knowledge of how different
151
libc versions add symbols to the executable and thus is probably
152
only useable for executables compiled using gcc.
154
The file is read and scanned in chunks of chunksize bytes.
157
if hasattr(os.path, 'realpath'):
158
# Python 2.2 introduced os.path.realpath(); it is used
159
# here to work around problems with Cygwin not being
160
# able to open symlinks for reading
161
executable = os.path.realpath(executable)
162
f = open(executable,'rb')
163
binary = f.read(chunksize)
166
if b'libc' in binary or b'GLIBC' in binary:
167
m = _libc_search.search(binary,pos)
171
binary = f.read(chunksize)
176
libcinit,glibc,glibcversion,so,threads,soversion = [
177
s.decode('latin1') if s is not None else s
179
if libcinit and not lib:
184
version = glibcversion
185
elif glibcversion > version:
186
version = glibcversion
190
if soversion and soversion > version:
192
if threads and version[-len(threads):] != threads:
193
version = version + threads
198
def _dist_try_harder(distname,version,id):
200
""" Tries some special tricks to get the distribution
201
information in case the default method fails.
203
Currently supports older SuSE Linux, Caldera OpenLinux and
204
Slackware Linux distributions.
207
if os.path.exists('/var/adm/inst-log/info'):
208
# SuSE Linux stores distribution information in that file
210
for line in open('/var/adm/inst-log/info'):
216
if tag == 'MIN_DIST_VERSION':
217
version = value.strip()
218
elif tag == 'DIST_IDENT':
219
values = value.split('-')
221
return distname,version,id
223
if os.path.exists('/etc/.installed'):
224
# Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
225
for line in open('/etc/.installed'):
226
pkg = line.split('-')
227
if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
228
# XXX does Caldera support non Intel platforms ? If yes,
229
# where can we find the needed id ?
230
return 'OpenLinux',pkg[1],id
232
if os.path.isdir('/usr/lib/setup'):
233
# Check for slackware version tag file (thanks to Greg Andruk)
234
verfiles = os.listdir('/usr/lib/setup')
235
for n in range(len(verfiles)-1, -1, -1):
236
if verfiles[n][:14] != 'slack-version-':
240
distname = 'slackware'
241
version = verfiles[-1][14:]
242
return distname,version,id
244
return distname,version,id
246
_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
247
_lsb_release_version = re.compile(r'(.+)'
250
'[^(]*(?:\((.+)\))?', re.ASCII)
251
_release_version = re.compile(r'([^0-9]+)'
254
'[^(]*(?:\((.+)\))?', re.ASCII)
256
# See also http://www.novell.com/coolsolutions/feature/11251.html
257
# and http://linuxmafia.com/faq/Admin/release-files.html
258
# and http://data.linux-ntfs.org/rpm/whichrpm
259
# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
262
'SuSE', 'debian', 'fedora', 'redhat', 'centos',
263
'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
264
'UnitedLinux', 'turbolinux', 'arch', 'mageia')
266
def _parse_release_file(firstline):
268
# Default to empty 'version' and 'id' strings. Both defaults are used
269
# when 'firstline' is empty. 'id' defaults to empty when an id can not
274
# Parse the first line
275
m = _lsb_release_version.match(firstline)
277
# LSB format: "distro release x.x (codename)"
278
return tuple(m.groups())
280
# Pre-LSB format: "distro x.x (codename)"
281
m = _release_version.match(firstline)
283
return tuple(m.groups())
285
# Unknown format... take the first two words
286
l = firstline.strip().split()
291
return '', version, id
293
def linux_distribution(distname='', version='', id='',
295
supported_dists=_supported_dists,
296
full_distribution_name=1):
298
""" Tries to determine the name of the Linux OS distribution name.
300
The function first looks for a distribution release file in
301
/etc and then reverts to _dist_try_harder() in case no
302
suitable files are found.
304
supported_dists may be given to define the set of Linux
305
distributions to look for. It defaults to a list of currently
306
supported Linux distributions identified by their release file
309
If full_distribution_name is true (default), the full
310
distribution read from the OS is returned. Otherwise the short
311
name taken from supported_dists is used.
313
Returns a tuple (distname,version,id) which default to the
314
args given as parameters.
318
etc = os.listdir('/etc')
320
# Probably not a Unix system
321
return distname,version,id
324
m = _release_filename.match(file)
326
_distname,dummy = m.groups()
327
if _distname in supported_dists:
331
return _dist_try_harder(distname,version,id)
333
# Read the first line
334
with open('/etc/'+file, 'r') as f:
335
firstline = f.readline()
336
_distname, _version, _id = _parse_release_file(firstline)
338
if _distname and full_distribution_name:
344
return distname, version, id
346
# To maintain backwards compatibility:
348
def dist(distname='',version='',id='',
350
supported_dists=_supported_dists):
352
""" Tries to determine the name of the Linux OS distribution name.
354
The function first looks for a distribution release file in
355
/etc and then reverts to _dist_try_harder() in case no
356
suitable files are found.
358
Returns a tuple (distname,version,id) which default to the
359
args given as parameters.
362
return linux_distribution(distname, version, id,
363
supported_dists=supported_dists,
364
full_distribution_name=0)
366
def popen(cmd, mode='r', bufsize=-1):
368
""" Portable popen() interface.
371
warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
372
return os.popen(cmd, mode, bufsize)
374
def _norm_version(version, build=''):
376
""" Normalize the version and build strings and return a single
377
version string using the format major.minor.build (or patchlevel).
379
l = version.split('.')
387
strings = list(map(str,ints))
388
version = '.'.join(strings[:3])
391
_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
395
# Examples of VER command output:
397
# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
398
# Windows XP: Microsoft Windows XP [Version 5.1.2600]
399
# Windows Vista: Microsoft Windows [Version 6.0.6002]
401
# Note that the "Version" string gets localized on different
404
def _syscmd_ver(system='', release='', version='',
406
supported_platforms=('win32','win16','dos')):
408
""" Tries to figure out the OS version used and returns
409
a tuple (system,release,version).
411
It uses the "ver" shell command for this which is known
412
to exists on Windows, DOS. XXX Others too ?
414
In case this fails, the given parameters are used as
418
if sys.platform not in supported_platforms:
419
return system,release,version
421
# Try some common cmd strings
422
for cmd in ('ver','command /c ver','cmd /c ver'):
427
raise OSError('command failed')
428
# XXX How can I suppress shell errors from being written
430
except OSError as why:
431
#print 'Command %s failed: %s' % (cmd,why)
436
return system,release,version
440
m = _ver_output.match(info)
442
system,release,version = m.groups()
443
# Strip trailing dots from version and release
444
if release[-1] == '.':
445
release = release[:-1]
446
if version[-1] == '.':
447
version = version[:-1]
448
# Normalize the version and build strings (eliminating additional
450
version = _norm_version(version)
451
return system,release,version
453
def _win32_getvalue(key,name,default=''):
455
""" Read a value for name from the registry key.
457
In case this fails, default is returned.
461
# Use win32api if available
462
from win32api import RegQueryValueEx
464
# On Python 2.0 and later, emulate using winreg
466
RegQueryValueEx = winreg.QueryValueEx
468
return RegQueryValueEx(key,name)
472
def win32_ver(release='',version='',csd='',ptype=''):
474
""" Get additional version information from the Windows Registry
475
and return a tuple (version,csd,ptype) referring to version
476
number, CSD level (service pack), and OS type (multi/single
479
As a hint: ptype returns 'Uniprocessor Free' on single
480
processor NT machines and 'Multiprocessor Free' on multi
481
processor machines. The 'Free' refers to the OS version being
482
free of debugging code. It could also state 'Checked' which
483
means the OS version uses debugging code, i.e. code that
484
checks arguments, ranges, etc. (Thomas Heller).
486
Note: this function works best with Mark Hammond's win32
487
package installed, but also on Python 2.3 and later. It
488
obviously only runs on Win32 compatible platforms.
491
# XXX Is there any way to find out the processor type on WinXX ?
492
# XXX Is win32 available on Windows CE ?
494
# Adapted from code posted by Karl Putland to comp.lang.python.
496
# The mappings between reg. values and release names can be found
497
# here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
499
# Import the needed APIs
502
from win32api import RegQueryValueEx, RegOpenKeyEx, \
503
RegCloseKey, GetVersionEx
504
from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
505
VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
507
# Emulate the win32api module using Python APIs
509
sys.getwindowsversion
510
except AttributeError:
511
# No emulation possible, so return the defaults...
512
return release,version,csd,ptype
514
# Emulation using winreg (added in Python 2.0) and
515
# sys.getwindowsversion() (added in Python 2.3)
517
GetVersionEx = sys.getwindowsversion
518
RegQueryValueEx = winreg.QueryValueEx
519
RegOpenKeyEx = winreg.OpenKeyEx
520
RegCloseKey = winreg.CloseKey
521
HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
522
VER_PLATFORM_WIN32_WINDOWS = 1
523
VER_PLATFORM_WIN32_NT = 2
524
VER_NT_WORKSTATION = 1
528
# Find out the registry key and some general version infos
529
winver = GetVersionEx()
530
maj,min,buildno,plat,csd = winver
531
version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
532
if hasattr(winver, "service_pack"):
533
if winver.service_pack != "":
534
csd = 'SP%s' % winver.service_pack_major
536
if csd[:13] == 'Service Pack ':
537
csd = 'SP' + csd[13:]
539
if plat == VER_PLATFORM_WIN32_WINDOWS:
540
regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
541
# Try to guess the release name
554
elif plat == VER_PLATFORM_WIN32_NT:
555
regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
564
release = '2003Server'
568
if hasattr(winver, "product_type"):
569
product_type = winver.product_type
571
product_type = VER_NT_WORKSTATION
572
# Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
573
# or help from the registry, we cannot properly identify
574
# non-workstation versions.
576
key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
577
name, type = RegQueryValueEx(key, "ProductName")
578
# Discard any type that isn't REG_SZ
579
if type == REG_SZ and name.find("Server") != -1:
580
product_type = VER_NT_SERVER
582
# Use default of VER_NT_WORKSTATION
586
if product_type == VER_NT_WORKSTATION:
589
release = '2008Server'
591
if product_type == VER_NT_WORKSTATION:
594
release = '2008ServerR2'
596
if product_type == VER_NT_WORKSTATION:
599
release = '2012Server'
601
release = 'post2012Server'
605
# E.g. Win3.1 with win32s
606
release = '%i.%i' % (maj,min)
607
return release,version,csd,ptype
609
# Open the registry key
611
keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
612
# Get a value to make sure the key exists...
613
RegQueryValueEx(keyCurVer, 'SystemRoot')
615
return release,version,csd,ptype
618
#subversion = _win32_getvalue(keyCurVer,
619
# 'SubVersionNumber',
622
# release = release + subversion # 95a, 95b, etc.
623
build = _win32_getvalue(keyCurVer,
624
'CurrentBuildNumber',
626
ptype = _win32_getvalue(keyCurVer,
631
version = _norm_version(version,build)
634
RegCloseKey(keyCurVer)
635
return release,version,csd,ptype
638
fn = '/System/Library/CoreServices/SystemVersion.plist'
639
if not os.path.exists(fn):
647
pl = plistlib.readPlist(fn)
648
release = pl['ProductVersion']
649
versioninfo=('', '', '')
650
machine = os.uname().machine
651
if machine in ('ppc', 'Power Macintosh'):
655
return release,versioninfo,machine
658
def mac_ver(release='',versioninfo=('','',''),machine=''):
660
""" Get MacOS version information and return it as tuple (release,
661
versioninfo, machine) with versioninfo being a tuple (version,
662
dev_stage, non_release_version).
664
Entries which cannot be determined are set to the parameter values
665
which default to ''. All tuple entries are strings.
668
# First try reading the information from an XML file which should
670
info = _mac_ver_xml()
674
# If that also doesn't work return the default values
675
return release,versioninfo,machine
677
def _java_getprop(name,default):
679
from java.lang import System
681
value = System.getProperty(name)
685
except AttributeError:
688
def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
690
""" Version interface for Jython.
692
Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
693
a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
694
tuple (os_name,os_version,os_arch).
696
Values which cannot be determined are set to the defaults
697
given as parameters (which all default to '').
700
# Import the needed APIs
704
return release,vendor,vminfo,osinfo
706
vendor = _java_getprop('java.vendor', vendor)
707
release = _java_getprop('java.version', release)
708
vm_name, vm_release, vm_vendor = vminfo
709
vm_name = _java_getprop('java.vm.name', vm_name)
710
vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
711
vm_release = _java_getprop('java.vm.version', vm_release)
712
vminfo = vm_name, vm_release, vm_vendor
713
os_name, os_version, os_arch = osinfo
714
os_arch = _java_getprop('java.os.arch', os_arch)
715
os_name = _java_getprop('java.os.name', os_name)
716
os_version = _java_getprop('java.os.version', os_version)
717
osinfo = os_name, os_version, os_arch
719
return release, vendor, vminfo, osinfo
721
### System name aliasing
723
def system_alias(system,release,version):
725
""" Returns (system,release,version) aliased to common
726
marketing names used for some systems.
728
It also does some reordering of the information in some cases
729
where it would otherwise cause confusion.
732
if system == 'Rhapsody':
733
# Apple's BSD derivative
734
# XXX How can we determine the marketing release number ?
735
return 'MacOS X Server',system+release,version
737
elif system == 'SunOS':
740
# These releases use the old name SunOS
741
return system,release,version
742
# Modify release (marketing release = SunOS release - 3)
743
l = release.split('.')
752
release = '.'.join(l)
756
# XXX Whatever the new SunOS marketing name is...
759
elif system == 'IRIX64':
760
# IRIX reports IRIX64 on platforms with 64-bit support; yet it
761
# is really a version and not a different platform, since 32-bit
762
# apps are also supported..
765
version = version + ' (64bit)'
769
elif system in ('win32','win16'):
770
# In case one of the other tricks
773
return system,release,version
775
### Various internal helpers
777
def _platform(*args):
779
""" Helper to format the platform string in a filename
780
compatible format e.g. "system-version-machine".
782
# Format the platform string
783
platform = '-'.join(x.strip() for x in filter(len, args))
785
# Cleanup some possible filename obstacles...
786
platform = platform.replace(' ','_')
787
platform = platform.replace('/','-')
788
platform = platform.replace('\\','-')
789
platform = platform.replace(':','-')
790
platform = platform.replace(';','-')
791
platform = platform.replace('"','-')
792
platform = platform.replace('(','-')
793
platform = platform.replace(')','-')
795
# No need to report 'unknown' information...
796
platform = platform.replace('unknown','')
798
# Fold '--'s and remove trailing '-'
800
cleaned = platform.replace('--','-')
801
if cleaned == platform:
804
while platform[-1] == '-':
805
platform = platform[:-1]
809
def _node(default=''):
811
""" Helper to determine the node name of this machine.
819
return socket.gethostname()
821
# Still not working...
824
def _follow_symlinks(filepath):
826
""" In case filepath is a symlink, follow it until a
827
real file is reached.
829
filepath = os.path.abspath(filepath)
830
while os.path.islink(filepath):
831
filepath = os.path.normpath(
832
os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
835
def _syscmd_uname(option,default=''):
837
""" Interface to the system's uname command.
839
if sys.platform in ('dos','win32','win16'):
843
f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
844
except (AttributeError, OSError):
846
output = f.read().strip()
853
def _syscmd_file(target,default=''):
855
""" Interface to the system's file command.
857
The function uses the -b option of the file command to have it
858
omit the filename in its output. Follow the symlinks. It returns
859
default in case the command should fail.
862
if sys.platform in ('dos','win32','win16'):
865
target = _follow_symlinks(target)
867
proc = subprocess.Popen(['file', target],
868
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
870
except (AttributeError, OSError):
872
output = proc.communicate()[0].decode('latin-1')
879
### Information about the used architecture
881
# Default values for architecture; non-empty strings override the
882
# defaults given as parameters
883
_default_architecture = {
884
'win32': ('','WindowsPE'),
885
'win16': ('','Windows'),
889
def architecture(executable=sys.executable,bits='',linkage=''):
891
""" Queries the given executable (defaults to the Python interpreter
892
binary) for various architecture information.
894
Returns a tuple (bits,linkage) which contains information about
895
the bit architecture and the linkage format used for the
896
executable. Both values are returned as strings.
898
Values that cannot be determined are returned as given by the
899
parameter presets. If bits is given as '', the sizeof(pointer)
900
(or sizeof(long) on Python version < 1.5.2) is used as
901
indicator for the supported pointer size.
903
The function relies on the system's "file" command to do the
904
actual work. This is available on most if not all Unix
905
platforms. On some non-Unix platforms where the "file" command
906
does not exist and the executable is set to the Python interpreter
907
binary defaults from _default_architecture are used.
910
# Use the sizeof(pointer) as default number of bits if nothing
911
# else is given as default.
915
size = struct.calcsize('P')
917
# Older installations can only query longs
918
size = struct.calcsize('l')
919
bits = str(size*8) + 'bit'
921
# Get data from the 'file' system command
923
fileout = _syscmd_file(executable, '')
928
executable == sys.executable:
929
# "file" command did not return anything; we'll try to provide
930
# some sensible defaults then...
931
if sys.platform in _default_architecture:
932
b,l = _default_architecture[sys.platform]
939
if 'executable' not in fileout:
940
# Format not supported
944
if '32-bit' in fileout:
946
elif 'N32' in fileout:
949
elif '64-bit' in fileout:
955
elif 'PE' in fileout:
956
# E.g. Windows uses this format
957
if 'Windows' in fileout:
958
linkage = 'WindowsPE'
961
elif 'COFF' in fileout:
963
elif 'MS-DOS' in fileout:
966
# XXX the A.OUT format also falls under this class...
971
### Portable uname() interface
973
uname_result = collections.namedtuple("uname_result",
974
"system node release version machine processor")
980
""" Fairly portable uname interface. Returns a tuple
981
of strings (system,node,release,version,machine,processor)
982
identifying the underlying platform.
984
Note that unlike the os.uname function this also returns
985
possible processor information as an additional tuple entry.
987
Entries which cannot be determined are set to ''.
993
if _uname_cache is not None:
998
# Get some infos from the builtin os.uname API...
1000
system,node,release,version,machine = os.uname()
1001
except AttributeError:
1004
if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
1005
# Hmm, no there is either no uname or uname has returned
1006
#'unknowns'... we'll have to poke around the system then.
1008
system = sys.platform
1016
# Try win32_ver() on win32 platforms
1017
if system == 'win32':
1018
release,version,csd,ptype = win32_ver()
1019
if release and version:
1021
# Try to use the PROCESSOR_* environment variables
1022
# available on Win XP and later; see
1023
# http://support.microsoft.com/kb/888731 and
1024
# http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
1026
# WOW64 processes mask the native architecture
1027
if "PROCESSOR_ARCHITEW6432" in os.environ:
1028
machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1030
machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1032
processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
1034
# Try the 'ver' system command available on some
1037
system,release,version = _syscmd_ver(system)
1038
# Normalize system to what win32_ver() normally returns
1039
# (_syscmd_ver() tends to return the vendor name as well)
1040
if system == 'Microsoft Windows':
1042
elif system == 'Microsoft' and release == 'Windows':
1043
# Under Windows Vista and Windows Server 2008,
1044
# Microsoft changed the output of the ver command. The
1045
# release is no longer printed. This causes the
1046
# system and release to be misidentified.
1048
if '6.0' == version[:3]:
1053
# In case we still don't know anything useful, we'll try to
1055
if system in ('win32','win16'):
1057
if system == 'win32':
1063
elif system[:4] == 'java':
1064
release,vendor,vminfo,osinfo = java_ver()
1066
version = ', '.join(vminfo)
1070
# System specific extensions
1071
if system == 'OpenVMS':
1072
# OpenVMS seems to have release and version mixed up
1073
if not release or release == '0':
1076
# Get processor information
1082
csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1083
if (cpu_number >= 128):
1088
# Get processor information from the uname system command
1089
processor = _syscmd_uname('-p','')
1091
#If any unknowns still exist, replace them with ''s, which are more portable
1092
if system == 'unknown':
1094
if node == 'unknown':
1096
if release == 'unknown':
1098
if version == 'unknown':
1100
if machine == 'unknown':
1102
if processor == 'unknown':
1106
if system == 'Microsoft' and release == 'Windows':
1110
_uname_cache = uname_result(system,node,release,version,machine,processor)
1113
### Direct interfaces to some of the uname() return values
1117
""" Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1119
An empty string is returned if the value cannot be determined.
1122
return uname().system
1126
""" Returns the computer's network name (which may not be fully
1129
An empty string is returned if the value cannot be determined.
1136
""" Returns the system's release, e.g. '2.2.0' or 'NT'
1138
An empty string is returned if the value cannot be determined.
1141
return uname().release
1145
""" Returns the system's release version, e.g. '#3 on degas'
1147
An empty string is returned if the value cannot be determined.
1150
return uname().version
1154
""" Returns the machine type, e.g. 'i386'
1156
An empty string is returned if the value cannot be determined.
1159
return uname().machine
1163
""" Returns the (true) processor name, e.g. 'amdk6'
1165
An empty string is returned if the value cannot be
1166
determined. Note that many platforms do not provide this
1167
information or simply return the same value as for machine(),
1168
e.g. NetBSD does this.
1171
return uname().processor
1173
### Various APIs for extracting information from sys.version
1175
_sys_version_parser = re.compile(
1177
'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1178
'\[([^\]]+)\]?', re.ASCII)
1180
_ironpython_sys_version_parser = re.compile(
1183
'(?: \(([\d\.]+)\))?'
1184
' on (.NET [\d\.]+)', re.ASCII)
1186
# IronPython covering 2.6 and 2.7
1187
_ironpython26_sys_version_parser = re.compile(
1191
'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1194
_pypy_sys_version_parser = re.compile(
1196
'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1199
_sys_version_cache = {}
1201
def _sys_version(sys_version=None):
1203
""" Returns a parsed version of Python's sys.version as tuple
1204
(name, version, branch, revision, buildno, builddate, compiler)
1205
referring to the Python implementation name, version, branch,
1206
revision, build number, build date/time as string and the compiler
1207
identification string.
1209
Note that unlike the Python sys.version, the returned value
1210
for the Python version will always include the patchlevel (it
1213
The function returns empty strings for tuple entries that
1214
cannot be determined.
1216
sys_version may be given to parse an alternative version
1217
string, e.g. if the version was read from a different Python
1221
# Get the Python version
1222
if sys_version is None:
1223
sys_version = sys.version
1225
# Try the cache first
1226
result = _sys_version_cache.get(sys_version, None)
1227
if result is not None:
1231
if 'IronPython' in sys_version:
1234
if sys_version.startswith('IronPython'):
1235
match = _ironpython_sys_version_parser.match(sys_version)
1237
match = _ironpython26_sys_version_parser.match(sys_version)
1241
'failed to parse IronPython sys.version: %s' %
1244
version, alt_version, compiler = match.groups()
1248
elif sys.platform.startswith('java'):
1251
match = _sys_version_parser.match(sys_version)
1254
'failed to parse Jython sys.version: %s' %
1256
version, buildno, builddate, buildtime, _ = match.groups()
1257
compiler = sys.platform
1259
elif "PyPy" in sys_version:
1262
match = _pypy_sys_version_parser.match(sys_version)
1264
raise ValueError("failed to parse PyPy sys.version: %s" %
1266
version, buildno, builddate, buildtime = match.groups()
1271
match = _sys_version_parser.match(sys_version)
1274
'failed to parse CPython sys.version: %s' %
1276
version, buildno, builddate, buildtime, compiler = \
1279
builddate = builddate + ' ' + buildtime
1281
if hasattr(sys, '_mercurial'):
1282
_, branch, revision = sys._mercurial
1283
elif hasattr(sys, 'subversion'):
1284
# sys.subversion was added in Python 2.5
1285
_, branch, revision = sys.subversion
1290
# Add the patchlevel version if missing
1291
l = version.split('.')
1294
version = '.'.join(l)
1296
# Build and cache the result
1297
result = (name, version, branch, revision, buildno, builddate, compiler)
1298
_sys_version_cache[sys_version] = result
1301
def python_implementation():
1303
""" Returns a string identifying the Python implementation.
1305
Currently, the following implementations are identified:
1306
'CPython' (C implementation of Python),
1307
'IronPython' (.NET implementation of Python),
1308
'Jython' (Java implementation of Python),
1309
'PyPy' (Python implementation of Python).
1312
return _sys_version()[0]
1314
def python_version():
1316
""" Returns the Python version as string 'major.minor.patchlevel'
1318
Note that unlike the Python sys.version, the returned value
1319
will always include the patchlevel (it defaults to 0).
1322
return _sys_version()[1]
1324
def python_version_tuple():
1326
""" Returns the Python version as tuple (major, minor, patchlevel)
1329
Note that unlike the Python sys.version, the returned value
1330
will always include the patchlevel (it defaults to 0).
1333
return tuple(_sys_version()[1].split('.'))
1335
def python_branch():
1337
""" Returns a string identifying the Python implementation
1340
For CPython this is the Subversion branch from which the
1341
Python binary was built.
1343
If not available, an empty string is returned.
1347
return _sys_version()[2]
1349
def python_revision():
1351
""" Returns a string identifying the Python implementation
1354
For CPython this is the Subversion revision from which the
1355
Python binary was built.
1357
If not available, an empty string is returned.
1360
return _sys_version()[3]
1364
""" Returns a tuple (buildno, builddate) stating the Python
1365
build number and date as strings.
1368
return _sys_version()[4:6]
1370
def python_compiler():
1372
""" Returns a string identifying the compiler used for compiling
1376
return _sys_version()[6]
1378
### The Opus Magnum of platform strings :-)
1380
_platform_cache = {}
1382
def platform(aliased=0, terse=0):
1384
""" Returns a single string identifying the underlying platform
1385
with as much useful information as possible (but no more :).
1387
The output is intended to be human readable rather than
1388
machine parseable. It may look different on different
1389
platforms and this is intended.
1391
If "aliased" is true, the function will use aliases for
1392
various platforms that report system names which differ from
1393
their common names, e.g. SunOS will be reported as
1394
Solaris. The system_alias() function is used to implement
1397
Setting terse to true causes the function to return only the
1398
absolute minimum information needed to identify the platform.
1401
result = _platform_cache.get((aliased, terse), None)
1402
if result is not None:
1405
# Get uname information and then apply platform specific cosmetics
1407
system,node,release,version,machine,processor = uname()
1408
if machine == processor:
1411
system,release,version = system_alias(system,release,version)
1413
if system == 'Windows':
1415
rel,vers,csd,ptype = win32_ver(version)
1417
platform = _platform(system,release)
1419
platform = _platform(system,release,version,csd)
1421
elif system in ('Linux',):
1422
# Linux based systems
1423
distname,distversion,distid = dist('')
1424
if distname and not terse:
1425
platform = _platform(system,release,machine,processor,
1427
distname,distversion,distid)
1429
# If the distribution name is unknown check for libc vs. glibc
1430
libcname,libcversion = libc_ver(sys.executable)
1431
platform = _platform(system,release,machine,processor,
1433
libcname+libcversion)
1434
elif system == 'Java':
1436
r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
1437
if terse or not os_name:
1438
platform = _platform(system,release,version)
1440
platform = _platform(system,release,version,
1442
os_name,os_version,os_arch)
1444
elif system == 'MacOS':
1447
platform = _platform(system,release)
1449
platform = _platform(system,release,machine)
1454
platform = _platform(system,release)
1456
bits,linkage = architecture(sys.executable)
1457
platform = _platform(system,release,machine,processor,bits,linkage)
1459
_platform_cache[(aliased, terse)] = platform
1462
### Command line interface
1464
if __name__ == '__main__':
1465
# Default is to print the aliased verbose platform string
1466
terse = ('terse' in sys.argv or '--terse' in sys.argv)
1467
aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1468
print(platform(aliased,terse))