summaryrefslogtreecommitdiff
path: root/Lib/platform.py
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2020-04-16 08:28:09 -0400
committerGitHub <noreply@github.com>2020-04-16 08:28:09 -0400
commit518835f3354d6672e61c9f52348c1e4a2533ea00 (patch)
tree870820aa95948c58a6616795f266c290f0432a65 /Lib/platform.py
parent6a5bf15c71a1c101c28774ae714b58e8a65b130c (diff)
downloadcpython-git-518835f3354d6672e61c9f52348c1e4a2533ea00.tar.gz
bpo-35967 resolve platform.processor late (GH-12239)
* Replace flag-flip indirection with direct inspection * Use any for simpler code * Avoid flag flip and set results directly. * Resolve processor in a single function. * Extract processor handling into a namespace (class) * Remove _syscmd_uname, unused * Restore platform.processor behavior to match prior expectation (reliant on uname -p in a subprocess). * Extract '_unknown_as_blank' function. * Override uname_result to resolve the processor late. * Add a test intended to capture the expected values from 'uname -p' * Instead of trying to keep track of all of the possible outputs on different systems (probably a fool's errand), simply assert that except for the known platform variance, uname().processor matches the output of 'uname -p' * Use a skipIf directive * Use contextlib.suppress to suppress the error. Inline strip call. * 📜🤖 Added by blurb_it. * Remove use of contextlib.suppress (it would fail with NameError if it had any effect). Rely on _unknown_as_blank to replace unknown with blank. Co-authored-by: blurb-it[bot] <blurb-it[bot]@users.noreply.github.com>
Diffstat (limited to 'Lib/platform.py')
-rwxr-xr-xLib/platform.py172
1 files changed, 93 insertions, 79 deletions
diff --git a/Lib/platform.py b/Lib/platform.py
index ed41edc98f..3f442ef0fb 100755
--- a/Lib/platform.py
+++ b/Lib/platform.py
@@ -116,6 +116,9 @@ import collections
import os
import re
import sys
+import subprocess
+import functools
+import itertools
### Globals & Constants
@@ -600,22 +603,6 @@ def _follow_symlinks(filepath):
os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
return filepath
-def _syscmd_uname(option, default=''):
-
- """ Interface to the system's uname command.
- """
- if sys.platform in ('dos', 'win32', 'win16'):
- # XXX Others too ?
- return default
-
- import subprocess
- try:
- output = subprocess.check_output(('uname', option),
- stderr=subprocess.DEVNULL,
- text=True)
- except (OSError, subprocess.CalledProcessError):
- return default
- return (output.strip() or default)
def _syscmd_file(target, default=''):
@@ -736,13 +723,89 @@ def architecture(executable=sys.executable, bits='', linkage=''):
return bits, linkage
+
+def _get_machine_win32():
+ # Try to use the PROCESSOR_* environment variables
+ # available on Win XP and later; see
+ # http://support.microsoft.com/kb/888731 and
+ # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
+
+ # WOW64 processes mask the native architecture
+ return (
+ os.environ.get('PROCESSOR_ARCHITEW6432', '') or
+ os.environ.get('PROCESSOR_ARCHITECTURE', '')
+ )
+
+
+class _Processor:
+ @classmethod
+ def get(cls):
+ func = getattr(cls, f'get_{sys.platform}', cls.from_subprocess)
+ return func() or ''
+
+ def get_win32():
+ return os.environ.get('PROCESSOR_IDENTIFIER', _get_machine_win32())
+
+ def get_OpenVMS():
+ try:
+ import vms_lib
+ except ImportError:
+ pass
+ else:
+ csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
+ return 'Alpha' if cpu_number >= 128 else 'VAX'
+
+ def from_subprocess():
+ """
+ Fall back to `uname -p`
+ """
+ try:
+ return subprocess.check_output(
+ ['uname', '-p'],
+ stderr=subprocess.DEVNULL,
+ text=True,
+ ).strip()
+ except (OSError, subprocess.CalledProcessError):
+ pass
+
+
+def _unknown_as_blank(val):
+ return '' if val == 'unknown' else val
+
+
### Portable uname() interface
-uname_result = collections.namedtuple("uname_result",
- "system node release version machine processor")
+class uname_result(
+ collections.namedtuple(
+ "uname_result_base",
+ "system node release version machine")
+ ):
+ """
+ A uname_result that's largely compatible with a
+ simple namedtuple except that 'platform' is
+ resolved late and cached to avoid calling "uname"
+ except when needed.
+ """
+
+ @functools.cached_property
+ def processor(self):
+ return _unknown_as_blank(_Processor.get())
+
+ def __iter__(self):
+ return itertools.chain(
+ super().__iter__(),
+ (self.processor,)
+ )
+
+ def __getitem__(self, key):
+ if key == 5:
+ return self.processor
+ return super().__getitem__(key)
+
_uname_cache = None
+
def uname():
""" Fairly portable uname interface. Returns a tuple
@@ -756,52 +819,30 @@ def uname():
"""
global _uname_cache
- no_os_uname = 0
if _uname_cache is not None:
return _uname_cache
- processor = ''
-
# Get some infos from the builtin os.uname API...
try:
- system, node, release, version, machine = os.uname()
+ system, node, release, version, machine = infos = os.uname()
except AttributeError:
- no_os_uname = 1
-
- if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
- # Hmm, no there is either no uname or uname has returned
- #'unknowns'... we'll have to poke around the system then.
- if no_os_uname:
- system = sys.platform
- release = ''
- version = ''
- node = _node()
- machine = ''
+ system = sys.platform
+ node = _node()
+ release = version = machine = ''
+ infos = ()
- use_syscmd_ver = 1
+ if not any(infos):
+ # uname is not available
# Try win32_ver() on win32 platforms
if system == 'win32':
release, version, csd, ptype = win32_ver()
- if release and version:
- use_syscmd_ver = 0
- # Try to use the PROCESSOR_* environment variables
- # available on Win XP and later; see
- # http://support.microsoft.com/kb/888731 and
- # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
- if not machine:
- # WOW64 processes mask the native architecture
- if "PROCESSOR_ARCHITEW6432" in os.environ:
- machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
- else:
- machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
- if not processor:
- processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
+ machine = machine or _get_machine_win32()
# Try the 'ver' system command available on some
# platforms
- if use_syscmd_ver:
+ if not (release and version):
system, release, version = _syscmd_ver(system)
# Normalize system to what win32_ver() normally returns
# (_syscmd_ver() tends to return the vendor name as well)
@@ -841,42 +882,15 @@ def uname():
if not release or release == '0':
release = version
version = ''
- # Get processor information
- try:
- import vms_lib
- except ImportError:
- pass
- else:
- csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
- if (cpu_number >= 128):
- processor = 'Alpha'
- else:
- processor = 'VAX'
- if not processor:
- # Get processor information from the uname system command
- processor = _syscmd_uname('-p', '')
-
- #If any unknowns still exist, replace them with ''s, which are more portable
- if system == 'unknown':
- system = ''
- if node == 'unknown':
- node = ''
- if release == 'unknown':
- release = ''
- if version == 'unknown':
- version = ''
- if machine == 'unknown':
- machine = ''
- if processor == 'unknown':
- processor = ''
# normalize name
if system == 'Microsoft' and release == 'Windows':
system = 'Windows'
release = 'Vista'
- _uname_cache = uname_result(system, node, release, version,
- machine, processor)
+ vals = system, node, release, version, machine
+ # Replace 'unknown' values with the more portable ''
+ _uname_cache = uname_result(*map(_unknown_as_blank, vals))
return _uname_cache
### Direct interfaces to some of the uname() return values