ยปCore Development>Code coverage>Lib/platform.py

Python code coverage for Lib/platform.py

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