Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,27 @@ def _syscmd_file(target, default=''):
'dos': ('', 'MSDOS'),
})


_sysconfig_architecture = frozendict({
# platform: (arch, bits, linkage)
'win32': ('x86', '32bit', 'WindowsPE'),
'win-amd64': ('AMD64', '64bit', 'WindowsPE'),
'win-arm32': ('ARM', '32bit', 'WindowsPE'),
'win-arm64': ('ARM64', '64bit', 'WindowsPE'),
})

def _sysconfig_platform():
try:
import _sysconfig
except ImportError:
return ('', '', '')

platform = _sysconfig.get_platform()
if platform in _sysconfig_architecture:
return _sysconfig_architecture[platform]
return ('', '', '')


def architecture(executable=sys.executable, bits='', linkage=''):

""" Queries the given executable (defaults to the Python interpreter
Expand Down Expand Up @@ -745,10 +766,15 @@ def architecture(executable=sys.executable, bits='', linkage=''):
else:
fileout = ''

if not fileout and \
executable == sys.executable:
if not fileout and executable == sys.executable:
# "file" command did not return anything; we'll try to provide
# some sensible defaults then...
if os.name == "nt":
# Use _sysconfig.get_platform() if available
_, b, l = _sysconfig_platform()
if b:
return (b, l)

if sys.platform in _default_architecture:
b, l = _default_architecture[sys.platform]
if b:
Expand Down Expand Up @@ -790,10 +816,10 @@ def architecture(executable=sys.executable, 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
# Use _sysconfig.get_platform() if available
arch, bits, linkage = _sysconfig_platform()
if arch:
return arch

# WOW64 processes mask the native architecture
try:
Expand All @@ -811,6 +837,11 @@ def _get_machine_win32():
else:
if arch:
return arch

# 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
return (
os.environ.get('PROCESSOR_ARCHITEW6432', '') or
os.environ.get('PROCESSOR_ARCHITECTURE', '')
Expand Down
38 changes: 35 additions & 3 deletions Lib/test/test_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,22 @@ def test_invalidate_caches(self):
self.assertIsNone(platform._os_release_cache)

def test_architecture(self):
res = platform.architecture()
bits, linkage = platform.architecture()
self.assertIsInstance(bits, str)
self.assertIsInstance(linkage, str)

if support.MS_WINDOWS:
for sysconfig_platform, expected_bits in (
('win32', 32),
('win-amd64', 64),
('win-arm32', 32),
('win-arm64', 64),
):
with mock.patch('_sysconfig.get_platform',
return_value=sysconfig_platform):
bits, linkage = platform.architecture()
self.assertEqual(bits, f'{expected_bits}bit')
self.assertEqual(linkage, 'WindowsPE')

@os_helper.skip_unless_symlink
@support.requires_subprocess()
Expand Down Expand Up @@ -372,26 +387,43 @@ def test_uname_processor(self):
expect = ''
self.assertEqual(platform.uname().processor, expect)

@unittest.skipUnless(sys.platform.startswith('win'), "windows only test")
@unittest.skipUnless(support.MS_WINDOWS, "windows only test")
def test_uname_win32_ARCHITEW6432(self):
# Issue 7860: make sure we get architecture from the correct variable
# on 64 bit Windows: if PROCESSOR_ARCHITEW6432 exists we should be
# using it, per
# http://blogs.msdn.com/david.wang/archive/2006/03/26/HOWTO-Detect-Process-Bitness.aspx

for sysconfig_platform, arch in (
('win32', 'x86'),
('win-amd64', 'AMD64'),
('win-arm32', 'ARM'),
('win-arm64', 'ARM64'),
):
with mock.patch('_sysconfig.get_platform',
return_value=sysconfig_platform):
try:
platform._uname_cache = None
system, node, release, version, machine, processor = platform.uname()
self.assertEqual(machine, arch)
finally:
platform._uname_cache = None

# We also need to suppress WMI checks, as those are reliable and
# overrule the environment variables
def raises_oserror(*a):
raise OSError()

with support.swap_attr(platform, '_wmi_query', raises_oserror):
with (mock.patch('_sysconfig.get_platform', return_value=None),
support.swap_attr(platform, '_wmi_query', raises_oserror)):
with os_helper.EnvironmentVarGuard() as environ:
try:
del environ['PROCESSOR_ARCHITEW6432']
environ['PROCESSOR_ARCHITECTURE'] = 'foo'
platform._uname_cache = None
system, node, release, version, machine, processor = platform.uname()
self.assertEqual(machine, 'foo')

environ['PROCESSOR_ARCHITEW6432'] = 'bar'
platform._uname_cache = None
system, node, release, version, machine, processor = platform.uname()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:mod:`platform`: On Windows, use the ``_sysconfig`` module to get the
architecture and the machine. Patch by Victor Stinner.
Loading