mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
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>
This commit is contained in:
parent
6a5bf15c71
commit
518835f335
3 changed files with 96 additions and 86 deletions
172
Lib/platform.py
172
Lib/platform.py
|
@ -116,6 +116,9 @@ import collections
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import functools
|
||||||
|
import itertools
|
||||||
|
|
||||||
### Globals & Constants
|
### Globals & Constants
|
||||||
|
|
||||||
|
@ -600,22 +603,6 @@ def _follow_symlinks(filepath):
|
||||||
os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
|
os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
|
||||||
return 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=''):
|
def _syscmd_file(target, default=''):
|
||||||
|
|
||||||
|
@ -736,13 +723,89 @@ def architecture(executable=sys.executable, bits='', linkage=''):
|
||||||
|
|
||||||
return 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
|
### Portable uname() interface
|
||||||
|
|
||||||
uname_result = collections.namedtuple("uname_result",
|
class uname_result(
|
||||||
"system node release version machine processor")
|
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
|
_uname_cache = None
|
||||||
|
|
||||||
|
|
||||||
def uname():
|
def uname():
|
||||||
|
|
||||||
""" Fairly portable uname interface. Returns a tuple
|
""" Fairly portable uname interface. Returns a tuple
|
||||||
|
@ -756,52 +819,30 @@ def uname():
|
||||||
|
|
||||||
"""
|
"""
|
||||||
global _uname_cache
|
global _uname_cache
|
||||||
no_os_uname = 0
|
|
||||||
|
|
||||||
if _uname_cache is not None:
|
if _uname_cache is not None:
|
||||||
return _uname_cache
|
return _uname_cache
|
||||||
|
|
||||||
processor = ''
|
|
||||||
|
|
||||||
# Get some infos from the builtin os.uname API...
|
# Get some infos from the builtin os.uname API...
|
||||||
try:
|
try:
|
||||||
system, node, release, version, machine = os.uname()
|
system, node, release, version, machine = infos = os.uname()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
no_os_uname = 1
|
system = sys.platform
|
||||||
|
node = _node()
|
||||||
|
release = version = machine = ''
|
||||||
|
infos = ()
|
||||||
|
|
||||||
if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
|
if not any(infos):
|
||||||
# Hmm, no there is either no uname or uname has returned
|
# uname is not available
|
||||||
#'unknowns'... we'll have to poke around the system then.
|
|
||||||
if no_os_uname:
|
|
||||||
system = sys.platform
|
|
||||||
release = ''
|
|
||||||
version = ''
|
|
||||||
node = _node()
|
|
||||||
machine = ''
|
|
||||||
|
|
||||||
use_syscmd_ver = 1
|
|
||||||
|
|
||||||
# Try win32_ver() on win32 platforms
|
# Try win32_ver() on win32 platforms
|
||||||
if system == 'win32':
|
if system == 'win32':
|
||||||
release, version, csd, ptype = win32_ver()
|
release, version, csd, ptype = win32_ver()
|
||||||
if release and version:
|
machine = machine or _get_machine_win32()
|
||||||
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)
|
|
||||||
|
|
||||||
# Try the 'ver' system command available on some
|
# Try the 'ver' system command available on some
|
||||||
# platforms
|
# platforms
|
||||||
if use_syscmd_ver:
|
if not (release and version):
|
||||||
system, release, version = _syscmd_ver(system)
|
system, release, version = _syscmd_ver(system)
|
||||||
# Normalize system to what win32_ver() normally returns
|
# Normalize system to what win32_ver() normally returns
|
||||||
# (_syscmd_ver() tends to return the vendor name as well)
|
# (_syscmd_ver() tends to return the vendor name as well)
|
||||||
|
@ -841,42 +882,15 @@ def uname():
|
||||||
if not release or release == '0':
|
if not release or release == '0':
|
||||||
release = version
|
release = version
|
||||||
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
|
# normalize name
|
||||||
if system == 'Microsoft' and release == 'Windows':
|
if system == 'Microsoft' and release == 'Windows':
|
||||||
system = 'Windows'
|
system = 'Windows'
|
||||||
release = 'Vista'
|
release = 'Vista'
|
||||||
|
|
||||||
_uname_cache = uname_result(system, node, release, version,
|
vals = system, node, release, version, machine
|
||||||
machine, processor)
|
# Replace 'unknown' values with the more portable ''
|
||||||
|
_uname_cache = uname_result(*map(_unknown_as_blank, vals))
|
||||||
return _uname_cache
|
return _uname_cache
|
||||||
|
|
||||||
### Direct interfaces to some of the uname() return values
|
### Direct interfaces to some of the uname() return values
|
||||||
|
|
|
@ -4,7 +4,6 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import collections
|
import collections
|
||||||
import contextlib
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
|
@ -168,12 +167,8 @@ class PlatformTest(unittest.TestCase):
|
||||||
On some systems, the processor must match the output
|
On some systems, the processor must match the output
|
||||||
of 'uname -p'. See Issue 35967 for rationale.
|
of 'uname -p'. See Issue 35967 for rationale.
|
||||||
"""
|
"""
|
||||||
with contextlib.suppress(subprocess.CalledProcessError):
|
proc_res = subprocess.check_output(['uname', '-p'], text=True).strip()
|
||||||
expect = subprocess.check_output(['uname', '-p'], text=True).strip()
|
expect = platform._unknown_as_blank(proc_res)
|
||||||
|
|
||||||
if expect == 'unknown':
|
|
||||||
expect = ''
|
|
||||||
|
|
||||||
self.assertEqual(platform.uname().processor, expect)
|
self.assertEqual(platform.uname().processor, expect)
|
||||||
|
|
||||||
@unittest.skipUnless(sys.platform.startswith('win'), "windows only test")
|
@unittest.skipUnless(sys.platform.startswith('win'), "windows only test")
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
In platform, delay the invocation of 'uname -p' until the processor attribute is requested.
|
Loading…
Add table
Add a link
Reference in a new issue