mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Update sysconfig from v3.14.3
This commit is contained in:
1 parent
d23eb4af6c
commit
5a11f33751
4 files changed
+352
-168
No files matched your search
Vendored
+135
-72
@@ -116,8 +116,10 @@ def _getuserbase():
|
||||
if env_base:
|
||||
return env_base
|
||||
|
||||
# Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories
|
||||
if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
|
||||
# Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories.
|
||||
# Use _PYTHON_HOST_PLATFORM to get the correct platform when cross-compiling.
|
||||
system_name = os.environ.get('_PYTHON_HOST_PLATFORM', sys.platform).split('-')[0]
|
||||
if system_name in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
|
||||
return None
|
||||
|
||||
def joinuser(*args):
|
||||
@@ -323,17 +325,37 @@ def get_default_scheme():
|
||||
|
||||
def get_makefile_filename():
|
||||
"""Return the path of the Makefile."""
|
||||
|
||||
# GH-127429: When cross-compiling, use the Makefile from the target, instead of the host Python.
|
||||
if cross_base := os.environ.get('_PYTHON_PROJECT_BASE'):
|
||||
return os.path.join(cross_base, 'Makefile')
|
||||
|
||||
if _PYTHON_BUILD:
|
||||
return os.path.join(_PROJECT_BASE, "Makefile")
|
||||
|
||||
if hasattr(sys, 'abiflags'):
|
||||
config_dir_name = f'config-{_PY_VERSION_SHORT}{sys.abiflags}'
|
||||
else:
|
||||
config_dir_name = 'config'
|
||||
|
||||
if hasattr(sys.implementation, '_multiarch'):
|
||||
config_dir_name += f'-{sys.implementation._multiarch}'
|
||||
|
||||
return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
|
||||
|
||||
|
||||
def _import_from_directory(path, name):
|
||||
if name not in sys.modules:
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
|
||||
spec = importlib.machinery.PathFinder.find_spec(name, [path])
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
sys.modules[name] = module
|
||||
return sys.modules[name]
|
||||
|
||||
|
||||
def _get_sysconfigdata_name():
|
||||
multiarch = getattr(sys.implementation, '_multiarch', '')
|
||||
return os.environ.get(
|
||||
@@ -341,26 +363,34 @@ def _get_sysconfigdata_name():
|
||||
f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}',
|
||||
)
|
||||
|
||||
|
||||
def _get_sysconfigdata():
|
||||
import importlib
|
||||
|
||||
name = _get_sysconfigdata_name()
|
||||
path = os.environ.get('_PYTHON_SYSCONFIGDATA_PATH')
|
||||
module = _import_from_directory(path, name) if path else importlib.import_module(name)
|
||||
|
||||
return module.build_time_vars
|
||||
|
||||
|
||||
def _installation_is_relocated():
|
||||
"""Is the Python installation running from a different prefix than what was targetted when building?"""
|
||||
if os.name != 'posix':
|
||||
raise NotImplementedError('sysconfig._installation_is_relocated() is currently only supported on POSIX')
|
||||
|
||||
data = _get_sysconfigdata()
|
||||
return (
|
||||
data['prefix'] != getattr(sys, 'base_prefix', '')
|
||||
or data['exec_prefix'] != getattr(sys, 'base_exec_prefix', '')
|
||||
)
|
||||
|
||||
|
||||
def _init_posix(vars):
|
||||
"""Initialize the module as appropriate for POSIX systems."""
|
||||
# _sysconfigdata is generated at build time, see _generate_posix_vars()
|
||||
name = _get_sysconfigdata_name()
|
||||
# GH-126920: Make sure we don't overwrite any of the keys already set
|
||||
vars.update(_get_sysconfigdata() | vars)
|
||||
|
||||
# For cross builds, the path to the target's sysconfigdata must be specified
|
||||
# so it can be imported. It cannot be in PYTHONPATH, as foreign modules in
|
||||
# sys.path can cause crashes when loaded by the host interpreter.
|
||||
# Rely on truthiness as a valueless env variable is still an empty string.
|
||||
# See OS X note in _generate_posix_vars re _sysconfigdata.
|
||||
if (path := os.environ.get('_PYTHON_SYSCONFIGDATA_PATH')):
|
||||
from importlib.machinery import FileFinder, SourceFileLoader, SOURCE_SUFFIXES
|
||||
from importlib.util import module_from_spec
|
||||
spec = FileFinder(path, (SourceFileLoader, SOURCE_SUFFIXES)).find_spec(name)
|
||||
_temp = module_from_spec(spec)
|
||||
spec.loader.exec_module(_temp)
|
||||
else:
|
||||
_temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
|
||||
build_time_vars = _temp.build_time_vars
|
||||
vars.update(build_time_vars)
|
||||
|
||||
def _init_non_posix(vars):
|
||||
"""Initialize the module as appropriate for NT"""
|
||||
@@ -371,9 +401,20 @@ def _init_non_posix(vars):
|
||||
vars['BINLIBDEST'] = get_path('platstdlib')
|
||||
vars['INCLUDEPY'] = get_path('include')
|
||||
|
||||
# Add EXT_SUFFIX, SOABI, and Py_GIL_DISABLED
|
||||
# Add EXT_SUFFIX, SOABI, Py_DEBUG, and Py_GIL_DISABLED
|
||||
vars.update(_sysconfig.config_vars())
|
||||
|
||||
# NOTE: ABIFLAGS is only an emulated value. It is not present during build
|
||||
# on Windows. sys.abiflags is absent on Windows and vars['abiflags']
|
||||
# is already widely used to calculate paths, so it should remain an
|
||||
# empty string.
|
||||
vars['ABIFLAGS'] = ''.join(
|
||||
(
|
||||
't' if vars['Py_GIL_DISABLED'] else '',
|
||||
'_d' if vars['Py_DEBUG'] else '',
|
||||
),
|
||||
)
|
||||
|
||||
vars['LIBDIR'] = _safe_realpath(os.path.join(get_config_var('installed_base'), 'libs'))
|
||||
if hasattr(sys, 'dllhandle'):
|
||||
dllhandle = _winapi.GetModuleFileName(sys.dllhandle)
|
||||
@@ -427,7 +468,7 @@ def get_config_h_filename():
|
||||
"""Return the path of pyconfig.h."""
|
||||
if _PYTHON_BUILD:
|
||||
if os.name == "nt":
|
||||
inc_dir = os.path.dirname(sys._base_executable)
|
||||
inc_dir = os.path.join(_PROJECT_BASE, 'PC')
|
||||
else:
|
||||
inc_dir = _PROJECT_BASE
|
||||
else:
|
||||
@@ -468,29 +509,44 @@ def get_path(name, scheme=get_default_scheme(), vars=None, expand=True):
|
||||
def _init_config_vars():
|
||||
global _CONFIG_VARS
|
||||
_CONFIG_VARS = {}
|
||||
|
||||
prefix = os.path.normpath(sys.prefix)
|
||||
exec_prefix = os.path.normpath(sys.exec_prefix)
|
||||
base_prefix = _BASE_PREFIX
|
||||
base_exec_prefix = _BASE_EXEC_PREFIX
|
||||
|
||||
try:
|
||||
abiflags = sys.abiflags
|
||||
except AttributeError:
|
||||
abiflags = ''
|
||||
|
||||
if os.name == 'posix':
|
||||
_init_posix(_CONFIG_VARS)
|
||||
# If we are cross-compiling, load the prefixes from the Makefile instead.
|
||||
if '_PYTHON_PROJECT_BASE' in os.environ:
|
||||
prefix = _CONFIG_VARS['host_prefix']
|
||||
exec_prefix = _CONFIG_VARS['host_exec_prefix']
|
||||
base_prefix = _CONFIG_VARS['host_prefix']
|
||||
base_exec_prefix = _CONFIG_VARS['host_exec_prefix']
|
||||
abiflags = _CONFIG_VARS['ABIFLAGS']
|
||||
|
||||
# Normalized versions of prefix and exec_prefix are handy to have;
|
||||
# in fact, these are the standard versions used most places in the
|
||||
# Distutils.
|
||||
_PREFIX = os.path.normpath(sys.prefix)
|
||||
_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
|
||||
_CONFIG_VARS['prefix'] = _PREFIX # FIXME: This gets overwriten by _init_posix.
|
||||
_CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX # FIXME: This gets overwriten by _init_posix.
|
||||
_CONFIG_VARS['prefix'] = prefix
|
||||
_CONFIG_VARS['exec_prefix'] = exec_prefix
|
||||
_CONFIG_VARS['py_version'] = _PY_VERSION
|
||||
_CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
|
||||
_CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT
|
||||
_CONFIG_VARS['installed_base'] = _BASE_PREFIX
|
||||
_CONFIG_VARS['base'] = _PREFIX
|
||||
_CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX
|
||||
_CONFIG_VARS['platbase'] = _EXEC_PREFIX
|
||||
_CONFIG_VARS['installed_base'] = base_prefix
|
||||
_CONFIG_VARS['base'] = prefix
|
||||
_CONFIG_VARS['installed_platbase'] = base_exec_prefix
|
||||
_CONFIG_VARS['platbase'] = exec_prefix
|
||||
_CONFIG_VARS['projectbase'] = _PROJECT_BASE
|
||||
_CONFIG_VARS['platlibdir'] = sys.platlibdir
|
||||
_CONFIG_VARS['implementation'] = _get_implementation()
|
||||
_CONFIG_VARS['implementation_lower'] = _get_implementation().lower()
|
||||
try:
|
||||
_CONFIG_VARS['abiflags'] = sys.abiflags
|
||||
except AttributeError:
|
||||
# sys.abiflags may not be defined on all platforms.
|
||||
_CONFIG_VARS['abiflags'] = ''
|
||||
_CONFIG_VARS['abiflags'] = abiflags
|
||||
try:
|
||||
_CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '')
|
||||
except AttributeError:
|
||||
@@ -499,8 +555,6 @@ def _init_config_vars():
|
||||
if os.name == 'nt':
|
||||
_init_non_posix(_CONFIG_VARS)
|
||||
_CONFIG_VARS['VPATH'] = sys._vpath
|
||||
if os.name == 'posix':
|
||||
_init_posix(_CONFIG_VARS)
|
||||
if _HAS_USER_BASE:
|
||||
# Setting 'userbase' is done below the call to the
|
||||
# init function to enable using 'get_config_var' in
|
||||
@@ -550,7 +604,16 @@ def get_config_vars(*args):
|
||||
global _CONFIG_VARS_INITIALIZED
|
||||
|
||||
# Avoid claiming the lock once initialization is complete.
|
||||
if not _CONFIG_VARS_INITIALIZED:
|
||||
if _CONFIG_VARS_INITIALIZED:
|
||||
# GH-126789: If sys.prefix or sys.exec_prefix were updated, invalidate the cache.
|
||||
prefix = os.path.normpath(sys.prefix)
|
||||
exec_prefix = os.path.normpath(sys.exec_prefix)
|
||||
if _CONFIG_VARS['prefix'] != prefix or _CONFIG_VARS['exec_prefix'] != exec_prefix:
|
||||
with _CONFIG_VARS_LOCK:
|
||||
_CONFIG_VARS_INITIALIZED = False
|
||||
_init_config_vars()
|
||||
else:
|
||||
# Initialize the config_vars cache.
|
||||
with _CONFIG_VARS_LOCK:
|
||||
# Test again with the lock held to avoid races. Note that
|
||||
# we test _CONFIG_VARS here, not _CONFIG_VARS_INITIALIZED,
|
||||
@@ -558,15 +621,6 @@ def get_config_vars(*args):
|
||||
# don't re-enter init_config_vars().
|
||||
if _CONFIG_VARS is None:
|
||||
_init_config_vars()
|
||||
else:
|
||||
# If the site module initialization happened after _CONFIG_VARS was
|
||||
# initialized, a virtual environment might have been activated, resulting in
|
||||
# variables like sys.prefix changing their value, so we need to re-init the
|
||||
# config vars (see GH-126789).
|
||||
if _CONFIG_VARS['base'] != os.path.normpath(sys.prefix):
|
||||
with _CONFIG_VARS_LOCK:
|
||||
_CONFIG_VARS_INITIALIZED = False
|
||||
_init_config_vars()
|
||||
|
||||
if args:
|
||||
vals = []
|
||||
@@ -627,34 +681,34 @@ def get_platform():
|
||||
|
||||
# Set for cross builds explicitly
|
||||
if "_PYTHON_HOST_PLATFORM" in os.environ:
|
||||
return os.environ["_PYTHON_HOST_PLATFORM"]
|
||||
osname, _, machine = os.environ["_PYTHON_HOST_PLATFORM"].partition('-')
|
||||
release = None
|
||||
else:
|
||||
# Try to distinguish various flavours of Unix
|
||||
osname, host, release, version, machine = os.uname()
|
||||
|
||||
# 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('/', '-')
|
||||
|
||||
# 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 == "android" or sys.platform == "android":
|
||||
osname = "android"
|
||||
release = get_config_var("ANDROID_API_LEVEL")
|
||||
|
||||
if osname[:5] == "linux":
|
||||
if sys.platform == "android":
|
||||
osname = "android"
|
||||
release = get_config_var("ANDROID_API_LEVEL")
|
||||
|
||||
# Wheel tags use the ABI names from Android's own tools.
|
||||
machine = {
|
||||
"x86_64": "x86_64",
|
||||
"i686": "x86",
|
||||
"aarch64": "arm64_v8a",
|
||||
"armv7l": "armeabi_v7a",
|
||||
}[machine]
|
||||
else:
|
||||
# At least on Linux/Intel, 'machine' is the processor --
|
||||
# i386, etc.
|
||||
# XXX what about Alpha, SPARC, etc?
|
||||
return f"{osname}-{machine}"
|
||||
# Wheel tags use the ABI names from Android's own tools.
|
||||
machine = {
|
||||
"x86_64": "x86_64",
|
||||
"i686": "x86",
|
||||
"aarch64": "arm64_v8a",
|
||||
"armv7l": "armeabi_v7a",
|
||||
}[machine]
|
||||
elif osname == "linux":
|
||||
# At least on Linux/Intel, 'machine' is the processor --
|
||||
# i386, etc.
|
||||
# XXX what about Alpha, SPARC, etc?
|
||||
return f"{osname}-{machine}"
|
||||
elif osname[:5] == "sunos":
|
||||
if release[0] >= "5": # SunOS 5 == Solaris 2
|
||||
osname = "solaris"
|
||||
@@ -686,7 +740,7 @@ def get_platform():
|
||||
get_config_vars(),
|
||||
osname, release, machine)
|
||||
|
||||
return f"{osname}-{release}-{machine}"
|
||||
return '-'.join(map(str, filter(None, (osname, release, machine))))
|
||||
|
||||
|
||||
def get_python_version():
|
||||
@@ -705,6 +759,15 @@ def expand_makefile_vars(s, vars):
|
||||
variable expansions; if 'vars' is the output of 'parse_makefile()',
|
||||
you're fine. Returns a variable-expanded version of 's'.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
warnings.warn(
|
||||
'sysconfig.expand_makefile_vars is deprecated and will be removed in '
|
||||
'Python 3.16. Use sysconfig.get_paths(vars=...) instead.',
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
import re
|
||||
|
||||
_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"
|
||||
|
||||
Vendored
+37
-9
@@ -1,10 +1,13 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
from sysconfig import (
|
||||
_ALWAYS_STR,
|
||||
_PYTHON_BUILD,
|
||||
_get_sysconfigdata_name,
|
||||
get_config_h_filename,
|
||||
get_config_var,
|
||||
get_config_vars,
|
||||
get_default_scheme,
|
||||
get_makefile_filename,
|
||||
@@ -157,6 +160,19 @@ def _print_config_dict(d, stream):
|
||||
print ("}", file=stream)
|
||||
|
||||
|
||||
def _get_pybuilddir():
|
||||
pybuilddir = f'build/lib.{get_platform()}-{get_python_version()}'
|
||||
if get_config_var('Py_DEBUG') == '1':
|
||||
pybuilddir += '-pydebug'
|
||||
return pybuilddir
|
||||
|
||||
|
||||
def _get_json_data_name():
|
||||
name = _get_sysconfigdata_name()
|
||||
assert name.startswith('_sysconfigdata')
|
||||
return name.replace('_sysconfigdata', '_sysconfig_vars') + '.json'
|
||||
|
||||
|
||||
def _generate_posix_vars():
|
||||
"""Generate the Python module containing build-time variables."""
|
||||
vars = {}
|
||||
@@ -185,6 +201,8 @@ def _generate_posix_vars():
|
||||
if _PYTHON_BUILD:
|
||||
vars['BLDSHARED'] = vars['LDSHARED']
|
||||
|
||||
name = _get_sysconfigdata_name()
|
||||
|
||||
# There's a chicken-and-egg situation on OS X with regards to the
|
||||
# _sysconfigdata module after the changes introduced by #15298:
|
||||
# get_config_vars() is called by get_platform() as part of the
|
||||
@@ -196,16 +214,13 @@ def _generate_posix_vars():
|
||||
# _sysconfigdata module manually and populate it with the build vars.
|
||||
# This is more than sufficient for ensuring the subsequent call to
|
||||
# get_platform() succeeds.
|
||||
name = _get_sysconfigdata_name()
|
||||
if 'darwin' in sys.platform:
|
||||
import types
|
||||
module = types.ModuleType(name)
|
||||
module.build_time_vars = vars
|
||||
sys.modules[name] = module
|
||||
# GH-127178: Since we started generating a .json file, we also need this to
|
||||
# be able to run sysconfig.get_config_vars().
|
||||
module = types.ModuleType(name)
|
||||
module.build_time_vars = vars
|
||||
sys.modules[name] = module
|
||||
|
||||
pybuilddir = f'build/lib.{get_platform()}-{get_python_version()}'
|
||||
if hasattr(sys, "gettotalrefcount"):
|
||||
pybuilddir += '-pydebug'
|
||||
pybuilddir = _get_pybuilddir()
|
||||
os.makedirs(pybuilddir, exist_ok=True)
|
||||
destfile = os.path.join(pybuilddir, name + '.py')
|
||||
|
||||
@@ -215,6 +230,19 @@ def _generate_posix_vars():
|
||||
f.write('build_time_vars = ')
|
||||
_print_config_dict(vars, stream=f)
|
||||
|
||||
print(f'Written {destfile}')
|
||||
|
||||
install_vars = get_config_vars()
|
||||
# Fix config vars to match the values after install (of the default environment)
|
||||
install_vars['projectbase'] = install_vars['BINDIR']
|
||||
install_vars['srcdir'] = install_vars['LIBPL']
|
||||
# Write a JSON file with the output of sysconfig.get_config_vars
|
||||
jsonfile = os.path.join(pybuilddir, _get_json_data_name())
|
||||
with open(jsonfile, 'w') as f:
|
||||
json.dump(install_vars, f, indent=2)
|
||||
|
||||
print(f'Written {jsonfile}')
|
||||
|
||||
# Create file used for sys.path fixup -- see Modules/getpath.c
|
||||
with open('pybuilddir.txt', 'w', encoding='utf8') as f:
|
||||
f.write(pybuilddir)
|
||||
|
||||
Vendored
+9
-8
@@ -20,12 +20,13 @@ class Test_OSXSupport(unittest.TestCase):
|
||||
self.prog_name = 'bogus_program_xxxx'
|
||||
self.temp_path_dir = os.path.abspath(os.getcwd())
|
||||
self.env = self.enterContext(os_helper.EnvironmentVarGuard())
|
||||
for cv in ('CFLAGS', 'LDFLAGS', 'CPPFLAGS',
|
||||
'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC',
|
||||
'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
|
||||
'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS'):
|
||||
if cv in self.env:
|
||||
self.env.unset(cv)
|
||||
|
||||
self.env.unset(
|
||||
'CFLAGS', 'LDFLAGS', 'CPPFLAGS',
|
||||
'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC',
|
||||
'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
|
||||
'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS'
|
||||
)
|
||||
|
||||
def add_expected_saved_initial_values(self, config_vars, expected_vars):
|
||||
# Ensure that the initial values for all modified config vars
|
||||
@@ -65,8 +66,8 @@ class Test_OSXSupport(unittest.TestCase):
|
||||
'cc not found - check xcode-select')
|
||||
|
||||
def test__get_system_version(self):
|
||||
self.assertTrue(platform.mac_ver()[0].startswith(
|
||||
_osx_support._get_system_version()))
|
||||
self.assertStartsWith(platform.mac_ver()[0],
|
||||
_osx_support._get_system_version())
|
||||
|
||||
def test__remove_original_values(self):
|
||||
config_vars = {
|
||||
|
||||
Vendored
+171
-79
@@ -9,8 +9,10 @@ import json
|
||||
import textwrap
|
||||
from copy import copy
|
||||
|
||||
from test import support
|
||||
from test.support import (
|
||||
captured_stdout,
|
||||
is_android,
|
||||
is_apple_mobile,
|
||||
is_wasi,
|
||||
PythonSymlink,
|
||||
@@ -19,14 +21,15 @@ from test.support import (
|
||||
from test.support.import_helper import import_module
|
||||
from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink,
|
||||
change_cwd)
|
||||
from test.support.venv import VirtualEnvironment
|
||||
from test.support.venv import VirtualEnvironmentMixin
|
||||
|
||||
import sysconfig
|
||||
from sysconfig import (get_paths, get_platform, get_config_vars,
|
||||
get_path, get_path_names, _INSTALL_SCHEMES,
|
||||
get_default_scheme, get_scheme_names, get_config_var,
|
||||
_expand_vars, _get_preferred_schemes)
|
||||
from sysconfig.__main__ import _main, _parse_makefile
|
||||
_expand_vars, _get_preferred_schemes,
|
||||
is_python_build, _PROJECT_BASE)
|
||||
from sysconfig.__main__ import _main, _parse_makefile, _get_pybuilddir, _get_json_data_name
|
||||
import _imp
|
||||
import _osx_support
|
||||
import _sysconfig
|
||||
@@ -35,10 +38,11 @@ import _sysconfig
|
||||
HAS_USER_BASE = sysconfig._HAS_USER_BASE
|
||||
|
||||
|
||||
class TestSysConfig(unittest.TestCase):
|
||||
class TestSysConfig(unittest.TestCase, VirtualEnvironmentMixin):
|
||||
|
||||
def setUp(self):
|
||||
super(TestSysConfig, self).setUp()
|
||||
self.maxDiff = None
|
||||
self.sys_path = sys.path[:]
|
||||
# patching os.uname
|
||||
if hasattr(os, 'uname'):
|
||||
@@ -50,6 +54,8 @@ class TestSysConfig(unittest.TestCase):
|
||||
os.uname = self._get_uname
|
||||
# saving the environment
|
||||
self.name = os.name
|
||||
self.prefix = sys.prefix
|
||||
self.exec_prefix = sys.exec_prefix
|
||||
self.platform = sys.platform
|
||||
self.version = sys.version
|
||||
self._framework = sys._framework
|
||||
@@ -74,6 +80,8 @@ class TestSysConfig(unittest.TestCase):
|
||||
else:
|
||||
del os.uname
|
||||
os.name = self.name
|
||||
sys.prefix = self.prefix
|
||||
sys.exec_prefix = self.exec_prefix
|
||||
sys.platform = self.platform
|
||||
sys.version = self.version
|
||||
sys._framework = self._framework
|
||||
@@ -104,12 +112,6 @@ class TestSysConfig(unittest.TestCase):
|
||||
elif os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
|
||||
def venv(self, **venv_create_args):
|
||||
return VirtualEnvironment.from_tmpdir(
|
||||
prefix=f'{self.id()}-venv-',
|
||||
**venv_create_args,
|
||||
)
|
||||
|
||||
def test_get_path_names(self):
|
||||
self.assertEqual(get_path_names(), sysconfig._SCHEME_KEYS)
|
||||
|
||||
@@ -160,14 +162,14 @@ class TestSysConfig(unittest.TestCase):
|
||||
self.assertIsInstance(schemes, dict)
|
||||
self.assertEqual(set(schemes), expected_schemes)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; ? ++++
|
||||
def test_posix_venv_scheme(self):
|
||||
# The following directories were hardcoded in the venv module
|
||||
# before bpo-45413, here we assert the posix_venv scheme does not regress
|
||||
binpath = 'bin'
|
||||
incpath = 'include'
|
||||
libpath = os.path.join('lib',
|
||||
# XXX: RUSTPYTHON
|
||||
f'rustpython{sysconfig._get_python_version_abi()}',
|
||||
f'python{sysconfig._get_python_version_abi()}',
|
||||
'site-packages')
|
||||
|
||||
# Resolve the paths in an imaginary venv/ directory
|
||||
@@ -185,7 +187,7 @@ class TestSysConfig(unittest.TestCase):
|
||||
# The include directory on POSIX isn't exactly the same as before,
|
||||
# but it is "within"
|
||||
sysconfig_includedir = sysconfig.get_path('include', scheme='posix_venv', vars=vars)
|
||||
self.assertTrue(sysconfig_includedir.startswith(incpath + os.sep))
|
||||
self.assertStartsWith(sysconfig_includedir, incpath + os.sep)
|
||||
|
||||
def test_nt_venv_scheme(self):
|
||||
# The following directories were hardcoded in the venv module
|
||||
@@ -386,7 +388,7 @@ class TestSysConfig(unittest.TestCase):
|
||||
|
||||
# XXX more platforms to tests here
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: False is not true : /Users/youknowone/Projects/RustPython2/include/python3.14t/pyconfig.h
|
||||
@unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds")
|
||||
@unittest.skipIf(is_apple_mobile,
|
||||
f"{sys.platform} doesn't distribute header files in the runtime environment")
|
||||
@@ -459,25 +461,25 @@ class TestSysConfig(unittest.TestCase):
|
||||
soabi = sysconfig.get_config_var('SOABI')
|
||||
self.assertIn(soabi, _imp.extension_suffixes()[0])
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Expected str, not NoneType
|
||||
def test_library(self):
|
||||
library = sysconfig.get_config_var('LIBRARY')
|
||||
ldlibrary = sysconfig.get_config_var('LDLIBRARY')
|
||||
major, minor = sys.version_info[:2]
|
||||
if sys.platform == 'win32':
|
||||
self.assertTrue(library.startswith(f'python{major}{minor}'))
|
||||
self.assertTrue(library.endswith('.dll'))
|
||||
abiflags = sysconfig.get_config_var('ABIFLAGS')
|
||||
if sys.platform.startswith('win'):
|
||||
self.assertEqual(library, f'python{major}{minor}{abiflags}.dll')
|
||||
self.assertEqual(library, ldlibrary)
|
||||
elif is_apple_mobile:
|
||||
framework = sysconfig.get_config_var('PYTHONFRAMEWORK')
|
||||
self.assertEqual(ldlibrary, f"{framework}.framework/{framework}")
|
||||
else:
|
||||
self.assertTrue(library.startswith(f'libpython{major}.{minor}'))
|
||||
self.assertTrue(library.endswith('.a'))
|
||||
self.assertStartsWith(library, f'libpython{major}.{minor}')
|
||||
self.assertEndsWith(library, '.a')
|
||||
if sys.platform == 'darwin' and sys._framework:
|
||||
self.skipTest('gh-110824: skip LDLIBRARY test for framework build')
|
||||
else:
|
||||
self.assertTrue(ldlibrary.startswith(f'libpython{major}.{minor}'))
|
||||
self.assertStartsWith(ldlibrary, f'libpython{major}.{minor}')
|
||||
|
||||
@unittest.skipUnless(sys.platform == "darwin", "test only relevant on MacOSX")
|
||||
@requires_subprocess()
|
||||
@@ -523,7 +525,7 @@ class TestSysConfig(unittest.TestCase):
|
||||
self.assertEqual(status, 0)
|
||||
self.assertEqual(my_platform, test_platform)
|
||||
|
||||
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON')
|
||||
@unittest.expectedFailureIf(sys.platform != "win32", "TODO: RUSTPYTHON")
|
||||
@unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds")
|
||||
@unittest.skipIf(is_apple_mobile,
|
||||
f"{sys.platform} doesn't include config folder at runtime")
|
||||
@@ -540,13 +542,10 @@ class TestSysConfig(unittest.TestCase):
|
||||
Python_h = os.path.join(srcdir, 'Include', 'Python.h')
|
||||
self.assertTrue(os.path.exists(Python_h), Python_h)
|
||||
# <srcdir>/PC/pyconfig.h.in always exists even if unused
|
||||
pyconfig_h = os.path.join(srcdir, 'PC', 'pyconfig.h.in')
|
||||
self.assertTrue(os.path.exists(pyconfig_h), pyconfig_h)
|
||||
pyconfig_h_in = os.path.join(srcdir, 'pyconfig.h.in')
|
||||
self.assertTrue(os.path.exists(pyconfig_h_in), pyconfig_h_in)
|
||||
if os.name == 'nt':
|
||||
# <executable dir>/pyconfig.h exists on Windows in a build tree
|
||||
pyconfig_h = os.path.join(sys.executable, '..', 'pyconfig.h')
|
||||
pyconfig_h = os.path.join(srcdir, 'PC', 'pyconfig.h')
|
||||
self.assertTrue(os.path.exists(pyconfig_h), pyconfig_h)
|
||||
elif os.name == 'posix':
|
||||
makefile_dir = os.path.dirname(sysconfig.get_makefile_filename())
|
||||
@@ -581,10 +580,8 @@ class TestSysConfig(unittest.TestCase):
|
||||
expected_suffixes = 'i386-linux-gnu.so', 'x86_64-linux-gnux32.so', 'i386-linux-musl.so'
|
||||
else: # 8 byte pointer size
|
||||
expected_suffixes = 'x86_64-linux-gnu.so', 'x86_64-linux-musl.so'
|
||||
self.assertTrue(suffix.endswith(expected_suffixes),
|
||||
f'unexpected suffix {suffix!r}')
|
||||
self.assertEndsWith(suffix, expected_suffixes)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@unittest.skipUnless(sys.platform == 'android', 'Android-specific test')
|
||||
def test_android_ext_suffix(self):
|
||||
machine = platform.machine()
|
||||
@@ -595,86 +592,169 @@ class TestSysConfig(unittest.TestCase):
|
||||
"aarch64": "aarch64-linux-android",
|
||||
"armv7l": "arm-linux-androideabi",
|
||||
}[machine]
|
||||
self.assertTrue(suffix.endswith(f"-{expected_triplet}.so"),
|
||||
f"{machine=}, {suffix=}")
|
||||
self.assertEndsWith(suffix, f"-{expected_triplet}.so")
|
||||
|
||||
@unittest.skipUnless(sys.platform == 'darwin', 'OS X-specific test')
|
||||
def test_osx_ext_suffix(self):
|
||||
suffix = sysconfig.get_config_var('EXT_SUFFIX')
|
||||
self.assertTrue(suffix.endswith('-darwin.so'), suffix)
|
||||
self.assertEndsWith(suffix, '-darwin.so')
|
||||
|
||||
def test_always_set_py_debug(self):
|
||||
self.assertIn('Py_DEBUG', sysconfig.get_config_vars())
|
||||
Py_DEBUG = sysconfig.get_config_var('Py_DEBUG')
|
||||
self.assertIn(Py_DEBUG, (0, 1))
|
||||
self.assertEqual(Py_DEBUG, support.Py_DEBUG)
|
||||
|
||||
def test_always_set_py_gil_disabled(self):
|
||||
self.assertIn('Py_GIL_DISABLED', sysconfig.get_config_vars())
|
||||
Py_GIL_DISABLED = sysconfig.get_config_var('Py_GIL_DISABLED')
|
||||
self.assertIn(Py_GIL_DISABLED, (0, 1))
|
||||
self.assertEqual(Py_GIL_DISABLED, support.Py_GIL_DISABLED)
|
||||
|
||||
def test_abiflags(self):
|
||||
# If this test fails on some platforms, maintainers should update the
|
||||
# test to make it pass, rather than changing the definition of ABIFLAGS.
|
||||
self.assertIn('abiflags', sysconfig.get_config_vars())
|
||||
self.assertIn('ABIFLAGS', sysconfig.get_config_vars())
|
||||
abiflags = sysconfig.get_config_var('abiflags')
|
||||
ABIFLAGS = sysconfig.get_config_var('ABIFLAGS')
|
||||
self.assertIsInstance(abiflags, str)
|
||||
self.assertIsInstance(ABIFLAGS, str)
|
||||
self.assertIn(abiflags, ABIFLAGS)
|
||||
if os.name == 'nt':
|
||||
self.assertEqual(abiflags, '')
|
||||
|
||||
if not sys.platform.startswith('win'):
|
||||
valid_abiflags = ('', 't', 'd', 'td')
|
||||
else:
|
||||
# Windows uses '_d' rather than 'd'; see also test_abi_debug below
|
||||
valid_abiflags = ('', 't', '_d', 't_d')
|
||||
|
||||
self.assertIn(ABIFLAGS, valid_abiflags)
|
||||
|
||||
def test_abi_debug(self):
|
||||
ABIFLAGS = sysconfig.get_config_var('ABIFLAGS')
|
||||
if support.Py_DEBUG:
|
||||
self.assertIn('d', ABIFLAGS)
|
||||
else:
|
||||
self.assertNotIn('d', ABIFLAGS)
|
||||
|
||||
# The 'd' flag should always be the last one on Windows.
|
||||
# On Windows, the debug flag is used differently with a underscore prefix.
|
||||
# For example, `python{X}.{Y}td` on Unix and `python{X}.{Y}t_d.exe` on Windows.
|
||||
if support.Py_DEBUG and sys.platform.startswith('win'):
|
||||
self.assertEndsWith(ABIFLAGS, '_d')
|
||||
|
||||
def test_abi_thread(self):
|
||||
abi_thread = sysconfig.get_config_var('abi_thread')
|
||||
ABIFLAGS = sysconfig.get_config_var('ABIFLAGS')
|
||||
self.assertIsInstance(abi_thread, str)
|
||||
if support.Py_GIL_DISABLED:
|
||||
self.assertEqual(abi_thread, 't')
|
||||
self.assertIn('t', ABIFLAGS)
|
||||
else:
|
||||
self.assertEqual(abi_thread, '')
|
||||
self.assertNotIn('t', ABIFLAGS)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@requires_subprocess()
|
||||
def test_config_vars_depend_on_site_initialization(self):
|
||||
@unittest.skipIf(os.name == 'nt', 'TODO: RUSTPYTHON; venv creates python.exe but sys.executable is rustpython.exe')
|
||||
def test_makefile_overwrites_config_vars(self):
|
||||
script = textwrap.dedent("""
|
||||
import sysconfig
|
||||
import sys, sysconfig
|
||||
|
||||
config_vars = sysconfig.get_config_vars()
|
||||
data = {
|
||||
'prefix': sys.prefix,
|
||||
'exec_prefix': sys.exec_prefix,
|
||||
'base_prefix': sys.base_prefix,
|
||||
'base_exec_prefix': sys.base_exec_prefix,
|
||||
'config_vars': sysconfig.get_config_vars(),
|
||||
}
|
||||
|
||||
import json
|
||||
print(json.dumps(config_vars, indent=2))
|
||||
print(json.dumps(data, indent=2))
|
||||
""")
|
||||
|
||||
# We need to run the test inside a virtual environment so that
|
||||
# sys.prefix/sys.exec_prefix have a different value from the
|
||||
# prefix/exec_prefix Makefile variables.
|
||||
with self.venv() as venv:
|
||||
site_config_vars = json.loads(venv.run('-c', script).stdout)
|
||||
no_site_config_vars = json.loads(venv.run('-S', '-c', script).stdout)
|
||||
data = json.loads(venv.run('-c', script).stdout)
|
||||
|
||||
self.assertNotEqual(site_config_vars, no_site_config_vars)
|
||||
# With the site initialization, the virtual environment should be enabled.
|
||||
self.assertEqual(site_config_vars['base'], venv.prefix)
|
||||
self.assertEqual(site_config_vars['platbase'], venv.prefix)
|
||||
#self.assertEqual(site_config_vars['prefix'], venv.prefix) # # FIXME: prefix gets overwriten by _init_posix
|
||||
# Without the site initialization, the virtual environment should be disabled.
|
||||
self.assertEqual(no_site_config_vars['base'], site_config_vars['installed_base'])
|
||||
self.assertEqual(no_site_config_vars['platbase'], site_config_vars['installed_platbase'])
|
||||
# We expect sysconfig.get_config_vars to correctly reflect sys.prefix/sys.exec_prefix
|
||||
self.assertEqual(data['prefix'], data['config_vars']['prefix'])
|
||||
self.assertEqual(data['exec_prefix'], data['config_vars']['exec_prefix'])
|
||||
# As a sanity check, just make sure sys.prefix/sys.exec_prefix really
|
||||
# are different from the Makefile values.
|
||||
# sys.base_prefix/sys.base_exec_prefix should reflect the value of the
|
||||
# prefix/exec_prefix Makefile variables, so we use them in the comparison.
|
||||
self.assertNotEqual(data['prefix'], data['base_prefix'])
|
||||
self.assertNotEqual(data['exec_prefix'], data['base_exec_prefix'])
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@requires_subprocess()
|
||||
def test_config_vars_recalculation_after_site_initialization(self):
|
||||
script = textwrap.dedent("""
|
||||
import sysconfig
|
||||
@unittest.skipIf(os.name != 'posix', '_sysconfig-vars JSON file is only available on POSIX')
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; JSON is generated at build time in CPython
|
||||
@unittest.skipIf(is_wasi, "_sysconfig-vars JSON file currently isn't available on WASI")
|
||||
@unittest.skipIf(is_android or is_apple_mobile, 'Android and iOS change the prefix')
|
||||
def test_sysconfigdata_json(self):
|
||||
if '_PYTHON_SYSCONFIGDATA_PATH' in os.environ:
|
||||
data_dir = os.environ['_PYTHON_SYSCONFIGDATA_PATH']
|
||||
elif is_python_build():
|
||||
data_dir = os.path.join(_PROJECT_BASE, _get_pybuilddir())
|
||||
else:
|
||||
data_dir = sys._stdlib_dir
|
||||
|
||||
before = sysconfig.get_config_vars()
|
||||
json_data_path = os.path.join(data_dir, _get_json_data_name())
|
||||
|
||||
import site
|
||||
site.main()
|
||||
with open(json_data_path) as f:
|
||||
json_config_vars = json.load(f)
|
||||
|
||||
after = sysconfig.get_config_vars()
|
||||
system_config_vars = get_config_vars()
|
||||
|
||||
import json
|
||||
print(json.dumps({'before': before, 'after': after}, indent=2))
|
||||
""")
|
||||
# Keys dependent on uncontrollable external context
|
||||
ignore_keys = {'userbase'}
|
||||
# Keys dependent on Python being run outside the build directrory
|
||||
if sysconfig.is_python_build():
|
||||
ignore_keys |= {'srcdir'}
|
||||
# Keys dependent on the executable location
|
||||
if os.path.dirname(sys.executable) != system_config_vars['BINDIR']:
|
||||
ignore_keys |= {'projectbase'}
|
||||
# Keys dependent on the environment (different inside virtual environments)
|
||||
if sys.prefix != sys.base_prefix:
|
||||
ignore_keys |= {'prefix', 'exec_prefix', 'base', 'platbase'}
|
||||
# Keys dependent on Python being run from the prefix targetted when building (different on relocatable installs)
|
||||
if sysconfig._installation_is_relocated():
|
||||
ignore_keys |= {'prefix', 'exec_prefix', 'base', 'platbase', 'installed_base', 'installed_platbase', 'srcdir'}
|
||||
|
||||
with self.venv() as venv:
|
||||
config_vars = json.loads(venv.run('-S', '-c', script).stdout)
|
||||
for key in ignore_keys:
|
||||
json_config_vars.pop(key, None)
|
||||
system_config_vars.pop(key, None)
|
||||
|
||||
self.assertNotEqual(config_vars['before'], config_vars['after'])
|
||||
self.assertEqual(config_vars['after']['base'], venv.prefix)
|
||||
#self.assertEqual(config_vars['after']['prefix'], venv.prefix) # FIXME: prefix gets overwriten by _init_posix
|
||||
#self.assertEqual(config_vars['after']['exec_prefix'], venv.prefix) # FIXME: exec_prefix gets overwriten by _init_posix
|
||||
self.assertEqual(system_config_vars, json_config_vars)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@requires_subprocess()
|
||||
def test_paths_depend_on_site_initialization(self):
|
||||
script = textwrap.dedent("""
|
||||
import sysconfig
|
||||
def test_sysconfig_config_vars_no_prefix_cache(self):
|
||||
sys.prefix = 'prefix-AAA'
|
||||
sys.exec_prefix = 'exec-prefix-AAA'
|
||||
|
||||
paths = sysconfig.get_paths()
|
||||
config_vars = sysconfig.get_config_vars()
|
||||
|
||||
import json
|
||||
print(json.dumps(paths, indent=2))
|
||||
""")
|
||||
self.assertEqual(config_vars['prefix'], sys.prefix)
|
||||
self.assertEqual(config_vars['base'], sys.prefix)
|
||||
self.assertEqual(config_vars['exec_prefix'], sys.exec_prefix)
|
||||
self.assertEqual(config_vars['platbase'], sys.exec_prefix)
|
||||
|
||||
with self.venv() as venv:
|
||||
site_paths = json.loads(venv.run('-c', script).stdout)
|
||||
no_site_paths = json.loads(venv.run('-S', '-c', script).stdout)
|
||||
sys.prefix = 'prefix-BBB'
|
||||
sys.exec_prefix = 'exec-prefix-BBB'
|
||||
|
||||
self.assertNotEqual(site_paths, no_site_paths)
|
||||
config_vars = sysconfig.get_config_vars()
|
||||
|
||||
self.assertEqual(config_vars['prefix'], sys.prefix)
|
||||
self.assertEqual(config_vars['base'], sys.prefix)
|
||||
self.assertEqual(config_vars['exec_prefix'], sys.exec_prefix)
|
||||
self.assertEqual(config_vars['platbase'], sys.exec_prefix)
|
||||
|
||||
|
||||
class MakefileTests(unittest.TestCase):
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: False is not true : /Users/youknowone/Projects/RustPython2/lib/python3.14t/config-3.14t-aarch64-apple-darwin/Makefile
|
||||
@unittest.skipIf(sys.platform.startswith('win'),
|
||||
'Test is not Windows compatible')
|
||||
@unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds")
|
||||
@@ -712,6 +792,18 @@ class DeprecationTests(unittest.TestCase):
|
||||
else:
|
||||
return self.assertWarns(DeprecationWarning, msg=deprecation_msg)
|
||||
|
||||
def test_expand_makefile_vars(self):
|
||||
with self.deprecated(
|
||||
removal_version=(3, 16),
|
||||
deprecation_msg=(
|
||||
'sysconfig.expand_makefile_vars is deprecated and will be removed in '
|
||||
'Python 3.16. Use sysconfig.get_paths(vars=...) instead.',
|
||||
),
|
||||
error=AttributeError,
|
||||
error_msg="module 'sysconfig' has no attribute 'expand_makefile_vars'",
|
||||
):
|
||||
sysconfig.expand_makefile_vars('', {})
|
||||
|
||||
def test_is_python_build_check_home(self):
|
||||
with self.deprecated(
|
||||
removal_version=(3, 15),
|
||||
|
||||
Reference in new issue
Block a user