From a43ceb090202d1553a0f5827e062d6dfd1955e33 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 19 Mar 2026 00:26:45 +0100 Subject: [PATCH 1/4] gh-146145: Use _sysconfig.get_platform() in the platform module --- Lib/platform.py | 43 ++++++++++++++++--- Lib/test/test_platform.py | 18 +++++++- ...-03-19-00-32-12.gh-issue-145410.gu1Ops.rst | 2 + 3 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-03-19-00-32-12.gh-issue-145410.gu1Ops.rst diff --git a/Lib/platform.py b/Lib/platform.py index 9d7aa5c66a91cb..46c7381b363b96 100644 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -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', '32bit', '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 @@ -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: @@ -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: @@ -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', '') diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 9ee97b922ad48e..011066f9defeb8 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -379,12 +379,27 @@ def test_uname_win32_ARCHITEW6432(self): # 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-arm32', 'ARM'), + ('win-amd64', 'AMD64'), + ('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'] @@ -392,6 +407,7 @@ def raises_oserror(*a): 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() diff --git a/Misc/NEWS.d/next/Library/2026-03-19-00-32-12.gh-issue-145410.gu1Ops.rst b/Misc/NEWS.d/next/Library/2026-03-19-00-32-12.gh-issue-145410.gu1Ops.rst new file mode 100644 index 00000000000000..e735338903d242 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-19-00-32-12.gh-issue-145410.gu1Ops.rst @@ -0,0 +1,2 @@ +:mod:`platform`: On Windows, use the ``_sysconfig`` module to get the +architecture and the machine. Patch by Victor Stinner. From a97eafd7b9851a675340bb825504b5422c512db8 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 19 Mar 2026 01:02:54 +0100 Subject: [PATCH 2/4] Fix _sysconfig_architecture for win-amd64 --- Lib/platform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/platform.py b/Lib/platform.py index 46c7381b363b96..7b9adf65a43ff2 100644 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -715,7 +715,7 @@ def _syscmd_file(target, default=''): _sysconfig_architecture = frozendict({ # platform: (arch, bits, linkage) 'win32': ('x86', '32bit', 'WindowsPE'), - 'win-amd64': ('AMD64', '32bit', 'WindowsPE'), + 'win-amd64': ('AMD64', '64bit', 'WindowsPE'), 'win-arm32': ('ARM', '32bit', 'WindowsPE'), 'win-arm64': ('ARM64', '64bit', 'WindowsPE'), }) From 35ebd340146e0b0b3a16a2631c6f9111e0c2c4fb Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 19 Mar 2026 01:09:45 +0100 Subject: [PATCH 3/4] Add more tests on architecture() --- Lib/test/test_platform.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 011066f9defeb8..989ab88bebc927 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -121,6 +121,19 @@ def test_invalidate_caches(self): def test_architecture(self): res = platform.architecture() + 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() def test_architecture_via_symlink(self): # issue3762 @@ -372,7 +385,7 @@ 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 @@ -381,11 +394,12 @@ def test_uname_win32_ARCHITEW6432(self): for sysconfig_platform, arch in ( ('win32', 'x86'), - ('win-arm32', 'ARM'), ('win-amd64', 'AMD64'), + ('win-arm32', 'ARM'), ('win-arm64', 'ARM64'), ): - with mock.patch('_sysconfig.get_platform', return_value=sysconfig_platform): + with mock.patch('_sysconfig.get_platform', + return_value=sysconfig_platform): try: platform._uname_cache = None system, node, release, version, machine, processor = platform.uname() From ab707614e6f3fe5e8128589e8260be8c36221410 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 19 Mar 2026 01:11:15 +0100 Subject: [PATCH 4/4] Add even more tests on architecture() --- Lib/test/test_platform.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 989ab88bebc927..b6a43d909f13be 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -119,7 +119,9 @@ 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 (