gh-89545: Updates platform module to use new internal _wmi module on Windows to directly query OS properties (GH-96289)

This commit is contained in:
Steve Dower 2022-09-07 21:09:20 +01:00 committed by GitHub
parent 4114bcc9ef
commit de33df27aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 856 additions and 88 deletions

View file

@ -309,34 +309,52 @@ def _syscmd_ver(system='', release='', version='',
version = _norm_version(version)
return system, release, version
_WIN32_CLIENT_RELEASES = {
(5, 0): "2000",
(5, 1): "XP",
# Strictly, 5.2 client is XP 64-bit, but platform.py historically
# has always called it 2003 Server
(5, 2): "2003Server",
(5, None): "post2003",
try:
import _wmi
except ImportError:
def _wmi_query(*keys):
raise OSError("not supported")
else:
def _wmi_query(table, *keys):
table = {
"OS": "Win32_OperatingSystem",
"CPU": "Win32_Processor",
}[table]
data = _wmi.exec_query("SELECT {} FROM {}".format(
",".join(keys),
table,
)).split("\0")
split_data = (i.partition("=") for i in data)
dict_data = {i[0]: i[2] for i in split_data}
return (dict_data[k] for k in keys)
(6, 0): "Vista",
(6, 1): "7",
(6, 2): "8",
(6, 3): "8.1",
(6, None): "post8.1",
(10, 0): "10",
(10, None): "post10",
}
_WIN32_CLIENT_RELEASES = [
((10, 1, 0), "post11"),
((10, 0, 22000), "11"),
((6, 4, 0), "10"),
((6, 3, 0), "8.1"),
((6, 2, 0), "8"),
((6, 1, 0), "7"),
((6, 0, 0), "Vista"),
((5, 2, 3790), "XP64"),
((5, 2, 0), "XPMedia"),
((5, 1, 0), "XP"),
((5, 0, 0), "2000"),
]
# Server release name lookup will default to client names if necessary
_WIN32_SERVER_RELEASES = {
(5, 2): "2003Server",
(6, 0): "2008Server",
(6, 1): "2008ServerR2",
(6, 2): "2012Server",
(6, 3): "2012ServerR2",
(6, None): "post2012ServerR2",
}
_WIN32_SERVER_RELEASES = [
((10, 1, 0), "post2022Server"),
((10, 0, 20348), "2022Server"),
((10, 0, 17763), "2019Server"),
((6, 4, 0), "2016Server"),
((6, 3, 0), "2012ServerR2"),
((6, 2, 0), "2012Server"),
((6, 1, 0), "2008ServerR2"),
((6, 0, 0), "2008Server"),
((5, 2, 0), "2003Server"),
((5, 0, 0), "2000Server"),
]
def win32_is_iot():
return win32_edition() in ('IoTUAP', 'NanoServer', 'WindowsCoreHeadless', 'IoTEdgeOS')
@ -359,22 +377,40 @@ def win32_edition():
return None
def win32_ver(release='', version='', csd='', ptype=''):
def _win32_ver(version, csd, ptype):
# Try using WMI first, as this is the canonical source of data
try:
(version, product_type, ptype, spmajor, spminor) = _wmi_query(
'OS',
'Version',
'ProductType',
'BuildType',
'ServicePackMajorVersion',
'ServicePackMinorVersion',
)
is_client = (int(product_type) == 1)
if spminor and spminor != '0':
csd = f'SP{spmajor}.{spminor}'
else:
csd = f'SP{spmajor}'
return version, csd, ptype, is_client
except OSError:
pass
# Fall back to a combination of sys.getwindowsversion and "ver"
try:
from sys import getwindowsversion
except ImportError:
return release, version, csd, ptype
return version, csd, ptype, True
winver = getwindowsversion()
is_client = (getattr(winver, 'product_type', 1) == 1)
try:
major, minor, build = map(int, _syscmd_ver()[2].split('.'))
version = _syscmd_ver()[2]
major, minor, build = map(int, version.split('.'))
except ValueError:
major, minor, build = winver.platform_version or winver[:3]
version = '{0}.{1}.{2}'.format(major, minor, build)
release = (_WIN32_CLIENT_RELEASES.get((major, minor)) or
_WIN32_CLIENT_RELEASES.get((major, None)) or
release)
version = '{0}.{1}.{2}'.format(major, minor, build)
# getwindowsversion() reflect the compatibility mode Python is
# running under, and so the service pack value is only going to be
@ -386,12 +422,6 @@ def win32_ver(release='', version='', csd='', ptype=''):
if csd[:13] == 'Service Pack ':
csd = 'SP' + csd[13:]
# VER_NT_SERVER = 3
if getattr(winver, 'product_type', None) == 3:
release = (_WIN32_SERVER_RELEASES.get((major, minor)) or
_WIN32_SERVER_RELEASES.get((major, None)) or
release)
try:
try:
import winreg
@ -407,6 +437,18 @@ def win32_ver(release='', version='', csd='', ptype=''):
except OSError:
pass
return version, csd, ptype, is_client
def win32_ver(release='', version='', csd='', ptype=''):
is_client = False
version, csd, ptype, is_client = _win32_ver(version, csd, ptype)
if version:
intversion = tuple(map(int, version.split('.')))
releases = _WIN32_CLIENT_RELEASES if is_client else _WIN32_SERVER_RELEASES
release = next((r for v, r in releases if v <= intversion), release)
return release, version, csd, ptype
@ -725,6 +767,21 @@ def _get_machine_win32():
# http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
# WOW64 processes mask the native architecture
try:
[arch, *_] = _wmi_query('CPU', 'Architecture')
except OSError:
pass
else:
try:
arch = ['x86', 'MIPS', 'Alpha', 'PowerPC', None,
'ARM', 'ia64', None, None,
'AMD64', None, None, 'ARM64',
][int(arch)]
except (ValueError, IndexError):
pass
else:
if arch:
return arch
return (
os.environ.get('PROCESSOR_ARCHITEW6432', '') or
os.environ.get('PROCESSOR_ARCHITECTURE', '')
@ -738,7 +795,12 @@ class _Processor:
return func() or ''
def get_win32():
return os.environ.get('PROCESSOR_IDENTIFIER', _get_machine_win32())
try:
manufacturer, caption = _wmi_query('CPU', 'Manufacturer', 'Caption')
except OSError:
return os.environ.get('PROCESSOR_IDENTIFIER', _get_machine_win32())
else:
return f'{caption}, {manufacturer}'
def get_OpenVMS():
try: