From 6039303f8890f4321f83803e7c960dd057bb8fd2 Mon Sep 17 00:00:00 2001 From: Naveen M K Date: Fri, 31 Dec 2021 13:30:10 +0530 Subject: [PATCH 1/2] util.get_host_platform: use sysconfig.get_platform sysconfig module has a copy of this function in `sysconfig.get_platform` and would be better to use that directly. This should help distributors to patch that function in a single place, ie sysconfig. Co-authored-by: Christoph Reiter Signed-off-by: Naveen M K --- distutils/tests/test_util.py | 120 ++++------------------------------- distutils/util.py | 81 ++--------------------- 2 files changed, 18 insertions(+), 183 deletions(-) diff --git a/distutils/tests/test_util.py b/distutils/tests/test_util.py index 12469e3d..bfbc2ec6 100644 --- a/distutils/tests/test_util.py +++ b/distutils/tests/test_util.py @@ -2,6 +2,7 @@ import os import sys import unittest +import sysconfig as stdlib_sysconfig from copy import copy from test.support import run_unittest from unittest import mock @@ -10,12 +11,10 @@ from distutils.util import (get_platform, convert_path, change_root, check_environ, split_quoted, strtobool, rfc822_escape, byte_compile, - grok_environment_error) + grok_environment_error, get_host_platform) from distutils import util # used to patch _environ_checked -from distutils.sysconfig import get_config_vars from distutils import sysconfig from distutils.tests import support -import _osx_support class UtilTestCase(support.EnvironGuard, unittest.TestCase): @@ -63,110 +62,19 @@ def _set_uname(self, uname): def _get_uname(self): return self._uname - def test_get_platform(self): - - # windows XP, 32bits - os.name = 'nt' - sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) ' - '[MSC v.1310 32 bit (Intel)]') - sys.platform = 'win32' - self.assertEqual(get_platform(), 'win32') - - # windows XP, amd64 - os.name = 'nt' - sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) ' - '[MSC v.1310 32 bit (Amd64)]') - sys.platform = 'win32' - self.assertEqual(get_platform(), 'win-amd64') - - # macbook - os.name = 'posix' - sys.version = ('2.5 (r25:51918, Sep 19 2006, 08:49:13) ' - '\n[GCC 4.0.1 (Apple Computer, Inc. build 5341)]') - sys.platform = 'darwin' - self._set_uname(('Darwin', 'macziade', '8.11.1', - ('Darwin Kernel Version 8.11.1: ' - 'Wed Oct 10 18:23:28 PDT 2007; ' - 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' - - get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' - '-fwrapv -O3 -Wall -Wstrict-prototypes') - - cursize = sys.maxsize - sys.maxsize = (2 ** 31)-1 - try: - self.assertEqual(get_platform(), 'macosx-10.3-i386') - finally: - sys.maxsize = cursize - - # macbook with fat binaries (fat, universal or fat64) - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' - get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - - self.assertEqual(get_platform(), 'macosx-10.4-fat') - - _osx_support._remove_original_values(get_config_vars()) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.1' - self.assertEqual(get_platform(), 'macosx-10.4-fat') - + def test_get_host_platform(self): + self.assertEqual(get_host_platform(), stdlib_sysconfig.get_platform()) - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - - self.assertEqual(get_platform(), 'macosx-10.4-intel') - - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - self.assertEqual(get_platform(), 'macosx-10.4-fat3') - - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch ppc64 -arch x86_64 -arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - self.assertEqual(get_platform(), 'macosx-10.4-universal') - - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc64 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - - self.assertEqual(get_platform(), 'macosx-10.4-fat64') - - for arch in ('ppc', 'i386', 'x86_64', 'ppc64'): - _osx_support._remove_original_values(get_config_vars()) - get_config_vars()['CFLAGS'] = ('-arch %s -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3'%(arch,)) - - self.assertEqual(get_platform(), 'macosx-10.4-%s'%(arch,)) - - - # linux debian sarge - os.name = 'posix' - sys.version = ('2.3.5 (#1, Jul 4 2007, 17:28:59) ' - '\n[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)]') - sys.platform = 'linux2' - self._set_uname(('Linux', 'aglae', '2.6.21.1dedibox-r7', - '#1 Mon Apr 30 17:25:38 CEST 2007', 'i686')) - - self.assertEqual(get_platform(), 'linux-i686') - - # XXX more platforms to tests here + def test_get_platform(self): + with unittest.mock.patch('os.name', 'nt'): + with unittest.mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'x86'}): + self.assertEqual(get_platform(), 'win32') + with unittest.mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'x64'}): + self.assertEqual(get_platform(), 'win-amd64') + with unittest.mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'arm'}): + self.assertEqual(get_platform(), 'win-arm32') + with unittest.mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'arm64'}): + self.assertEqual(get_platform(), 'win-arm64') def test_convert_path(self): # linux/mac diff --git a/distutils/util.py b/distutils/util.py index ac6d446d..50633408 100644 --- a/distutils/util.py +++ b/distutils/util.py @@ -9,6 +9,7 @@ import importlib.util import string import sys +import sysconfig from distutils.errors import DistutilsPlatformError from distutils.dep_util import newer from distutils.spawn import spawn @@ -18,84 +19,10 @@ def get_host_platform(): - """Return a string that identifies the current platform. This is used mainly to - distinguish platform-specific build directories and platform-specific built - distributions. Typically includes the OS name and version and the - architecture (as supplied by 'os.uname()'), although the exact information - included depends on the OS; eg. on Linux, the kernel version isn't - particularly important. - - Examples of returned values: - linux-i586 - linux-alpha (?) - solaris-2.6-sun4u - - Windows will return one of: - win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) - win32 (all others - specifically, sys.platform is returned) - - For other non-POSIX platforms, currently just returns 'sys.platform'. - + """Returns the same as `get_platform()` from sysconfig. """ - if os.name == 'nt': - if 'amd64' in sys.version.lower(): - return 'win-amd64' - if '(arm)' in sys.version.lower(): - return 'win-arm32' - if '(arm64)' in sys.version.lower(): - return 'win-arm64' - return sys.platform - - # Set for cross builds explicitly - if "_PYTHON_HOST_PLATFORM" in os.environ: - return os.environ["_PYTHON_HOST_PLATFORM"] - - if os.name != "posix" or not hasattr(os, 'uname'): - # XXX what about the architecture? NT is Intel or Alpha, - # Mac OS is M68k or PPC, etc. - return sys.platform - - # Try to distinguish various flavours of Unix - - (osname, host, release, version, machine) = os.uname() - - # Convert the OS name to lowercase, remove '/' characters, and translate - # spaces (for "Power Macintosh") - osname = osname.lower().replace('/', '') - machine = machine.replace(' ', '_') - machine = machine.replace('/', '-') - - if osname[:5] == "linux": - # At least on Linux/Intel, 'machine' is the processor -- - # i386, etc. - # XXX what about Alpha, SPARC, etc? - return "%s-%s" % (osname, machine) - elif osname[:5] == "sunos": - if release[0] >= "5": # SunOS 5 == Solaris 2 - osname = "solaris" - release = "%d.%s" % (int(release[0]) - 3, release[2:]) - # We can't use "platform.architecture()[0]" because a - # bootstrap problem. We use a dict to get an error - # if some suspicious happens. - bitness = {2147483647:"32bit", 9223372036854775807:"64bit"} - machine += ".%s" % bitness[sys.maxsize] - # fall through to standard osname-release-machine representation - elif osname[:3] == "aix": - from .py38compat import aix_platform - return aix_platform(osname, version, release) - elif osname[:6] == "cygwin": - osname = "cygwin" - rel_re = re.compile (r'[\d.]+', re.ASCII) - m = rel_re.match(release) - if m: - release = m.group() - elif osname[:6] == "darwin": - import _osx_support, distutils.sysconfig - osname, release, machine = _osx_support.get_platform_osx( - distutils.sysconfig.get_config_vars(), - osname, release, machine) - - return "%s-%s-%s" % (osname, release, machine) + + return sysconfig.get_platform() def get_platform(): if os.name == 'nt': From 057adb220b6018ff5ad175a5f83e6173cc83f3ad Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Mon, 3 Jan 2022 20:38:17 +0100 Subject: [PATCH 2/2] util.get_host_platform: restore Python 3.9 behaviour for Python 3.7/3.8 While get_host_platform() in distutils and sysconfig.get_platform() are more or less the same for the same Python version, this extracted distutils containing the Python 3.9 logic was exposed via setuptools to users using older Python versions. To avoid any breakage make sure to restore the 3.9 behaviour for 3.7/3.8. For any newer version get_host_platform() just delegates to sysconfig as before. Also partly revert the docstring to be more generic and no longer mention sysconfig.get_platform(), so no one depends on them matching. --- distutils/tests/test_util.py | 9 ++++++++- distutils/util.py | 23 ++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/distutils/tests/test_util.py b/distutils/tests/test_util.py index bfbc2ec6..2738388e 100644 --- a/distutils/tests/test_util.py +++ b/distutils/tests/test_util.py @@ -63,7 +63,14 @@ def _get_uname(self): return self._uname def test_get_host_platform(self): - self.assertEqual(get_host_platform(), stdlib_sysconfig.get_platform()) + with unittest.mock.patch('os.name', 'nt'): + with unittest.mock.patch('sys.version', '... [... (ARM64)]'): + self.assertEqual(get_host_platform(), 'win-arm64') + with unittest.mock.patch('sys.version', '... [... (ARM)]'): + self.assertEqual(get_host_platform(), 'win-arm32') + + with unittest.mock.patch('sys.version_info', (3, 9, 0, 'final', 0)): + self.assertEqual(get_host_platform(), stdlib_sysconfig.get_platform()) def test_get_platform(self): with unittest.mock.patch('os.name', 'nt'): diff --git a/distutils/util.py b/distutils/util.py index 50633408..6d506d7e 100644 --- a/distutils/util.py +++ b/distutils/util.py @@ -19,9 +19,30 @@ def get_host_platform(): - """Returns the same as `get_platform()` from sysconfig. + """Return a string that identifies the current platform. This is used mainly to + distinguish platform-specific build directories and platform-specific built + distributions. """ + # We initially exposed platforms as defined in Python 3.9 + # even with older Python versions when distutils was split out. + # Now that we delegate to stdlib sysconfig we need to restore this + # in case anyone has started to depend on it. + + if sys.version_info < (3, 8): + if os.name == 'nt': + if '(arm)' in sys.version.lower(): + return 'win-arm32' + if '(arm64)' in sys.version.lower(): + return 'win-arm64' + + if sys.version_info < (3, 9): + if os.name == "posix" and hasattr(os, 'uname'): + osname, host, release, version, machine = os.uname() + if osname[:3] == "aix": + from .py38compat import aix_platform + return aix_platform(osname, version, release) + return sysconfig.get_platform() def get_platform():