mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Update {site,sysconfig}.py from 3.13.7 (#6132)
* Update `{site,sysconfig}.py` from 3.13.7
* Update vm/src/stdlib/sysconfig.rs
This commit is contained in:
1 parent
74c2d490ac
commit
7044d43dc8
8 files changed
+901
-461
No files matched your search
Vendored
+154
-75
@@ -75,6 +75,7 @@ import builtins
|
||||
import _sitebuiltins
|
||||
import io
|
||||
import stat
|
||||
import errno
|
||||
|
||||
# Prefixes for site-packages; add additional prefixes like /usr/local here
|
||||
PREFIXES = [sys.prefix, sys.exec_prefix]
|
||||
@@ -179,35 +180,46 @@ def addpackage(sitedir, name, known_paths):
|
||||
return
|
||||
_trace(f"Processing .pth file: {fullname!r}")
|
||||
try:
|
||||
# locale encoding is not ideal especially on Windows. But we have used
|
||||
# it for a long time. setuptools uses the locale encoding too.
|
||||
f = io.TextIOWrapper(io.open_code(fullname), encoding="locale")
|
||||
with io.open_code(fullname) as f:
|
||||
pth_content = f.read()
|
||||
except OSError:
|
||||
return
|
||||
with f:
|
||||
for n, line in enumerate(f):
|
||||
if line.startswith("#"):
|
||||
|
||||
try:
|
||||
# Accept BOM markers in .pth files as we do in source files
|
||||
# (Windows PowerShell 5.1 makes it hard to emit UTF-8 files without a BOM)
|
||||
pth_content = pth_content.decode("utf-8-sig")
|
||||
except UnicodeDecodeError:
|
||||
# Fallback to locale encoding for backward compatibility.
|
||||
# We will deprecate this fallback in the future.
|
||||
import locale
|
||||
pth_content = pth_content.decode(locale.getencoding())
|
||||
_trace(f"Cannot read {fullname!r} as UTF-8. "
|
||||
f"Using fallback encoding {locale.getencoding()!r}")
|
||||
|
||||
for n, line in enumerate(pth_content.splitlines(), 1):
|
||||
if line.startswith("#"):
|
||||
continue
|
||||
if line.strip() == "":
|
||||
continue
|
||||
try:
|
||||
if line.startswith(("import ", "import\t")):
|
||||
exec(line)
|
||||
continue
|
||||
if line.strip() == "":
|
||||
continue
|
||||
try:
|
||||
if line.startswith(("import ", "import\t")):
|
||||
exec(line)
|
||||
continue
|
||||
line = line.rstrip()
|
||||
dir, dircase = makepath(sitedir, line)
|
||||
if not dircase in known_paths and os.path.exists(dir):
|
||||
sys.path.append(dir)
|
||||
known_paths.add(dircase)
|
||||
except Exception as exc:
|
||||
print("Error processing line {:d} of {}:\n".format(n+1, fullname),
|
||||
file=sys.stderr)
|
||||
import traceback
|
||||
for record in traceback.format_exception(exc):
|
||||
for line in record.splitlines():
|
||||
print(' '+line, file=sys.stderr)
|
||||
print("\nRemainder of file ignored", file=sys.stderr)
|
||||
break
|
||||
line = line.rstrip()
|
||||
dir, dircase = makepath(sitedir, line)
|
||||
if dircase not in known_paths and os.path.exists(dir):
|
||||
sys.path.append(dir)
|
||||
known_paths.add(dircase)
|
||||
except Exception as exc:
|
||||
print(f"Error processing line {n:d} of {fullname}:\n",
|
||||
file=sys.stderr)
|
||||
import traceback
|
||||
for record in traceback.format_exception(exc):
|
||||
for line in record.splitlines():
|
||||
print(' '+line, file=sys.stderr)
|
||||
print("\nRemainder of file ignored", file=sys.stderr)
|
||||
break
|
||||
if reset:
|
||||
known_paths = None
|
||||
return known_paths
|
||||
@@ -270,14 +282,18 @@ def check_enableusersite():
|
||||
#
|
||||
# See https://bugs.python.org/issue29585
|
||||
|
||||
# Copy of sysconfig._get_implementation()
|
||||
def _get_implementation():
|
||||
return 'RustPython' # XXX: RustPython; for site-packages
|
||||
|
||||
# Copy of sysconfig._getuserbase()
|
||||
def _getuserbase():
|
||||
env_base = os.environ.get("PYTHONUSERBASE", None)
|
||||
if env_base:
|
||||
return env_base
|
||||
|
||||
# Emscripten, VxWorks, and WASI have no home directories
|
||||
if sys.platform in {"emscripten", "vxworks", "wasi"}:
|
||||
# Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories
|
||||
if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
|
||||
return None
|
||||
|
||||
def joinuser(*args):
|
||||
@@ -285,8 +301,7 @@ def _getuserbase():
|
||||
|
||||
if os.name == "nt":
|
||||
base = os.environ.get("APPDATA") or "~"
|
||||
# XXX: RUSTPYTHON; please keep this change for site-packages
|
||||
return joinuser(base, "RustPython")
|
||||
return joinuser(base, _get_implementation())
|
||||
|
||||
if sys.platform == "darwin" and sys._framework:
|
||||
return joinuser("~", "Library", sys._framework,
|
||||
@@ -298,15 +313,22 @@ def _getuserbase():
|
||||
# Same to sysconfig.get_path('purelib', os.name+'_user')
|
||||
def _get_path(userbase):
|
||||
version = sys.version_info
|
||||
if hasattr(sys, 'abiflags') and 't' in sys.abiflags:
|
||||
abi_thread = 't'
|
||||
else:
|
||||
abi_thread = ''
|
||||
|
||||
implementation = _get_implementation()
|
||||
implementation_lower = implementation.lower()
|
||||
if os.name == 'nt':
|
||||
ver_nodot = sys.winver.replace('.', '')
|
||||
return f'{userbase}\\RustPython{ver_nodot}\\site-packages'
|
||||
return f'{userbase}\\{implementation}{ver_nodot}\\site-packages'
|
||||
|
||||
if sys.platform == 'darwin' and sys._framework:
|
||||
return f'{userbase}/lib/rustpython/site-packages'
|
||||
return f'{userbase}/lib/{implementation_lower}/site-packages'
|
||||
|
||||
return f'{userbase}/lib/rustpython{version[0]}.{version[1]}/site-packages'
|
||||
# XXX: RUSTPYTHON
|
||||
return f'{userbase}/lib/rustpython{version[0]}.{version[1]}{abi_thread}/site-packages'
|
||||
|
||||
|
||||
def getuserbase():
|
||||
@@ -372,6 +394,12 @@ def getsitepackages(prefixes=None):
|
||||
continue
|
||||
seen.add(prefix)
|
||||
|
||||
implementation = _get_implementation().lower()
|
||||
ver = sys.version_info
|
||||
if hasattr(sys, 'abiflags') and 't' in sys.abiflags:
|
||||
abi_thread = 't'
|
||||
else:
|
||||
abi_thread = ''
|
||||
if os.sep == '/':
|
||||
libdirs = [sys.platlibdir]
|
||||
if sys.platlibdir != "lib":
|
||||
@@ -379,8 +407,7 @@ def getsitepackages(prefixes=None):
|
||||
|
||||
for libdir in libdirs:
|
||||
path = os.path.join(prefix, libdir,
|
||||
# XXX: RUSTPYTHON; please keep this change for site-packages
|
||||
"rustpython%d.%d" % sys.version_info[:2],
|
||||
f"{implementation}{ver[0]}.{ver[1]}{abi_thread}",
|
||||
"site-packages")
|
||||
sitepackages.append(path)
|
||||
else:
|
||||
@@ -417,8 +444,9 @@ def setcopyright():
|
||||
"""Set 'copyright' and 'credits' in builtins"""
|
||||
builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright)
|
||||
builtins.credits = _sitebuiltins._Printer("credits", """\
|
||||
Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
|
||||
for supporting Python development. See www.python.org for more information.""")
|
||||
Thanks to CWI, CNRI, BeOpen, Zope Corporation, the Python Software
|
||||
Foundation, and a cast of thousands for supporting Python
|
||||
development. See www.python.org for more information.""")
|
||||
files, dirs = [], []
|
||||
# Not all modules are required to have a __file__ attribute. See
|
||||
# PEP 420 for more details.
|
||||
@@ -437,27 +465,76 @@ def setcopyright():
|
||||
def sethelper():
|
||||
builtins.help = _sitebuiltins._Helper()
|
||||
|
||||
|
||||
def gethistoryfile():
|
||||
"""Check if the PYTHON_HISTORY environment variable is set and define
|
||||
it as the .python_history file. If PYTHON_HISTORY is not set, use the
|
||||
default .python_history file.
|
||||
"""
|
||||
if not sys.flags.ignore_environment:
|
||||
history = os.environ.get("PYTHON_HISTORY")
|
||||
if history:
|
||||
return history
|
||||
return os.path.join(os.path.expanduser('~'),
|
||||
'.python_history')
|
||||
|
||||
|
||||
def enablerlcompleter():
|
||||
"""Enable default readline configuration on interactive prompts, by
|
||||
registering a sys.__interactivehook__.
|
||||
"""
|
||||
sys.__interactivehook__ = register_readline
|
||||
|
||||
|
||||
def register_readline():
|
||||
"""Configure readline completion on interactive prompts.
|
||||
|
||||
If the readline module can be imported, the hook will set the Tab key
|
||||
as completion key and register ~/.python_history as history file.
|
||||
This can be overridden in the sitecustomize or usercustomize module,
|
||||
or in a PYTHONSTARTUP file.
|
||||
"""
|
||||
def register_readline():
|
||||
import atexit
|
||||
if not sys.flags.ignore_environment:
|
||||
PYTHON_BASIC_REPL = os.getenv("PYTHON_BASIC_REPL")
|
||||
else:
|
||||
PYTHON_BASIC_REPL = False
|
||||
|
||||
import atexit
|
||||
|
||||
try:
|
||||
try:
|
||||
import readline
|
||||
import rlcompleter
|
||||
except ImportError:
|
||||
return
|
||||
readline = None
|
||||
else:
|
||||
import rlcompleter # noqa: F401
|
||||
except ImportError:
|
||||
return
|
||||
|
||||
try:
|
||||
if PYTHON_BASIC_REPL:
|
||||
CAN_USE_PYREPL = False
|
||||
else:
|
||||
original_path = sys.path
|
||||
sys.path = [p for p in original_path if p != '']
|
||||
try:
|
||||
import _pyrepl.readline
|
||||
if os.name == "nt":
|
||||
import _pyrepl.windows_console
|
||||
console_errors = (_pyrepl.windows_console._error,)
|
||||
else:
|
||||
import _pyrepl.unix_console
|
||||
console_errors = _pyrepl.unix_console._error
|
||||
from _pyrepl.main import CAN_USE_PYREPL
|
||||
finally:
|
||||
sys.path = original_path
|
||||
except ImportError:
|
||||
return
|
||||
|
||||
if readline is not None:
|
||||
# Reading the initialization (config) file may not be enough to set a
|
||||
# completion key, so we set one first and then read the file.
|
||||
readline_doc = getattr(readline, '__doc__', '')
|
||||
if readline_doc is not None and 'libedit' in readline_doc:
|
||||
if readline.backend == 'editline':
|
||||
readline.parse_and_bind('bind ^I rl_complete')
|
||||
else:
|
||||
readline.parse_and_bind('tab: complete')
|
||||
@@ -471,30 +548,44 @@ def enablerlcompleter():
|
||||
# want to ignore the exception.
|
||||
pass
|
||||
|
||||
if readline.get_current_history_length() == 0:
|
||||
# If no history was loaded, default to .python_history.
|
||||
# The guard is necessary to avoid doubling history size at
|
||||
# each interpreter exit when readline was already configured
|
||||
# through a PYTHONSTARTUP hook, see:
|
||||
# http://bugs.python.org/issue5845#msg198636
|
||||
history = os.path.join(os.path.expanduser('~'),
|
||||
'.python_history')
|
||||
if readline is None or readline.get_current_history_length() == 0:
|
||||
# If no history was loaded, default to .python_history,
|
||||
# or PYTHON_HISTORY.
|
||||
# The guard is necessary to avoid doubling history size at
|
||||
# each interpreter exit when readline was already configured
|
||||
# through a PYTHONSTARTUP hook, see:
|
||||
# http://bugs.python.org/issue5845#msg198636
|
||||
history = gethistoryfile()
|
||||
|
||||
if CAN_USE_PYREPL:
|
||||
readline_module = _pyrepl.readline
|
||||
exceptions = (OSError, *console_errors)
|
||||
else:
|
||||
if readline is None:
|
||||
return
|
||||
readline_module = readline
|
||||
exceptions = OSError
|
||||
|
||||
try:
|
||||
readline_module.read_history_file(history)
|
||||
except exceptions:
|
||||
pass
|
||||
|
||||
def write_history():
|
||||
try:
|
||||
readline.read_history_file(history)
|
||||
except OSError:
|
||||
readline_module.write_history_file(history)
|
||||
except (FileNotFoundError, PermissionError):
|
||||
# home directory does not exist or is not writable
|
||||
# https://bugs.python.org/issue19891
|
||||
pass
|
||||
except OSError:
|
||||
if errno.EROFS:
|
||||
pass # gh-128066: read-only file system
|
||||
else:
|
||||
raise
|
||||
|
||||
def write_history():
|
||||
try:
|
||||
readline.write_history_file(history)
|
||||
except OSError:
|
||||
# bpo-19891, bpo-41193: Home directory does not exist
|
||||
# or is not writable, or the filesystem is read-only.
|
||||
pass
|
||||
atexit.register(write_history)
|
||||
|
||||
atexit.register(write_history)
|
||||
|
||||
sys.__interactivehook__ = register_readline
|
||||
|
||||
def venv(known_paths):
|
||||
global PREFIXES, ENABLE_USER_SITE
|
||||
@@ -679,17 +770,5 @@ def _script():
|
||||
print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
|
||||
sys.exit(10)
|
||||
|
||||
def gethistoryfile():
|
||||
"""Check if the PYTHON_HISTORY environment variable is set and define
|
||||
it as the .python_history file. If PYTHON_HISTORY is not set, use the
|
||||
default .python_history file.
|
||||
"""
|
||||
if not sys.flags.ignore_environment:
|
||||
history = os.environ.get("PYTHON_HISTORY")
|
||||
if history:
|
||||
return history
|
||||
return os.path.join(os.path.expanduser('~'),
|
||||
'.python_history')
|
||||
|
||||
if __name__ == '__main__':
|
||||
_script()
|
||||
+208
-344
@@ -1,10 +1,9 @@
|
||||
# XXX: RUSTPYTHON; Trick to make sysconfig work as RustPython
|
||||
exec(r'''
|
||||
"""Access to Python's configuration information."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from os.path import pardir, realpath
|
||||
import threading
|
||||
from os.path import realpath
|
||||
|
||||
__all__ = [
|
||||
'get_config_h_filename',
|
||||
@@ -22,29 +21,30 @@ __all__ = [
|
||||
|
||||
# Keys for get_config_var() that are never converted to Python integers.
|
||||
_ALWAYS_STR = {
|
||||
'IPHONEOS_DEPLOYMENT_TARGET',
|
||||
'MACOSX_DEPLOYMENT_TARGET',
|
||||
}
|
||||
|
||||
_INSTALL_SCHEMES = {
|
||||
'posix_prefix': {
|
||||
'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}',
|
||||
'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}',
|
||||
'purelib': '{base}/lib/python{py_version_short}/site-packages',
|
||||
'platlib': '{platbase}/{platlibdir}/python{py_version_short}/site-packages',
|
||||
'stdlib': '{installed_base}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',
|
||||
'platstdlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',
|
||||
'purelib': '{base}/lib/{implementation_lower}{py_version_short}{abi_thread}/site-packages',
|
||||
'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}/site-packages',
|
||||
'include':
|
||||
'{installed_base}/include/python{py_version_short}{abiflags}',
|
||||
'{installed_base}/include/{implementation_lower}{py_version_short}{abiflags}',
|
||||
'platinclude':
|
||||
'{installed_platbase}/include/python{py_version_short}{abiflags}',
|
||||
'{installed_platbase}/include/{implementation_lower}{py_version_short}{abiflags}',
|
||||
'scripts': '{base}/bin',
|
||||
'data': '{base}',
|
||||
},
|
||||
'posix_home': {
|
||||
'stdlib': '{installed_base}/lib/python',
|
||||
'platstdlib': '{base}/lib/python',
|
||||
'purelib': '{base}/lib/python',
|
||||
'platlib': '{base}/lib/python',
|
||||
'include': '{installed_base}/include/python',
|
||||
'platinclude': '{installed_base}/include/python',
|
||||
'stdlib': '{installed_base}/lib/{implementation_lower}',
|
||||
'platstdlib': '{base}/lib/{implementation_lower}',
|
||||
'purelib': '{base}/lib/{implementation_lower}',
|
||||
'platlib': '{base}/lib/{implementation_lower}',
|
||||
'include': '{installed_base}/include/{implementation_lower}',
|
||||
'platinclude': '{installed_base}/include/{implementation_lower}',
|
||||
'scripts': '{base}/bin',
|
||||
'data': '{base}',
|
||||
},
|
||||
@@ -58,6 +58,7 @@ _INSTALL_SCHEMES = {
|
||||
'scripts': '{base}/Scripts',
|
||||
'data': '{base}',
|
||||
},
|
||||
|
||||
# Downstream distributors can overwrite the default install scheme.
|
||||
# This is done to support downstream modifications where distributors change
|
||||
# the installation layout (eg. different site-packages directory).
|
||||
@@ -76,14 +77,14 @@ _INSTALL_SCHEMES = {
|
||||
# Downstream distributors who patch posix_prefix/nt scheme are encouraged to
|
||||
# leave the following schemes unchanged
|
||||
'posix_venv': {
|
||||
'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}',
|
||||
'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}',
|
||||
'purelib': '{base}/lib/python{py_version_short}/site-packages',
|
||||
'platlib': '{platbase}/{platlibdir}/python{py_version_short}/site-packages',
|
||||
'stdlib': '{installed_base}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',
|
||||
'platstdlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',
|
||||
'purelib': '{base}/lib/{implementation_lower}{py_version_short}{abi_thread}/site-packages',
|
||||
'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}/site-packages',
|
||||
'include':
|
||||
'{installed_base}/include/python{py_version_short}{abiflags}',
|
||||
'{installed_base}/include/{implementation_lower}{py_version_short}{abiflags}',
|
||||
'platinclude':
|
||||
'{installed_platbase}/include/python{py_version_short}{abiflags}',
|
||||
'{installed_platbase}/include/{implementation_lower}{py_version_short}{abiflags}',
|
||||
'scripts': '{base}/bin',
|
||||
'data': '{base}',
|
||||
},
|
||||
@@ -105,6 +106,8 @@ if os.name == 'nt':
|
||||
else:
|
||||
_INSTALL_SCHEMES['venv'] = _INSTALL_SCHEMES['posix_venv']
|
||||
|
||||
def _get_implementation():
|
||||
return 'RustPython' # XXX: For site-packages
|
||||
|
||||
# NOTE: site.py has copy of this function.
|
||||
# Sync it when modify this function.
|
||||
@@ -113,8 +116,8 @@ def _getuserbase():
|
||||
if env_base:
|
||||
return env_base
|
||||
|
||||
# Emscripten, VxWorks, and WASI have no home directories
|
||||
if sys.platform in {"emscripten", "vxworks", "wasi"}:
|
||||
# Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories
|
||||
if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
|
||||
return None
|
||||
|
||||
def joinuser(*args):
|
||||
@@ -122,7 +125,7 @@ def _getuserbase():
|
||||
|
||||
if os.name == "nt":
|
||||
base = os.environ.get("APPDATA") or "~"
|
||||
return joinuser(base, "Python")
|
||||
return joinuser(base, _get_implementation())
|
||||
|
||||
if sys.platform == "darwin" and sys._framework:
|
||||
return joinuser("~", "Library", sys._framework,
|
||||
@@ -136,29 +139,29 @@ if _HAS_USER_BASE:
|
||||
_INSTALL_SCHEMES |= {
|
||||
# NOTE: When modifying "purelib" scheme, update site._get_path() too.
|
||||
'nt_user': {
|
||||
'stdlib': '{userbase}/Python{py_version_nodot_plat}',
|
||||
'platstdlib': '{userbase}/Python{py_version_nodot_plat}',
|
||||
'purelib': '{userbase}/Python{py_version_nodot_plat}/site-packages',
|
||||
'platlib': '{userbase}/Python{py_version_nodot_plat}/site-packages',
|
||||
'include': '{userbase}/Python{py_version_nodot_plat}/Include',
|
||||
'scripts': '{userbase}/Python{py_version_nodot_plat}/Scripts',
|
||||
'stdlib': '{userbase}/{implementation}{py_version_nodot_plat}',
|
||||
'platstdlib': '{userbase}/{implementation}{py_version_nodot_plat}',
|
||||
'purelib': '{userbase}/{implementation}{py_version_nodot_plat}/site-packages',
|
||||
'platlib': '{userbase}/{implementation}{py_version_nodot_plat}/site-packages',
|
||||
'include': '{userbase}/{implementation}{py_version_nodot_plat}/Include',
|
||||
'scripts': '{userbase}/{implementation}{py_version_nodot_plat}/Scripts',
|
||||
'data': '{userbase}',
|
||||
},
|
||||
'posix_user': {
|
||||
'stdlib': '{userbase}/{platlibdir}/python{py_version_short}',
|
||||
'platstdlib': '{userbase}/{platlibdir}/python{py_version_short}',
|
||||
'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
|
||||
'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
|
||||
'include': '{userbase}/include/python{py_version_short}',
|
||||
'stdlib': '{userbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',
|
||||
'platstdlib': '{userbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',
|
||||
'purelib': '{userbase}/lib/{implementation_lower}{py_version_short}{abi_thread}/site-packages',
|
||||
'platlib': '{userbase}/lib/{implementation_lower}{py_version_short}{abi_thread}/site-packages',
|
||||
'include': '{userbase}/include/{implementation_lower}{py_version_short}{abi_thread}',
|
||||
'scripts': '{userbase}/bin',
|
||||
'data': '{userbase}',
|
||||
},
|
||||
'osx_framework_user': {
|
||||
'stdlib': '{userbase}/lib/python',
|
||||
'platstdlib': '{userbase}/lib/python',
|
||||
'purelib': '{userbase}/lib/python/site-packages',
|
||||
'platlib': '{userbase}/lib/python/site-packages',
|
||||
'include': '{userbase}/include/python{py_version_short}',
|
||||
'stdlib': '{userbase}/lib/{implementation_lower}',
|
||||
'platstdlib': '{userbase}/lib/{implementation_lower}',
|
||||
'purelib': '{userbase}/lib/{implementation_lower}/site-packages',
|
||||
'platlib': '{userbase}/lib/{implementation_lower}/site-packages',
|
||||
'include': '{userbase}/include/{implementation_lower}{py_version_short}',
|
||||
'scripts': '{userbase}/bin',
|
||||
'data': '{userbase}',
|
||||
},
|
||||
@@ -170,19 +173,15 @@ _SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
|
||||
_PY_VERSION = sys.version.split()[0]
|
||||
_PY_VERSION_SHORT = f'{sys.version_info[0]}.{sys.version_info[1]}'
|
||||
_PY_VERSION_SHORT_NO_DOT = f'{sys.version_info[0]}{sys.version_info[1]}'
|
||||
_PREFIX = os.path.normpath(sys.prefix)
|
||||
_BASE_PREFIX = os.path.normpath(sys.base_prefix)
|
||||
_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
|
||||
_BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
|
||||
# Mutex guarding initialization of _CONFIG_VARS.
|
||||
_CONFIG_VARS_LOCK = threading.RLock()
|
||||
_CONFIG_VARS = None
|
||||
# True iff _CONFIG_VARS has been fully initialized.
|
||||
_CONFIG_VARS_INITIALIZED = False
|
||||
_USER_BASE = None
|
||||
|
||||
# Regexes needed for parsing Makefile (and similar syntaxes,
|
||||
# like old-style Setup files).
|
||||
_variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)"
|
||||
_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"
|
||||
_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}"
|
||||
|
||||
|
||||
def _safe_realpath(path):
|
||||
try:
|
||||
@@ -221,8 +220,15 @@ if "_PYTHON_PROJECT_BASE" in os.environ:
|
||||
def is_python_build(check_home=None):
|
||||
if check_home is not None:
|
||||
import warnings
|
||||
warnings.warn("check_home argument is deprecated and ignored.",
|
||||
DeprecationWarning, stacklevel=2)
|
||||
warnings.warn(
|
||||
(
|
||||
'The check_home argument of sysconfig.is_python_build is '
|
||||
'deprecated and its value is ignored. '
|
||||
'It will be removed in Python 3.15.'
|
||||
),
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
for fn in ("Setup", "Setup.local"):
|
||||
if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)):
|
||||
return True
|
||||
@@ -291,6 +297,7 @@ def _get_preferred_schemes():
|
||||
'home': 'posix_home',
|
||||
'user': 'osx_framework_user',
|
||||
}
|
||||
|
||||
return {
|
||||
'prefix': 'posix_prefix',
|
||||
'home': 'posix_home',
|
||||
@@ -314,134 +321,6 @@ def get_default_scheme():
|
||||
return get_preferred_scheme('prefix')
|
||||
|
||||
|
||||
def _parse_makefile(filename, vars=None, keep_unresolved=True):
|
||||
"""Parse a Makefile-style file.
|
||||
|
||||
A dictionary containing name/value pairs is returned. If an
|
||||
optional dictionary is passed in as the second argument, it is
|
||||
used instead of a new dictionary.
|
||||
"""
|
||||
import re
|
||||
|
||||
if vars is None:
|
||||
vars = {}
|
||||
done = {}
|
||||
notdone = {}
|
||||
|
||||
with open(filename, encoding=sys.getfilesystemencoding(),
|
||||
errors="surrogateescape") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
for line in lines:
|
||||
if line.startswith('#') or line.strip() == '':
|
||||
continue
|
||||
m = re.match(_variable_rx, line)
|
||||
if m:
|
||||
n, v = m.group(1, 2)
|
||||
v = v.strip()
|
||||
# `$$' is a literal `$' in make
|
||||
tmpv = v.replace('$$', '')
|
||||
|
||||
if "$" in tmpv:
|
||||
notdone[n] = v
|
||||
else:
|
||||
try:
|
||||
if n in _ALWAYS_STR:
|
||||
raise ValueError
|
||||
|
||||
v = int(v)
|
||||
except ValueError:
|
||||
# insert literal `$'
|
||||
done[n] = v.replace('$$', '$')
|
||||
else:
|
||||
done[n] = v
|
||||
|
||||
# do variable interpolation here
|
||||
variables = list(notdone.keys())
|
||||
|
||||
# Variables with a 'PY_' prefix in the makefile. These need to
|
||||
# be made available without that prefix through sysconfig.
|
||||
# Special care is needed to ensure that variable expansion works, even
|
||||
# if the expansion uses the name without a prefix.
|
||||
renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
|
||||
|
||||
while len(variables) > 0:
|
||||
for name in tuple(variables):
|
||||
value = notdone[name]
|
||||
m1 = re.search(_findvar1_rx, value)
|
||||
m2 = re.search(_findvar2_rx, value)
|
||||
if m1 and m2:
|
||||
m = m1 if m1.start() < m2.start() else m2
|
||||
else:
|
||||
m = m1 if m1 else m2
|
||||
if m is not None:
|
||||
n = m.group(1)
|
||||
found = True
|
||||
if n in done:
|
||||
item = str(done[n])
|
||||
elif n in notdone:
|
||||
# get it on a subsequent round
|
||||
found = False
|
||||
elif n in os.environ:
|
||||
# do it like make: fall back to environment
|
||||
item = os.environ[n]
|
||||
|
||||
elif n in renamed_variables:
|
||||
if (name.startswith('PY_') and
|
||||
name[3:] in renamed_variables):
|
||||
item = ""
|
||||
|
||||
elif 'PY_' + n in notdone:
|
||||
found = False
|
||||
|
||||
else:
|
||||
item = str(done['PY_' + n])
|
||||
|
||||
else:
|
||||
done[n] = item = ""
|
||||
|
||||
if found:
|
||||
after = value[m.end():]
|
||||
value = value[:m.start()] + item + after
|
||||
if "$" in after:
|
||||
notdone[name] = value
|
||||
else:
|
||||
try:
|
||||
if name in _ALWAYS_STR:
|
||||
raise ValueError
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
done[name] = value.strip()
|
||||
else:
|
||||
done[name] = value
|
||||
variables.remove(name)
|
||||
|
||||
if name.startswith('PY_') \
|
||||
and name[3:] in renamed_variables:
|
||||
|
||||
name = name[3:]
|
||||
if name not in done:
|
||||
done[name] = value
|
||||
|
||||
else:
|
||||
# Adds unresolved variables to the done dict.
|
||||
# This is disabled when called from distutils.sysconfig
|
||||
if keep_unresolved:
|
||||
done[name] = value
|
||||
# bogus variable reference (e.g. "prefix=$/opt/python");
|
||||
# just drop it since we can't deal
|
||||
variables.remove(name)
|
||||
|
||||
# strip spurious spaces
|
||||
for k, v in done.items():
|
||||
if isinstance(v, str):
|
||||
done[k] = v.strip()
|
||||
|
||||
# save the results in the global dictionary
|
||||
vars.update(done)
|
||||
return vars
|
||||
|
||||
|
||||
def get_makefile_filename():
|
||||
"""Return the path of the Makefile."""
|
||||
if _PYTHON_BUILD:
|
||||
@@ -462,91 +341,44 @@ def _get_sysconfigdata_name():
|
||||
f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}',
|
||||
)
|
||||
|
||||
|
||||
def _generate_posix_vars():
|
||||
"""Generate the Python module containing build-time variables."""
|
||||
import pprint
|
||||
vars = {}
|
||||
# load the installed Makefile:
|
||||
makefile = get_makefile_filename()
|
||||
try:
|
||||
_parse_makefile(makefile, vars)
|
||||
except OSError as e:
|
||||
msg = f"invalid Python installation: unable to open {makefile}"
|
||||
if hasattr(e, "strerror"):
|
||||
msg = f"{msg} ({e.strerror})"
|
||||
raise OSError(msg)
|
||||
# load the installed pyconfig.h:
|
||||
config_h = get_config_h_filename()
|
||||
try:
|
||||
with open(config_h, encoding="utf-8") as f:
|
||||
parse_config_h(f, vars)
|
||||
except OSError as e:
|
||||
msg = f"invalid Python installation: unable to open {config_h}"
|
||||
if hasattr(e, "strerror"):
|
||||
msg = f"{msg} ({e.strerror})"
|
||||
raise OSError(msg)
|
||||
# On AIX, there are wrong paths to the linker scripts in the Makefile
|
||||
# -- these paths are relative to the Python source, but when installed
|
||||
# the scripts are in another directory.
|
||||
if _PYTHON_BUILD:
|
||||
vars['BLDSHARED'] = vars['LDSHARED']
|
||||
|
||||
# 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
|
||||
# `make pybuilddir.txt` target -- which is a precursor to the
|
||||
# _sysconfigdata.py module being constructed. Unfortunately,
|
||||
# get_config_vars() eventually calls _init_posix(), which attempts
|
||||
# to import _sysconfigdata, which we won't have built yet. In order
|
||||
# for _init_posix() to work, if we're on Darwin, just mock up the
|
||||
# _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
|
||||
|
||||
pybuilddir = f'build/lib.{get_platform()}-{_PY_VERSION_SHORT}'
|
||||
if hasattr(sys, "gettotalrefcount"):
|
||||
pybuilddir += '-pydebug'
|
||||
os.makedirs(pybuilddir, exist_ok=True)
|
||||
destfile = os.path.join(pybuilddir, name + '.py')
|
||||
|
||||
with open(destfile, 'w', encoding='utf8') as f:
|
||||
f.write('# system configuration generated and used by'
|
||||
' the sysconfig module\n')
|
||||
f.write('build_time_vars = ')
|
||||
pprint.pprint(vars, stream=f)
|
||||
|
||||
# Create file used for sys.path fixup -- see Modules/getpath.c
|
||||
with open('pybuilddir.txt', 'w', encoding='utf8') as f:
|
||||
f.write(pybuilddir)
|
||||
|
||||
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()
|
||||
_temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
|
||||
|
||||
# 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"""
|
||||
# set basic install directories
|
||||
import _imp
|
||||
import _winapi
|
||||
import _sysconfig
|
||||
vars['LIBDEST'] = get_path('stdlib')
|
||||
vars['BINLIBDEST'] = get_path('platstdlib')
|
||||
vars['INCLUDEPY'] = get_path('include')
|
||||
try:
|
||||
# GH-99201: _imp.extension_suffixes may be empty when
|
||||
# HAVE_DYNAMIC_LOADING is not set. In this case, don't set EXT_SUFFIX.
|
||||
vars['EXT_SUFFIX'] = _imp.extension_suffixes()[0]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
# Add EXT_SUFFIX, SOABI, and Py_GIL_DISABLED
|
||||
vars.update(_sysconfig.config_vars())
|
||||
|
||||
vars['LIBDIR'] = _safe_realpath(os.path.join(get_config_var('installed_base'), 'libs'))
|
||||
if hasattr(sys, 'dllhandle'):
|
||||
dllhandle = _winapi.GetModuleFileName(sys.dllhandle)
|
||||
vars['LIBRARY'] = os.path.basename(_safe_realpath(dllhandle))
|
||||
vars['LDLIBRARY'] = vars['LIBRARY']
|
||||
vars['EXE'] = '.exe'
|
||||
vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
|
||||
vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
|
||||
@@ -595,7 +427,7 @@ def get_config_h_filename():
|
||||
"""Return the path of pyconfig.h."""
|
||||
if _PYTHON_BUILD:
|
||||
if os.name == "nt":
|
||||
inc_dir = os.path.join(_PROJECT_BASE, "PC")
|
||||
inc_dir = os.path.dirname(sys._base_executable)
|
||||
else:
|
||||
inc_dir = _PROJECT_BASE
|
||||
else:
|
||||
@@ -633,6 +465,78 @@ def get_path(name, scheme=get_default_scheme(), vars=None, expand=True):
|
||||
return get_paths(scheme, vars, expand)[name]
|
||||
|
||||
|
||||
def _init_config_vars():
|
||||
global _CONFIG_VARS
|
||||
_CONFIG_VARS = {}
|
||||
# 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['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['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'] = ''
|
||||
try:
|
||||
_CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '')
|
||||
except AttributeError:
|
||||
_CONFIG_VARS['py_version_nodot_plat'] = ''
|
||||
|
||||
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
|
||||
# the init-function.
|
||||
_CONFIG_VARS['userbase'] = _getuserbase()
|
||||
|
||||
# e.g., 't' for free-threaded or '' for default build
|
||||
_CONFIG_VARS['abi_thread'] = 't' if _CONFIG_VARS.get('Py_GIL_DISABLED') else ''
|
||||
|
||||
# Always convert srcdir to an absolute path
|
||||
srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)
|
||||
if os.name == 'posix':
|
||||
if _PYTHON_BUILD:
|
||||
# If srcdir is a relative path (typically '.' or '..')
|
||||
# then it should be interpreted relative to the directory
|
||||
# containing Makefile.
|
||||
base = os.path.dirname(get_makefile_filename())
|
||||
srcdir = os.path.join(base, srcdir)
|
||||
else:
|
||||
# srcdir is not meaningful since the installation is
|
||||
# spread about the filesystem. We choose the
|
||||
# directory containing the Makefile since we know it
|
||||
# exists.
|
||||
srcdir = os.path.dirname(get_makefile_filename())
|
||||
_CONFIG_VARS['srcdir'] = _safe_realpath(srcdir)
|
||||
|
||||
# OS X platforms require special customization to handle
|
||||
# multi-architecture, multi-os-version installers
|
||||
if sys.platform == 'darwin':
|
||||
import _osx_support
|
||||
_osx_support.customize_config_vars(_CONFIG_VARS)
|
||||
|
||||
global _CONFIG_VARS_INITIALIZED
|
||||
_CONFIG_VARS_INITIALIZED = True
|
||||
|
||||
|
||||
def get_config_vars(*args):
|
||||
"""With no arguments, return a dictionary of all configuration
|
||||
variables relevant for the current platform.
|
||||
@@ -643,66 +547,26 @@ def get_config_vars(*args):
|
||||
With arguments, return a list of values that result from looking up
|
||||
each argument in the configuration variable dictionary.
|
||||
"""
|
||||
global _CONFIG_VARS
|
||||
if _CONFIG_VARS is None:
|
||||
_CONFIG_VARS = {}
|
||||
# Normalized versions of prefix and exec_prefix are handy to have;
|
||||
# in fact, these are the standard versions used most places in the
|
||||
# Distutils.
|
||||
_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['projectbase'] = _PROJECT_BASE
|
||||
_CONFIG_VARS['platlibdir'] = sys.platlibdir
|
||||
try:
|
||||
_CONFIG_VARS['abiflags'] = sys.abiflags
|
||||
except AttributeError:
|
||||
# sys.abiflags may not be defined on all platforms.
|
||||
_CONFIG_VARS['abiflags'] = ''
|
||||
try:
|
||||
_CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '')
|
||||
except AttributeError:
|
||||
_CONFIG_VARS['py_version_nodot_plat'] = ''
|
||||
global _CONFIG_VARS_INITIALIZED
|
||||
|
||||
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
|
||||
# the init-function.
|
||||
_CONFIG_VARS['userbase'] = _getuserbase()
|
||||
|
||||
# Always convert srcdir to an absolute path
|
||||
srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)
|
||||
if os.name == 'posix':
|
||||
if _PYTHON_BUILD:
|
||||
# If srcdir is a relative path (typically '.' or '..')
|
||||
# then it should be interpreted relative to the directory
|
||||
# containing Makefile.
|
||||
base = os.path.dirname(get_makefile_filename())
|
||||
srcdir = os.path.join(base, srcdir)
|
||||
else:
|
||||
# srcdir is not meaningful since the installation is
|
||||
# spread about the filesystem. We choose the
|
||||
# directory containing the Makefile since we know it
|
||||
# exists.
|
||||
srcdir = os.path.dirname(get_makefile_filename())
|
||||
_CONFIG_VARS['srcdir'] = _safe_realpath(srcdir)
|
||||
|
||||
# OS X platforms require special customization to handle
|
||||
# multi-architecture, multi-os-version installers
|
||||
if sys.platform == 'darwin':
|
||||
import _osx_support
|
||||
_osx_support.customize_config_vars(_CONFIG_VARS)
|
||||
# Avoid claiming the lock once initialization is complete.
|
||||
if not _CONFIG_VARS_INITIALIZED:
|
||||
with _CONFIG_VARS_LOCK:
|
||||
# Test again with the lock held to avoid races. Note that
|
||||
# we test _CONFIG_VARS here, not _CONFIG_VARS_INITIALIZED,
|
||||
# to ensure that recursive calls to get_config_vars()
|
||||
# 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 = []
|
||||
@@ -737,7 +601,8 @@ def get_platform():
|
||||
solaris-2.6-sun4u
|
||||
|
||||
Windows will return one of:
|
||||
win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
|
||||
win-amd64 (64-bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
|
||||
win-arm64 (64-bit Windows on ARM64 (aka AArch64)
|
||||
win32 (all others - specifically, sys.platform is returned)
|
||||
|
||||
For other non-POSIX platforms, currently just returns 'sys.platform'.
|
||||
@@ -770,10 +635,22 @@ def get_platform():
|
||||
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 f"{osname}-{machine}"
|
||||
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}"
|
||||
elif osname[:5] == "sunos":
|
||||
if release[0] >= "5": # SunOS 5 == Solaris 2
|
||||
osname = "solaris"
|
||||
@@ -795,10 +672,15 @@ def get_platform():
|
||||
if m:
|
||||
release = m.group()
|
||||
elif osname[:6] == "darwin":
|
||||
import _osx_support
|
||||
osname, release, machine = _osx_support.get_platform_osx(
|
||||
get_config_vars(),
|
||||
osname, release, machine)
|
||||
if sys.platform == "ios":
|
||||
release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0")
|
||||
osname = sys.platform
|
||||
machine = sys.implementation._multiarch
|
||||
else:
|
||||
import _osx_support
|
||||
osname, release, machine = _osx_support.get_platform_osx(
|
||||
get_config_vars(),
|
||||
osname, release, machine)
|
||||
|
||||
return f"{osname}-{release}-{machine}"
|
||||
|
||||
@@ -807,6 +689,10 @@ def get_python_version():
|
||||
return _PY_VERSION_SHORT
|
||||
|
||||
|
||||
def _get_python_version_abi():
|
||||
return _PY_VERSION_SHORT + get_config_var("abi_thread")
|
||||
|
||||
|
||||
def expand_makefile_vars(s, vars):
|
||||
"""Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
|
||||
'string' according to 'vars' (a dictionary mapping variable names to
|
||||
@@ -817,6 +703,9 @@ def expand_makefile_vars(s, vars):
|
||||
"""
|
||||
import re
|
||||
|
||||
_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"
|
||||
_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}"
|
||||
|
||||
# This algorithm does multiple expansion, so if vars['foo'] contains
|
||||
# "${bar}", it will expand ${foo} to ${bar}, and then expand
|
||||
# ${bar}... and so forth. This is fine as long as 'vars' comes from
|
||||
@@ -831,28 +720,3 @@ def expand_makefile_vars(s, vars):
|
||||
else:
|
||||
break
|
||||
return s
|
||||
|
||||
|
||||
def _print_dict(title, data):
|
||||
for index, (key, value) in enumerate(sorted(data.items())):
|
||||
if index == 0:
|
||||
print(f'{title}: ')
|
||||
print(f'\t{key} = "{value}"')
|
||||
|
||||
|
||||
def _main():
|
||||
"""Display all information sysconfig detains."""
|
||||
if '--generate-posix-vars' in sys.argv:
|
||||
_generate_posix_vars()
|
||||
return
|
||||
print(f'Platform: "{get_platform()}"')
|
||||
print(f'Python version: "{get_python_version()}"')
|
||||
print(f'Current installation scheme: "{get_default_scheme()}"')
|
||||
print()
|
||||
_print_dict('Paths', get_paths())
|
||||
print()
|
||||
_print_dict('Variables', get_config_vars())
|
||||
|
||||
if __name__ == '__main__':
|
||||
_main()
|
||||
'''.replace("Python", "RustPython").replace("/python", "/rustpython"))
|
||||
Vendored
+248
@@ -0,0 +1,248 @@
|
||||
import os
|
||||
import sys
|
||||
from sysconfig import (
|
||||
_ALWAYS_STR,
|
||||
_PYTHON_BUILD,
|
||||
_get_sysconfigdata_name,
|
||||
get_config_h_filename,
|
||||
get_config_vars,
|
||||
get_default_scheme,
|
||||
get_makefile_filename,
|
||||
get_paths,
|
||||
get_platform,
|
||||
get_python_version,
|
||||
parse_config_h,
|
||||
)
|
||||
|
||||
|
||||
# Regexes needed for parsing Makefile (and similar syntaxes,
|
||||
# like old-style Setup files).
|
||||
_variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)"
|
||||
_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"
|
||||
_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}"
|
||||
|
||||
|
||||
def _parse_makefile(filename, vars=None, keep_unresolved=True):
|
||||
"""Parse a Makefile-style file.
|
||||
|
||||
A dictionary containing name/value pairs is returned. If an
|
||||
optional dictionary is passed in as the second argument, it is
|
||||
used instead of a new dictionary.
|
||||
"""
|
||||
import re
|
||||
|
||||
if vars is None:
|
||||
vars = {}
|
||||
done = {}
|
||||
notdone = {}
|
||||
|
||||
with open(filename, encoding=sys.getfilesystemencoding(),
|
||||
errors="surrogateescape") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
for line in lines:
|
||||
if line.startswith('#') or line.strip() == '':
|
||||
continue
|
||||
m = re.match(_variable_rx, line)
|
||||
if m:
|
||||
n, v = m.group(1, 2)
|
||||
v = v.strip()
|
||||
# `$$' is a literal `$' in make
|
||||
tmpv = v.replace('$$', '')
|
||||
|
||||
if "$" in tmpv:
|
||||
notdone[n] = v
|
||||
else:
|
||||
try:
|
||||
if n in _ALWAYS_STR:
|
||||
raise ValueError
|
||||
|
||||
v = int(v)
|
||||
except ValueError:
|
||||
# insert literal `$'
|
||||
done[n] = v.replace('$$', '$')
|
||||
else:
|
||||
done[n] = v
|
||||
|
||||
# do variable interpolation here
|
||||
variables = list(notdone.keys())
|
||||
|
||||
# Variables with a 'PY_' prefix in the makefile. These need to
|
||||
# be made available without that prefix through sysconfig.
|
||||
# Special care is needed to ensure that variable expansion works, even
|
||||
# if the expansion uses the name without a prefix.
|
||||
renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
|
||||
|
||||
while len(variables) > 0:
|
||||
for name in tuple(variables):
|
||||
value = notdone[name]
|
||||
m1 = re.search(_findvar1_rx, value)
|
||||
m2 = re.search(_findvar2_rx, value)
|
||||
if m1 and m2:
|
||||
m = m1 if m1.start() < m2.start() else m2
|
||||
else:
|
||||
m = m1 if m1 else m2
|
||||
if m is not None:
|
||||
n = m.group(1)
|
||||
found = True
|
||||
if n in done:
|
||||
item = str(done[n])
|
||||
elif n in notdone:
|
||||
# get it on a subsequent round
|
||||
found = False
|
||||
elif n in os.environ:
|
||||
# do it like make: fall back to environment
|
||||
item = os.environ[n]
|
||||
|
||||
elif n in renamed_variables:
|
||||
if (name.startswith('PY_') and
|
||||
name[3:] in renamed_variables):
|
||||
item = ""
|
||||
|
||||
elif 'PY_' + n in notdone:
|
||||
found = False
|
||||
|
||||
else:
|
||||
item = str(done['PY_' + n])
|
||||
|
||||
else:
|
||||
done[n] = item = ""
|
||||
|
||||
if found:
|
||||
after = value[m.end():]
|
||||
value = value[:m.start()] + item + after
|
||||
if "$" in after:
|
||||
notdone[name] = value
|
||||
else:
|
||||
try:
|
||||
if name in _ALWAYS_STR:
|
||||
raise ValueError
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
done[name] = value.strip()
|
||||
else:
|
||||
done[name] = value
|
||||
variables.remove(name)
|
||||
|
||||
if name.startswith('PY_') \
|
||||
and name[3:] in renamed_variables:
|
||||
|
||||
name = name[3:]
|
||||
if name not in done:
|
||||
done[name] = value
|
||||
|
||||
else:
|
||||
# Adds unresolved variables to the done dict.
|
||||
# This is disabled when called from distutils.sysconfig
|
||||
if keep_unresolved:
|
||||
done[name] = value
|
||||
# bogus variable reference (e.g. "prefix=$/opt/python");
|
||||
# just drop it since we can't deal
|
||||
variables.remove(name)
|
||||
|
||||
# strip spurious spaces
|
||||
for k, v in done.items():
|
||||
if isinstance(v, str):
|
||||
done[k] = v.strip()
|
||||
|
||||
# save the results in the global dictionary
|
||||
vars.update(done)
|
||||
return vars
|
||||
|
||||
|
||||
def _print_config_dict(d, stream):
|
||||
print ("{", file=stream)
|
||||
for k, v in sorted(d.items()):
|
||||
print(f" {k!r}: {v!r},", file=stream)
|
||||
print ("}", file=stream)
|
||||
|
||||
|
||||
def _generate_posix_vars():
|
||||
"""Generate the Python module containing build-time variables."""
|
||||
vars = {}
|
||||
# load the installed Makefile:
|
||||
makefile = get_makefile_filename()
|
||||
try:
|
||||
_parse_makefile(makefile, vars)
|
||||
except OSError as e:
|
||||
msg = f"invalid Python installation: unable to open {makefile}"
|
||||
if hasattr(e, "strerror"):
|
||||
msg = f"{msg} ({e.strerror})"
|
||||
raise OSError(msg)
|
||||
# load the installed pyconfig.h:
|
||||
config_h = get_config_h_filename()
|
||||
try:
|
||||
with open(config_h, encoding="utf-8") as f:
|
||||
parse_config_h(f, vars)
|
||||
except OSError as e:
|
||||
msg = f"invalid Python installation: unable to open {config_h}"
|
||||
if hasattr(e, "strerror"):
|
||||
msg = f"{msg} ({e.strerror})"
|
||||
raise OSError(msg)
|
||||
# On AIX, there are wrong paths to the linker scripts in the Makefile
|
||||
# -- these paths are relative to the Python source, but when installed
|
||||
# the scripts are in another directory.
|
||||
if _PYTHON_BUILD:
|
||||
vars['BLDSHARED'] = vars['LDSHARED']
|
||||
|
||||
# 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
|
||||
# `make pybuilddir.txt` target -- which is a precursor to the
|
||||
# _sysconfigdata.py module being constructed. Unfortunately,
|
||||
# get_config_vars() eventually calls _init_posix(), which attempts
|
||||
# to import _sysconfigdata, which we won't have built yet. In order
|
||||
# for _init_posix() to work, if we're on Darwin, just mock up the
|
||||
# _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
|
||||
|
||||
pybuilddir = f'build/lib.{get_platform()}-{get_python_version()}'
|
||||
if hasattr(sys, "gettotalrefcount"):
|
||||
pybuilddir += '-pydebug'
|
||||
os.makedirs(pybuilddir, exist_ok=True)
|
||||
destfile = os.path.join(pybuilddir, name + '.py')
|
||||
|
||||
with open(destfile, 'w', encoding='utf8') as f:
|
||||
f.write('# system configuration generated and used by'
|
||||
' the sysconfig module\n')
|
||||
f.write('build_time_vars = ')
|
||||
_print_config_dict(vars, stream=f)
|
||||
|
||||
# Create file used for sys.path fixup -- see Modules/getpath.c
|
||||
with open('pybuilddir.txt', 'w', encoding='utf8') as f:
|
||||
f.write(pybuilddir)
|
||||
|
||||
|
||||
def _print_dict(title, data):
|
||||
for index, (key, value) in enumerate(sorted(data.items())):
|
||||
if index == 0:
|
||||
print(f'{title}: ')
|
||||
print(f'\t{key} = "{value}"')
|
||||
|
||||
|
||||
def _main():
|
||||
"""Display all information sysconfig detains."""
|
||||
if '--generate-posix-vars' in sys.argv:
|
||||
_generate_posix_vars()
|
||||
return
|
||||
print(f'Platform: "{get_platform()}"')
|
||||
print(f'Python version: "{get_python_version()}"')
|
||||
print(f'Current installation scheme: "{get_default_scheme()}"')
|
||||
print()
|
||||
_print_dict('Paths', get_paths())
|
||||
print()
|
||||
_print_dict('Variables', get_config_vars())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
_main()
|
||||
except BrokenPipeError:
|
||||
pass
|
||||
Vendored
+1
@@ -979,6 +979,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
self.assertEqual(output, [])
|
||||
self.assertEqual(exitcode, 0)
|
||||
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AttributeError: module 'msvcrt' has no attribute 'GetErrorMode'")
|
||||
@threading_helper.requires_working_threading()
|
||||
@unittest.skipUnless(support.Py_GIL_DISABLED, "only meaningful if the GIL is disabled")
|
||||
def test_free_threaded_dump_traceback(self):
|
||||
|
||||
Vendored
+55
-5
@@ -7,6 +7,7 @@ executing have not been removed.
|
||||
import unittest
|
||||
import test.support
|
||||
from test import support
|
||||
from test.support.script_helper import assert_python_ok
|
||||
from test.support import os_helper
|
||||
from test.support import socket_helper
|
||||
from test.support import captured_stderr
|
||||
@@ -330,14 +331,14 @@ class HelperFunctionsTests(unittest.TestCase):
|
||||
self.assertEqual(len(dirs), 2)
|
||||
wanted = os.path.join('xoxo', sys.platlibdir,
|
||||
# XXX: RUSTPYTHON
|
||||
'rustpython%d.%d' % sys.version_info[:2],
|
||||
f'rustpython{sysconfig._get_python_version_abi()}',
|
||||
'site-packages')
|
||||
self.assertEqual(dirs[0], wanted)
|
||||
else:
|
||||
self.assertEqual(len(dirs), 1)
|
||||
wanted = os.path.join('xoxo', 'lib',
|
||||
# XXX: RUSTPYTHON
|
||||
'rustpython%d.%d' % sys.version_info[:2],
|
||||
f'rustpython{sysconfig._get_python_version_abi()}',
|
||||
'site-packages')
|
||||
self.assertEqual(dirs[-1], wanted)
|
||||
else:
|
||||
@@ -358,9 +359,7 @@ class HelperFunctionsTests(unittest.TestCase):
|
||||
|
||||
with EnvironmentVarGuard() as environ, \
|
||||
mock.patch('os.path.expanduser', lambda path: path):
|
||||
|
||||
del environ['PYTHONUSERBASE']
|
||||
del environ['APPDATA']
|
||||
environ.unset('PYTHONUSERBASE', 'APPDATA')
|
||||
|
||||
user_base = site.getuserbase()
|
||||
self.assertTrue(user_base.startswith('~' + os.sep),
|
||||
@@ -382,6 +381,19 @@ class HelperFunctionsTests(unittest.TestCase):
|
||||
mock_addsitedir.assert_not_called()
|
||||
self.assertFalse(known_paths)
|
||||
|
||||
def test_gethistoryfile(self):
|
||||
filename = 'file'
|
||||
rc, out, err = assert_python_ok('-c',
|
||||
f'import site; assert site.gethistoryfile() == "{filename}"',
|
||||
PYTHON_HISTORY=filename)
|
||||
self.assertEqual(rc, 0)
|
||||
|
||||
# Check that PYTHON_HISTORY is ignored in isolated mode.
|
||||
rc, out, err = assert_python_ok('-I', '-c',
|
||||
f'import site; assert site.gethistoryfile() != "{filename}"',
|
||||
PYTHON_HISTORY=filename)
|
||||
self.assertEqual(rc, 0)
|
||||
|
||||
def test_trace(self):
|
||||
message = "bla-bla-bla"
|
||||
for verbose, out in (True, message + "\n"), (False, ""):
|
||||
@@ -509,6 +521,44 @@ class ImportSideEffectTests(unittest.TestCase):
|
||||
else:
|
||||
self.fail("sitecustomize not imported automatically")
|
||||
|
||||
@support.requires_subprocess()
|
||||
def test_customization_modules_on_startup(self):
|
||||
mod_names = [
|
||||
'sitecustomize'
|
||||
]
|
||||
|
||||
if site.ENABLE_USER_SITE:
|
||||
mod_names.append('usercustomize')
|
||||
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
self.addCleanup(os_helper.rmtree, temp_dir)
|
||||
|
||||
with EnvironmentVarGuard() as environ:
|
||||
environ['PYTHONPATH'] = temp_dir
|
||||
|
||||
for module_name in mod_names:
|
||||
os_helper.rmtree(temp_dir)
|
||||
os.mkdir(temp_dir)
|
||||
|
||||
customize_path = os.path.join(temp_dir, f'{module_name}.py')
|
||||
eyecatcher = f'EXECUTED_{module_name}'
|
||||
|
||||
with open(customize_path, 'w') as f:
|
||||
f.write(f'print("{eyecatcher}")')
|
||||
|
||||
output = subprocess.check_output([sys.executable, '-c', '""'])
|
||||
self.assertIn(eyecatcher, output.decode('utf-8'))
|
||||
|
||||
# -S blocks any site-packages
|
||||
output = subprocess.check_output([sys.executable, '-S', '-c', '""'])
|
||||
self.assertNotIn(eyecatcher, output.decode('utf-8'))
|
||||
|
||||
# -s blocks user site-packages
|
||||
if 'usercustomize' == module_name:
|
||||
output = subprocess.check_output([sys.executable, '-s', '-c', '""'])
|
||||
self.assertNotIn(eyecatcher, output.decode('utf-8'))
|
||||
|
||||
|
||||
@unittest.skipUnless(hasattr(urllib.request, "HTTPSHandler"),
|
||||
'need SSL support to download license')
|
||||
@test.support.requires_resource('network')
|
||||
|
||||
Vendored
+219
-37
@@ -1,24 +1,35 @@
|
||||
import platform
|
||||
import re
|
||||
import unittest
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import shutil
|
||||
import json
|
||||
import textwrap
|
||||
from copy import copy
|
||||
|
||||
from test.support import (
|
||||
captured_stdout, PythonSymlink, requires_subprocess, is_wasi
|
||||
captured_stdout,
|
||||
is_apple_mobile,
|
||||
is_wasi,
|
||||
PythonSymlink,
|
||||
requires_subprocess,
|
||||
)
|
||||
from test.support.import_helper import import_module
|
||||
from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink,
|
||||
change_cwd)
|
||||
from test.support.warnings_helper import check_warnings
|
||||
from test.support.venv import VirtualEnvironment
|
||||
|
||||
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, _main)
|
||||
_expand_vars, _get_preferred_schemes)
|
||||
from sysconfig.__main__ import _main, _parse_makefile
|
||||
import _imp
|
||||
import _osx_support
|
||||
import _sysconfig
|
||||
|
||||
|
||||
HAS_USER_BASE = sysconfig._HAS_USER_BASE
|
||||
@@ -41,6 +52,7 @@ class TestSysConfig(unittest.TestCase):
|
||||
self.name = os.name
|
||||
self.platform = sys.platform
|
||||
self.version = sys.version
|
||||
self._framework = sys._framework
|
||||
self.sep = os.sep
|
||||
self.join = os.path.join
|
||||
self.isabs = os.path.isabs
|
||||
@@ -64,6 +76,7 @@ class TestSysConfig(unittest.TestCase):
|
||||
os.name = self.name
|
||||
sys.platform = self.platform
|
||||
sys.version = self.version
|
||||
sys._framework = self._framework
|
||||
os.sep = self.sep
|
||||
os.path.join = self.join
|
||||
os.path.isabs = self.isabs
|
||||
@@ -91,6 +104,12 @@ 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)
|
||||
|
||||
@@ -137,35 +156,37 @@ class TestSysConfig(unittest.TestCase):
|
||||
# Mac, framework build.
|
||||
os.name = 'posix'
|
||||
sys.platform = 'darwin'
|
||||
sys._framework = True
|
||||
sys._framework = "MyPython"
|
||||
self.assertIsInstance(schemes, dict)
|
||||
self.assertEqual(set(schemes), expected_schemes)
|
||||
|
||||
# NOTE: RUSTPYTHON this is hardcoded to 'python', we're set up for failure.
|
||||
@unittest.expectedFailure
|
||||
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',
|
||||
'python%d.%d' % sys.version_info[:2],
|
||||
# XXX: RUSTPYTHON
|
||||
f'rustpython{sysconfig._get_python_version_abi()}',
|
||||
'site-packages')
|
||||
|
||||
# Resolve the paths in prefix
|
||||
binpath = os.path.join(sys.prefix, binpath)
|
||||
incpath = os.path.join(sys.prefix, incpath)
|
||||
libpath = os.path.join(sys.prefix, libpath)
|
||||
# Resolve the paths in an imaginary venv/ directory
|
||||
binpath = os.path.join('venv', binpath)
|
||||
incpath = os.path.join('venv', incpath)
|
||||
libpath = os.path.join('venv', libpath)
|
||||
|
||||
self.assertEqual(binpath, sysconfig.get_path('scripts', scheme='posix_venv'))
|
||||
self.assertEqual(libpath, sysconfig.get_path('purelib', scheme='posix_venv'))
|
||||
# Mimic the venv module, set all bases to the venv directory
|
||||
bases = ('base', 'platbase', 'installed_base', 'installed_platbase')
|
||||
vars = {base: 'venv' for base in bases}
|
||||
|
||||
self.assertEqual(binpath, sysconfig.get_path('scripts', scheme='posix_venv', vars=vars))
|
||||
self.assertEqual(libpath, sysconfig.get_path('purelib', scheme='posix_venv', vars=vars))
|
||||
|
||||
# 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')
|
||||
sysconfig_includedir = sysconfig.get_path('include', scheme='posix_venv', vars=vars)
|
||||
self.assertTrue(sysconfig_includedir.startswith(incpath + os.sep))
|
||||
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_nt_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
|
||||
@@ -173,14 +194,19 @@ class TestSysConfig(unittest.TestCase):
|
||||
incpath = 'Include'
|
||||
libpath = os.path.join('Lib', 'site-packages')
|
||||
|
||||
# Resolve the paths in prefix
|
||||
binpath = os.path.join(sys.prefix, binpath)
|
||||
incpath = os.path.join(sys.prefix, incpath)
|
||||
libpath = os.path.join(sys.prefix, libpath)
|
||||
# Resolve the paths in an imaginary venv\ directory
|
||||
venv = 'venv'
|
||||
binpath = os.path.join(venv, binpath)
|
||||
incpath = os.path.join(venv, incpath)
|
||||
libpath = os.path.join(venv, libpath)
|
||||
|
||||
self.assertEqual(binpath, sysconfig.get_path('scripts', scheme='nt_venv'))
|
||||
self.assertEqual(incpath, sysconfig.get_path('include', scheme='nt_venv'))
|
||||
self.assertEqual(libpath, sysconfig.get_path('purelib', scheme='nt_venv'))
|
||||
# Mimic the venv module, set all bases to the venv directory
|
||||
bases = ('base', 'platbase', 'installed_base', 'installed_platbase')
|
||||
vars = {base: 'venv' for base in bases}
|
||||
|
||||
self.assertEqual(binpath, sysconfig.get_path('scripts', scheme='nt_venv', vars=vars))
|
||||
self.assertEqual(incpath, sysconfig.get_path('include', scheme='nt_venv', vars=vars))
|
||||
self.assertEqual(libpath, sysconfig.get_path('purelib', scheme='nt_venv', vars=vars))
|
||||
|
||||
def test_venv_scheme(self):
|
||||
if sys.platform == 'win32':
|
||||
@@ -216,6 +242,11 @@ class TestSysConfig(unittest.TestCase):
|
||||
self.assertTrue(cvars)
|
||||
|
||||
def test_get_platform(self):
|
||||
# Check the actual platform returns something reasonable.
|
||||
actual_platform = get_platform()
|
||||
self.assertIsInstance(actual_platform, str)
|
||||
self.assertTrue(actual_platform)
|
||||
|
||||
# windows XP, 32bits
|
||||
os.name = 'nt'
|
||||
sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) '
|
||||
@@ -331,11 +362,28 @@ class TestSysConfig(unittest.TestCase):
|
||||
|
||||
self.assertEqual(get_platform(), 'linux-i686')
|
||||
|
||||
# Android
|
||||
os.name = 'posix'
|
||||
sys.platform = 'android'
|
||||
get_config_vars()['ANDROID_API_LEVEL'] = 9
|
||||
for machine, abi in {
|
||||
'x86_64': 'x86_64',
|
||||
'i686': 'x86',
|
||||
'aarch64': 'arm64_v8a',
|
||||
'armv7l': 'armeabi_v7a',
|
||||
}.items():
|
||||
with self.subTest(machine):
|
||||
self._set_uname(('Linux', 'localhost', '3.18.91+',
|
||||
'#1 Tue Jan 9 20:35:43 UTC 2018', machine))
|
||||
self.assertEqual(get_platform(), f'android-9-{abi}')
|
||||
|
||||
# XXX more platforms to tests here
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@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")
|
||||
def test_get_config_h_filename(self):
|
||||
config_h = sysconfig.get_config_h_filename()
|
||||
self.assertTrue(os.path.isfile(config_h), config_h)
|
||||
@@ -381,8 +429,8 @@ class TestSysConfig(unittest.TestCase):
|
||||
if name == 'platlib':
|
||||
# Replace "/lib64/python3.11/site-packages" suffix
|
||||
# with "/lib/python3.11/site-packages".
|
||||
py_version_short = sysconfig.get_python_version()
|
||||
suffix = f'python{py_version_short}/site-packages'
|
||||
py_version_abi = sysconfig._get_python_version_abi()
|
||||
suffix = f'python{py_version_abi}/site-packages'
|
||||
expected = expected.replace(f'/{sys.platlibdir}/{suffix}',
|
||||
f'/lib/{suffix}')
|
||||
self.assertEqual(user_path, expected)
|
||||
@@ -402,6 +450,32 @@ class TestSysConfig(unittest.TestCase):
|
||||
|
||||
self.assertIn(ldflags, ldshared)
|
||||
|
||||
@unittest.skipIf(not _imp.extension_suffixes(), "stub loader has no suffixes")
|
||||
def test_soabi(self):
|
||||
soabi = sysconfig.get_config_var('SOABI')
|
||||
self.assertIn(soabi, _imp.extension_suffixes()[0])
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
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'))
|
||||
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'))
|
||||
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}'))
|
||||
|
||||
@unittest.skipUnless(sys.platform == "darwin", "test only relevant on MacOSX")
|
||||
@requires_subprocess()
|
||||
def test_platform_in_subprocess(self):
|
||||
@@ -448,6 +522,8 @@ class TestSysConfig(unittest.TestCase):
|
||||
|
||||
@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")
|
||||
def test_srcdir(self):
|
||||
# See Issues #15322, #15364.
|
||||
srcdir = sysconfig.get_config_var('srcdir')
|
||||
@@ -460,11 +536,15 @@ class TestSysConfig(unittest.TestCase):
|
||||
# should be a full source checkout.
|
||||
Python_h = os.path.join(srcdir, 'Include', 'Python.h')
|
||||
self.assertTrue(os.path.exists(Python_h), Python_h)
|
||||
# <srcdir>/PC/pyconfig.h always exists even if unused on POSIX.
|
||||
pyconfig_h = os.path.join(srcdir, 'PC', 'pyconfig.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')
|
||||
self.assertTrue(os.path.exists(pyconfig_h), pyconfig_h)
|
||||
elif os.name == 'posix':
|
||||
makefile_dir = os.path.dirname(sysconfig.get_makefile_filename())
|
||||
# Issue #19340: srcdir has been realpath'ed already
|
||||
@@ -479,23 +559,16 @@ class TestSysConfig(unittest.TestCase):
|
||||
srcdir2 = sysconfig.get_config_var('srcdir')
|
||||
self.assertEqual(srcdir, srcdir2)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipIf(sysconfig.get_config_var('EXT_SUFFIX') is None,
|
||||
'EXT_SUFFIX required for this test')
|
||||
@unittest.skipIf(not _imp.extension_suffixes(), "stub loader has no suffixes")
|
||||
def test_EXT_SUFFIX_in_vars(self):
|
||||
import _imp
|
||||
if not _imp.extension_suffixes():
|
||||
self.skipTest("stub loader has no suffixes")
|
||||
vars = sysconfig.get_config_vars()
|
||||
self.assertEqual(vars['EXT_SUFFIX'], _imp.extension_suffixes()[0])
|
||||
|
||||
@unittest.skipUnless(sys.platform == 'linux' and
|
||||
hasattr(sys.implementation, '_multiarch'),
|
||||
'multiarch-specific test')
|
||||
def test_triplet_in_ext_suffix(self):
|
||||
@unittest.skipUnless(sys.platform == 'linux', 'Linux-specific test')
|
||||
def test_linux_ext_suffix(self):
|
||||
ctypes = import_module('ctypes')
|
||||
import platform, re
|
||||
machine = platform.machine()
|
||||
suffix = sysconfig.get_config_var('EXT_SUFFIX')
|
||||
if re.match('(aarch64|arm|mips|ppc|powerpc|s390|sparc)', machine):
|
||||
@@ -510,11 +583,97 @@ class TestSysConfig(unittest.TestCase):
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipUnless(sys.platform == 'android', 'Android-specific test')
|
||||
def test_android_ext_suffix(self):
|
||||
machine = platform.machine()
|
||||
suffix = sysconfig.get_config_var('EXT_SUFFIX')
|
||||
expected_triplet = {
|
||||
"x86_64": "x86_64-linux-android",
|
||||
"i686": "i686-linux-android",
|
||||
"aarch64": "aarch64-linux-android",
|
||||
"armv7l": "arm-linux-androideabi",
|
||||
}[machine]
|
||||
self.assertTrue(suffix.endswith(f"-{expected_triplet}.so"),
|
||||
f"{machine=}, {suffix=}")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@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)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@requires_subprocess()
|
||||
def test_config_vars_depend_on_site_initialization(self):
|
||||
script = textwrap.dedent("""
|
||||
import sysconfig
|
||||
|
||||
config_vars = sysconfig.get_config_vars()
|
||||
|
||||
import json
|
||||
print(json.dumps(config_vars, indent=2))
|
||||
""")
|
||||
|
||||
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)
|
||||
|
||||
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'])
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@requires_subprocess()
|
||||
def test_config_vars_recalculation_after_site_initialization(self):
|
||||
script = textwrap.dedent("""
|
||||
import sysconfig
|
||||
|
||||
before = sysconfig.get_config_vars()
|
||||
|
||||
import site
|
||||
site.main()
|
||||
|
||||
after = sysconfig.get_config_vars()
|
||||
|
||||
import json
|
||||
print(json.dumps({'before': before, 'after': after}, indent=2))
|
||||
""")
|
||||
|
||||
with self.venv() as venv:
|
||||
config_vars = json.loads(venv.run('-S', '-c', script).stdout)
|
||||
|
||||
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
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@requires_subprocess()
|
||||
def test_paths_depend_on_site_initialization(self):
|
||||
script = textwrap.dedent("""
|
||||
import sysconfig
|
||||
|
||||
paths = sysconfig.get_paths()
|
||||
|
||||
import json
|
||||
print(json.dumps(paths, indent=2))
|
||||
""")
|
||||
|
||||
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)
|
||||
|
||||
self.assertNotEqual(site_paths, no_site_paths)
|
||||
|
||||
|
||||
class MakefileTests(unittest.TestCase):
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@@ -522,6 +681,8 @@ class MakefileTests(unittest.TestCase):
|
||||
@unittest.skipIf(sys.platform.startswith('win'),
|
||||
'Test is not Windows compatible')
|
||||
@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")
|
||||
def test_get_makefile_filename(self):
|
||||
makefile = sysconfig.get_makefile_filename()
|
||||
self.assertTrue(os.path.isfile(makefile), makefile)
|
||||
@@ -536,7 +697,7 @@ class MakefileTests(unittest.TestCase):
|
||||
print("var5=dollar$$5", file=makefile)
|
||||
print("var6=${var3}/lib/python3.5/config-$(VAR2)$(var5)"
|
||||
"-x86_64-linux-gnu", file=makefile)
|
||||
vars = sysconfig._parse_makefile(TESTFN)
|
||||
vars = _parse_makefile(TESTFN)
|
||||
self.assertEqual(vars, {
|
||||
'var1': 'ab42',
|
||||
'VAR2': 'b42',
|
||||
@@ -547,5 +708,26 @@ class MakefileTests(unittest.TestCase):
|
||||
})
|
||||
|
||||
|
||||
class DeprecationTests(unittest.TestCase):
|
||||
def deprecated(self, removal_version, deprecation_msg=None, error=Exception, error_msg=None):
|
||||
if sys.version_info >= removal_version:
|
||||
return self.assertRaises(error, msg=error_msg)
|
||||
else:
|
||||
return self.assertWarns(DeprecationWarning, msg=deprecation_msg)
|
||||
|
||||
def test_is_python_build_check_home(self):
|
||||
with self.deprecated(
|
||||
removal_version=(3, 15),
|
||||
deprecation_msg=(
|
||||
'The check_home argument of sysconfig.is_python_build is '
|
||||
'deprecated and its value is ignored. '
|
||||
'It will be removed in Python 3.15.'
|
||||
),
|
||||
error=TypeError,
|
||||
error_msg="is_python_build() takes 0 positional arguments but 1 were given",
|
||||
):
|
||||
sysconfig.is_python_build('foo')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -18,6 +18,7 @@ mod stat;
|
||||
mod string;
|
||||
#[cfg(feature = "compiler")]
|
||||
mod symtable;
|
||||
mod sysconfig;
|
||||
mod sysconfigdata;
|
||||
#[cfg(feature = "threading")]
|
||||
pub mod thread;
|
||||
@@ -97,6 +98,7 @@ pub fn get_module_inits() -> StdlibMap {
|
||||
"_signal" => signal::make_module,
|
||||
"_sre" => sre::make_module,
|
||||
"_stat" => stat::make_module,
|
||||
"_sysconfig" => sysconfig::make_module,
|
||||
"_string" => string::make_module,
|
||||
"time" => time::make_module,
|
||||
"_typing" => typing::make_module,
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
pub(crate) use sysconfig::make_module;
|
||||
|
||||
#[pymodule(name = "_sysconfig")]
|
||||
pub(crate) mod sysconfig {
|
||||
use crate::{VirtualMachine, builtins::PyDictRef, convert::ToPyObject};
|
||||
|
||||
#[pyfunction]
|
||||
fn config_vars(vm: &VirtualMachine) -> PyDictRef {
|
||||
let vars = vm.ctx.new_dict();
|
||||
vars.set_item("Py_GIL_DISABLED", true.to_pyobject(vm), vm)
|
||||
.unwrap();
|
||||
vars
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user