Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
__init__.py800 linesDownload Raw Back to sysconfig
1"""Access to Python's configuration information."""2 3import os4import sys5import threading6from os.path import realpath7 8__all__ = [9    'get_config_h_filename',10    'get_config_var',11    'get_config_vars',12    'get_makefile_filename',13    'get_path',14    'get_path_names',15    'get_paths',16    'get_platform',17    'get_python_version',18    'get_scheme_names',19    'parse_config_h',20]21 22# Keys for get_config_var() that are never converted to Python integers.23_ALWAYS_STR = {24    'IPHONEOS_DEPLOYMENT_TARGET',25    'MACOSX_DEPLOYMENT_TARGET',26}27 28_INSTALL_SCHEMES = {29    'posix_prefix': {30        'stdlib': '{installed_base}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',31        'platstdlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',32        'purelib': '{base}/lib/{implementation_lower}{py_version_short}{abi_thread}/site-packages',33        'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}/site-packages',34        'include':35            '{installed_base}/include/{implementation_lower}{py_version_short}{abiflags}',36        'platinclude':37            '{installed_platbase}/include/{implementation_lower}{py_version_short}{abiflags}',38        'scripts': '{base}/bin',39        'data': '{base}',40        },41    'posix_home': {42        'stdlib': '{installed_base}/lib/{implementation_lower}',43        'platstdlib': '{base}/lib/{implementation_lower}',44        'purelib': '{base}/lib/{implementation_lower}',45        'platlib': '{base}/lib/{implementation_lower}',46        'include': '{installed_base}/include/{implementation_lower}',47        'platinclude': '{installed_base}/include/{implementation_lower}',48        'scripts': '{base}/bin',49        'data': '{base}',50        },51    'nt': {52        'stdlib': '{installed_base}/Lib',53        'platstdlib': '{base}/Lib',54        'purelib': '{base}/Lib/site-packages',55        'platlib': '{base}/Lib/site-packages',56        'include': '{installed_base}/Include',57        'platinclude': '{installed_base}/Include',58        'scripts': '{base}/Scripts',59        'data': '{base}',60        },61 62    # Downstream distributors can overwrite the default install scheme.63    # This is done to support downstream modifications where distributors change64    # the installation layout (eg. different site-packages directory).65    # So, distributors will change the default scheme to one that correctly66    # represents their layout.67    # This presents an issue for projects/people that need to bootstrap virtual68    # environments, like virtualenv. As distributors might now be customizing69    # the default install scheme, there is no guarantee that the information70    # returned by sysconfig.get_default_scheme/get_paths is correct for71    # a virtual environment, the only guarantee we have is that it is correct72    # for the *current* environment. When bootstrapping a virtual environment,73    # we need to know its layout, so that we can place the files in the74    # correct locations.75    # The "*_venv" install scheme is a scheme to bootstrap virtual environments,76    # essentially identical to the default posix_prefix/nt schemes.77    # Downstream distributors who patch posix_prefix/nt scheme are encouraged to78    # leave the following schemes unchanged79    'posix_venv': {80        'stdlib': '{installed_base}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',81        'platstdlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',82        'purelib': '{base}/lib/{implementation_lower}{py_version_short}{abi_thread}/site-packages',83        'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}/site-packages',84        'include':85            '{installed_base}/include/{implementation_lower}{py_version_short}{abiflags}',86        'platinclude':87            '{installed_platbase}/include/{implementation_lower}{py_version_short}{abiflags}',88        'scripts': '{base}/bin',89        'data': '{base}',90        },91    'nt_venv': {92        'stdlib': '{installed_base}/Lib',93        'platstdlib': '{base}/Lib',94        'purelib': '{base}/Lib/site-packages',95        'platlib': '{base}/Lib/site-packages',96        'include': '{installed_base}/Include',97        'platinclude': '{installed_base}/Include',98        'scripts': '{base}/Scripts',99        'data': '{base}',100        },101    }102 103# For the OS-native venv scheme, we essentially provide an alias:104if os.name == 'nt':105    _INSTALL_SCHEMES['venv'] = _INSTALL_SCHEMES['nt_venv']106else:107    _INSTALL_SCHEMES['venv'] = _INSTALL_SCHEMES['posix_venv']108 109def _get_implementation():110    return 'Python'111 112# NOTE: site.py has copy of this function.113# Sync it when modify this function.114def _getuserbase():115    env_base = os.environ.get("PYTHONUSERBASE", None)116    if env_base:117        return env_base118 119    # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories.120    # Use _PYTHON_HOST_PLATFORM to get the correct platform when cross-compiling.121    system_name = os.environ.get('_PYTHON_HOST_PLATFORM', sys.platform).split('-')[0]122    if system_name in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:123        return None124 125    def joinuser(*args):126        return os.path.expanduser(os.path.join(*args))127 128    if os.name == "nt":129        base = os.environ.get("APPDATA") or "~"130        return joinuser(base,  _get_implementation())131 132    if sys.platform == "darwin" and sys._framework:133        return joinuser("~", "Library", sys._framework,134                        f"{sys.version_info[0]}.{sys.version_info[1]}")135 136    return joinuser("~", ".local")137 138_HAS_USER_BASE = (_getuserbase() is not None)139 140if _HAS_USER_BASE:141    _INSTALL_SCHEMES |= {142        # NOTE: When modifying "purelib" scheme, update site._get_path() too.143        'nt_user': {144            'stdlib': '{userbase}/{implementation}{py_version_nodot_plat}',145            'platstdlib': '{userbase}/{implementation}{py_version_nodot_plat}',146            'purelib': '{userbase}/{implementation}{py_version_nodot_plat}/site-packages',147            'platlib': '{userbase}/{implementation}{py_version_nodot_plat}/site-packages',148            'include': '{userbase}/{implementation}{py_version_nodot_plat}/Include',149            'scripts': '{userbase}/{implementation}{py_version_nodot_plat}/Scripts',150            'data': '{userbase}',151            },152        'posix_user': {153            'stdlib': '{userbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',154            'platstdlib': '{userbase}/{platlibdir}/{implementation_lower}{py_version_short}{abi_thread}',155            'purelib': '{userbase}/lib/{implementation_lower}{py_version_short}{abi_thread}/site-packages',156            'platlib': '{userbase}/lib/{implementation_lower}{py_version_short}{abi_thread}/site-packages',157            'include': '{userbase}/include/{implementation_lower}{py_version_short}{abi_thread}',158            'scripts': '{userbase}/bin',159            'data': '{userbase}',160            },161        'osx_framework_user': {162            'stdlib': '{userbase}/lib/{implementation_lower}',163            'platstdlib': '{userbase}/lib/{implementation_lower}',164            'purelib': '{userbase}/lib/{implementation_lower}/site-packages',165            'platlib': '{userbase}/lib/{implementation_lower}/site-packages',166            'include': '{userbase}/include/{implementation_lower}{py_version_short}',167            'scripts': '{userbase}/bin',168            'data': '{userbase}',169            },170    }171 172_SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',173                'scripts', 'data')174 175_PY_VERSION = sys.version.split()[0]176_PY_VERSION_SHORT = f'{sys.version_info[0]}.{sys.version_info[1]}'177_PY_VERSION_SHORT_NO_DOT = f'{sys.version_info[0]}{sys.version_info[1]}'178_PREFIX = os.path.normpath(sys.prefix)179_BASE_PREFIX = os.path.normpath(sys.base_prefix)180_BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)181# Mutex guarding initialization of _CONFIG_VARS.182_CONFIG_VARS_LOCK = threading.RLock()183_CONFIG_VARS = None184# True iff _CONFIG_VARS has been fully initialized.185_CONFIG_VARS_INITIALIZED = False186_USER_BASE = None187 188 189def _safe_realpath(path):190    try:191        return realpath(path)192    except OSError:193        return path194 195if sys.executable:196    _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))197else:198    # sys.executable can be empty if argv[0] has been changed and Python is199    # unable to retrieve the real program name200    _PROJECT_BASE = _safe_realpath(os.getcwd())201 202# In a virtual environment, `sys._home` gives us the target directory203# `_PROJECT_BASE` for the executable that created it when the virtual204# python is an actual executable ('venv --copies' or Windows).205_sys_home = getattr(sys, '_home', None)206if _sys_home:207    _PROJECT_BASE = _sys_home208 209if os.name == 'nt':210    # In a source build, the executable is in a subdirectory of the root211    # that we want (<root>\PCbuild\<platname>).212    # `_BASE_PREFIX` is used as the base installation is where the source213    # will be.  The realpath is needed to prevent mount point confusion214    # that can occur with just string comparisons.215    if _safe_realpath(_PROJECT_BASE).startswith(216            _safe_realpath(f'{_BASE_PREFIX}\\PCbuild')):217        _PROJECT_BASE = _BASE_PREFIX218 219# set for cross builds220if "_PYTHON_PROJECT_BASE" in os.environ:221    _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"])222 223def is_python_build(check_home=None):224    if check_home is not None:225        import warnings226        warnings.warn(227            (228                'The check_home argument of sysconfig.is_python_build is '229                'deprecated and its value is ignored. '230                'It will be removed in Python 3.15.'231            ),232            DeprecationWarning,233            stacklevel=2,234        )235    for fn in ("Setup", "Setup.local"):236        if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)):237            return True238    return False239 240_PYTHON_BUILD = is_python_build()241 242if _PYTHON_BUILD:243    for scheme in ('posix_prefix', 'posix_home'):244        # On POSIX-y platforms, Python will:245        # - Build from .h files in 'headers' (which is only added to the246        #   scheme when building CPython)247        # - Install .h files to 'include'248        scheme = _INSTALL_SCHEMES[scheme]249        scheme['headers'] = scheme['include']250        scheme['include'] = '{srcdir}/Include'251        scheme['platinclude'] = '{projectbase}/.'252    del scheme253 254 255def _subst_vars(s, local_vars):256    try:257        return s.format(**local_vars)258    except KeyError as var:259        try:260            return s.format(**os.environ)261        except KeyError:262            raise AttributeError(f'{var}') from None263 264def _extend_dict(target_dict, other_dict):265    target_keys = target_dict.keys()266    for key, value in other_dict.items():267        if key in target_keys:268            continue269        target_dict[key] = value270 271 272def _expand_vars(scheme, vars):273    res = {}274    if vars is None:275        vars = {}276    _extend_dict(vars, get_config_vars())277    if os.name == 'nt':278        # On Windows we want to substitute 'lib' for schemes rather279        # than the native value (without modifying vars, in case it280        # was passed in)281        vars = vars | {'platlibdir': 'lib'}282 283    for key, value in _INSTALL_SCHEMES[scheme].items():284        if os.name in ('posix', 'nt'):285            value = os.path.expanduser(value)286        res[key] = os.path.normpath(_subst_vars(value, vars))287    return res288 289 290def _get_preferred_schemes():291    if os.name == 'nt':292        return {293            'prefix': 'nt',294            'home': 'posix_home',295            'user': 'nt_user',296        }297    if sys.platform == 'darwin' and sys._framework:298        return {299            'prefix': 'posix_prefix',300            'home': 'posix_home',301            'user': 'osx_framework_user',302        }303 304    return {305        'prefix': 'posix_prefix',306        'home': 'posix_home',307        'user': 'posix_user',308    }309 310 311def get_preferred_scheme(key):312    if key == 'prefix' and sys.prefix != sys.base_prefix:313        return 'venv'314    scheme = _get_preferred_schemes()[key]315    if scheme not in _INSTALL_SCHEMES:316        raise ValueError(317            f"{key!r} returned {scheme!r}, which is not a valid scheme "318            f"on this platform"319        )320    return scheme321 322 323def get_default_scheme():324    return get_preferred_scheme('prefix')325 326 327def get_makefile_filename():328    """Return the path of the Makefile."""329 330    # GH-127429: When cross-compiling, use the Makefile from the target, instead of the host Python.331    if cross_base := os.environ.get('_PYTHON_PROJECT_BASE'):332        return os.path.join(cross_base, 'Makefile')333 334    if _PYTHON_BUILD:335        return os.path.join(_PROJECT_BASE, "Makefile")336 337    if hasattr(sys, 'abiflags'):338        config_dir_name = f'config-{_PY_VERSION_SHORT}{sys.abiflags}'339    else:340        config_dir_name = 'config'341 342    if hasattr(sys.implementation, '_multiarch'):343        config_dir_name += f'-{sys.implementation._multiarch}'344 345    return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')346 347 348def _import_from_directory(path, name):349    if name not in sys.modules:350        import importlib.machinery351        import importlib.util352 353        spec = importlib.machinery.PathFinder.find_spec(name, [path])354        module = importlib.util.module_from_spec(spec)355        spec.loader.exec_module(module)356        sys.modules[name] = module357    return sys.modules[name]358 359 360def _get_sysconfigdata_name():361    multiarch = getattr(sys.implementation, '_multiarch', '')362    return os.environ.get(363        '_PYTHON_SYSCONFIGDATA_NAME',364        f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}',365    )366 367 368def _get_sysconfigdata():369    import importlib370 371    name = _get_sysconfigdata_name()372    path = os.environ.get('_PYTHON_SYSCONFIGDATA_PATH')373    module = _import_from_directory(path, name) if path else importlib.import_module(name)374 375    return module.build_time_vars376 377 378def _installation_is_relocated():379    """Is the Python installation running from a different prefix than what was targetted when building?"""380    if os.name != 'posix':381        raise NotImplementedError('sysconfig._installation_is_relocated() is currently only supported on POSIX')382 383    data = _get_sysconfigdata()384    return (385        data['prefix'] != getattr(sys, 'base_prefix', '')386        or data['exec_prefix'] != getattr(sys, 'base_exec_prefix', '')387    )388 389 390def _init_posix(vars):391    """Initialize the module as appropriate for POSIX systems."""392    # GH-126920: Make sure we don't overwrite any of the keys already set393    vars.update(_get_sysconfigdata() | vars)394 395 396def _init_non_posix(vars):397    """Initialize the module as appropriate for NT"""398    # set basic install directories399    import _winapi400    import _sysconfig401    vars['LIBDEST'] = get_path('stdlib')402    vars['BINLIBDEST'] = get_path('platstdlib')403    vars['INCLUDEPY'] = get_path('include')404 405    # Add EXT_SUFFIX, SOABI, Py_DEBUG, and Py_GIL_DISABLED406    vars.update(_sysconfig.config_vars())407 408    # NOTE: ABIFLAGS is only an emulated value. It is not present during build409    #       on Windows. sys.abiflags is absent on Windows and vars['abiflags']410    #       is already widely used to calculate paths, so it should remain an411    #       empty string.412    vars['ABIFLAGS'] = ''.join(413        (414            't' if vars['Py_GIL_DISABLED'] else '',415            '_d' if vars['Py_DEBUG'] else '',416        ),417    )418 419    vars['LIBDIR'] = _safe_realpath(os.path.join(get_config_var('installed_base'), 'libs'))420    if hasattr(sys, 'dllhandle'):421        dllhandle = _winapi.GetModuleFileName(sys.dllhandle)422        vars['LIBRARY'] = os.path.basename(_safe_realpath(dllhandle))423        vars['LDLIBRARY'] = vars['LIBRARY']424    vars['EXE'] = '.exe'425    vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT426    vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))427    vars['TZPATH'] = ''428 429#430# public APIs431#432 433 434def parse_config_h(fp, vars=None):435    """Parse a config.h-style file.436 437    A dictionary containing name/value pairs is returned.  If an438    optional dictionary is passed in as the second argument, it is439    used instead of a new dictionary.440    """441    if vars is None:442        vars = {}443    import re444    define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")445    undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")446 447    while True:448        line = fp.readline()449        if not line:450            break451        m = define_rx.match(line)452        if m:453            n, v = m.group(1, 2)454            try:455                if n in _ALWAYS_STR:456                    raise ValueError457                v = int(v)458            except ValueError:459                pass460            vars[n] = v461        else:462            m = undef_rx.match(line)463            if m:464                vars[m.group(1)] = 0465    return vars466 467 468def get_config_h_filename():469    """Return the path of pyconfig.h."""470    if _PYTHON_BUILD:471        if os.name == "nt":472            inc_dir = os.path.join(_PROJECT_BASE, 'PC')473        else:474            inc_dir = _PROJECT_BASE475    else:476        inc_dir = get_path('platinclude')477    return os.path.join(inc_dir, 'pyconfig.h')478 479 480def get_scheme_names():481    """Return a tuple containing the schemes names."""482    return tuple(sorted(_INSTALL_SCHEMES))483 484 485def get_path_names():486    """Return a tuple containing the paths names."""487    return _SCHEME_KEYS488 489 490def get_paths(scheme=get_default_scheme(), vars=None, expand=True):491    """Return a mapping containing an install scheme.492 493    ``scheme`` is the install scheme name. If not provided, it will494    return the default scheme for the current platform.495    """496    if expand:497        return _expand_vars(scheme, vars)498    else:499        return _INSTALL_SCHEMES[scheme]500 501 502def get_path(name, scheme=get_default_scheme(), vars=None, expand=True):503    """Return a path corresponding to the scheme.504 505    ``scheme`` is the install scheme name.506    """507    return get_paths(scheme, vars, expand)[name]508 509 510def _init_config_vars():511    global _CONFIG_VARS512    _CONFIG_VARS = {}513 514    prefix = os.path.normpath(sys.prefix)515    exec_prefix = os.path.normpath(sys.exec_prefix)516    base_prefix = _BASE_PREFIX517    base_exec_prefix = _BASE_EXEC_PREFIX518 519    try:520        abiflags = sys.abiflags521    except AttributeError:522        abiflags = ''523 524    if os.name == 'posix':525        _init_posix(_CONFIG_VARS)526        # If we are cross-compiling, load the prefixes from the Makefile instead.527        if '_PYTHON_PROJECT_BASE' in os.environ:528            prefix = _CONFIG_VARS['host_prefix']529            exec_prefix = _CONFIG_VARS['host_exec_prefix']530            base_prefix = _CONFIG_VARS['host_prefix']531            base_exec_prefix = _CONFIG_VARS['host_exec_prefix']532            abiflags = _CONFIG_VARS['ABIFLAGS']533 534    # Normalized versions of prefix and exec_prefix are handy to have;535    # in fact, these are the standard versions used most places in the536    # Distutils.537    _CONFIG_VARS['prefix'] = prefix538    _CONFIG_VARS['exec_prefix'] = exec_prefix539    _CONFIG_VARS['py_version'] = _PY_VERSION540    _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT541    _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT542    _CONFIG_VARS['installed_base'] = base_prefix543    _CONFIG_VARS['base'] = prefix544    _CONFIG_VARS['installed_platbase'] = base_exec_prefix545    _CONFIG_VARS['platbase'] = exec_prefix546    _CONFIG_VARS['projectbase'] = _PROJECT_BASE547    _CONFIG_VARS['platlibdir'] = sys.platlibdir548    _CONFIG_VARS['implementation'] = _get_implementation()549    _CONFIG_VARS['implementation_lower'] = _get_implementation().lower()550    _CONFIG_VARS['abiflags'] = abiflags551    try:552        _CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '')553    except AttributeError:554        _CONFIG_VARS['py_version_nodot_plat'] = ''555 556    if os.name == 'nt':557        _init_non_posix(_CONFIG_VARS)558        _CONFIG_VARS['VPATH'] = sys._vpath559        _CONFIG_VARS['TZPATH'] = os.path.join(_PREFIX, "share", "zoneinfo")560    if _HAS_USER_BASE:561        # Setting 'userbase' is done below the call to the562        # init function to enable using 'get_config_var' in563        # the init-function.564        _CONFIG_VARS['userbase'] = _getuserbase()565 566    # e.g., 't' for free-threaded or '' for default build567    _CONFIG_VARS['abi_thread'] = 't' if _CONFIG_VARS.get('Py_GIL_DISABLED') else ''568 569    # Always convert srcdir to an absolute path570    srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)571    if os.name == 'posix':572        if _PYTHON_BUILD:573            # If srcdir is a relative path (typically '.' or '..')574            # then it should be interpreted relative to the directory575            # containing Makefile.576            base = os.path.dirname(get_makefile_filename())577            srcdir = os.path.join(base, srcdir)578        else:579            # srcdir is not meaningful since the installation is580            # spread about the filesystem.  We choose the581            # directory containing the Makefile since we know it582            # exists.583            srcdir = os.path.dirname(get_makefile_filename())584    _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir)585 586    # OS X platforms require special customization to handle587    # multi-architecture, multi-os-version installers588    if sys.platform == 'darwin':589        import _osx_support590        _osx_support.customize_config_vars(_CONFIG_VARS)591 592    global _CONFIG_VARS_INITIALIZED593    _CONFIG_VARS_INITIALIZED = True594 595 596def get_config_vars(*args):597    """With no arguments, return a dictionary of all configuration598    variables relevant for the current platform.599 600    On Unix, this means every variable defined in Python's installed Makefile;601    On Windows it's a much smaller set.602 603    With arguments, return a list of values that result from looking up604    each argument in the configuration variable dictionary.605    """606    global _CONFIG_VARS_INITIALIZED607 608    # Avoid claiming the lock once initialization is complete.609    if _CONFIG_VARS_INITIALIZED:610        # GH-126789: If sys.prefix or sys.exec_prefix were updated, invalidate the cache.611        prefix = os.path.normpath(sys.prefix)612        exec_prefix = os.path.normpath(sys.exec_prefix)613        if _CONFIG_VARS['prefix'] != prefix or _CONFIG_VARS['exec_prefix'] != exec_prefix:614            with _CONFIG_VARS_LOCK:615                _CONFIG_VARS_INITIALIZED = False616                _init_config_vars()617    else:618        # Initialize the config_vars cache.619        with _CONFIG_VARS_LOCK:620            # Test again with the lock held to avoid races. Note that621            # we test _CONFIG_VARS here, not _CONFIG_VARS_INITIALIZED,622            # to ensure that recursive calls to get_config_vars()623            # don't re-enter init_config_vars().624            if _CONFIG_VARS is None:625                _init_config_vars()626 627    if args:628        vals = []629        for name in args:630            vals.append(_CONFIG_VARS.get(name))631        return vals632    else:633        return _CONFIG_VARS634 635 636def get_config_var(name):637    """Return the value of a single variable using the dictionary returned by638    'get_config_vars()'.639 640    Equivalent to get_config_vars().get(name)641    """642    return get_config_vars().get(name)643 644 645def get_platform():646    """Return a string that identifies the current platform.647 648    This is used mainly to distinguish platform-specific build directories and649    platform-specific built distributions.  Typically includes the OS name and650    version and the architecture (as supplied by 'os.uname()'), although the651    exact information included depends on the OS; on Linux, the kernel version652    isn't particularly important.653 654    Examples of returned values:655 656 657    Windows:658 659    - win-amd64 (64-bit Windows on AMD64, aka x86_64, Intel64, and EM64T)660    - win-arm64 (64-bit Windows on ARM64, aka AArch64)661    - win32 (all others - specifically, sys.platform is returned)662 663    POSIX based OS:664 665    - linux-x86_64666    - macosx-15.5-arm64667    - macosx-26.0-universal2 (macOS on Apple Silicon or Intel)668    - android-24-arm64_v8a669 670    For other non-POSIX platforms, currently just returns :data:`sys.platform`."""671    if os.name == 'nt':672        if 'amd64' in sys.version.lower():673            return 'win-amd64'674        if '(arm)' in sys.version.lower():675            return 'win-arm32'676        if '(arm64)' in sys.version.lower():677            return 'win-arm64'678        return sys.platform679 680    if os.name != "posix" or not hasattr(os, 'uname'):681        # XXX what about the architecture? NT is Intel or Alpha682        return sys.platform683 684    # Set for cross builds explicitly685    if "_PYTHON_HOST_PLATFORM" in os.environ:686        osname, _, machine = os.environ["_PYTHON_HOST_PLATFORM"].partition('-')687        release = None688    else:689        # Try to distinguish various flavours of Unix690        osname, host, release, version, machine = os.uname()691 692        # Convert the OS name to lowercase, remove '/' characters, and translate693        # spaces (for "Power Macintosh")694        osname = osname.lower().replace('/', '')695        machine = machine.replace(' ', '_')696        machine = machine.replace('/', '-')697 698    if osname == "android" or sys.platform == "android":699        osname = "android"700        release = get_config_var("ANDROID_API_LEVEL")701 702        # Wheel tags use the ABI names from Android's own tools.703        # When Python is running on 32-bit ARM Android on a 64-bit ARM kernel,704        # 'os.uname().machine' is 'armv8l'. Such devices run the same userspace705        # code as 'armv7l' devices.706        # During the build process of the Android testbed when targeting 32-bit ARM,707        # '_PYTHON_HOST_PLATFORM' is 'arm-linux-androideabi', so 'machine' becomes708        # 'arm'.709        machine = {710            "aarch64": "arm64_v8a",711            "arm": "armeabi_v7a",712            "armv7l": "armeabi_v7a",713            "armv8l": "armeabi_v7a",714            "i686": "x86",715            "x86_64": "x86_64",716        }[machine]717    elif osname == "linux":718        # At least on Linux/Intel, 'machine' is the processor --719        # i386, etc.720        # XXX what about Alpha, SPARC, etc?721        return  f"{osname}-{machine}"722    elif osname[:5] == "sunos":723        if release[0] >= "5":           # SunOS 5 == Solaris 2724            osname = "solaris"725            release = f"{int(release[0]) - 3}.{release[2:]}"726            # We can't use "platform.architecture()[0]" because a727            # bootstrap problem. We use a dict to get an error728            # if some suspicious happens.729            bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}730            machine += f".{bitness[sys.maxsize]}"731        # fall through to standard osname-release-machine representation732    elif osname[:3] == "aix":733        from _aix_support import aix_platform734        return aix_platform()735    elif osname[:6] == "cygwin":736        osname = "cygwin"737        import re738        rel_re = re.compile(r'[\d.]+')739        m = rel_re.match(release)740        if m:741            release = m.group()742    elif osname[:6] == "darwin":743        if sys.platform == "ios":744            release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0")745            osname = sys.platform746            machine = sys.implementation._multiarch747        else:748            import _osx_support749            osname, release, machine = _osx_support.get_platform_osx(750                                                get_config_vars(),751                                                osname, release, machine)752 753    return '-'.join(map(str, filter(None, (osname, release, machine))))754 755 756def get_python_version():757    return _PY_VERSION_SHORT758 759 760def _get_python_version_abi():761    return _PY_VERSION_SHORT + get_config_var("abi_thread")762 763 764def expand_makefile_vars(s, vars):765    """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in766    'string' according to 'vars' (a dictionary mapping variable names to767    values).  Variables not present in 'vars' are silently expanded to the768    empty string.  The variable values in 'vars' should not contain further769    variable expansions; if 'vars' is the output of 'parse_makefile()',770    you're fine.  Returns a variable-expanded version of 's'.771    """772 773    import warnings774    warnings.warn(775        'sysconfig.expand_makefile_vars is deprecated and will be removed in '776        'Python 3.16. Use sysconfig.get_paths(vars=...) instead.',777        DeprecationWarning,778        stacklevel=2,779    )780 781    import re782 783    _findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"784    _findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}"785 786    # This algorithm does multiple expansion, so if vars['foo'] contains787    # "${bar}", it will expand ${foo} to ${bar}, and then expand788    # ${bar}... and so forth.  This is fine as long as 'vars' comes from789    # 'parse_makefile()', which takes care of such expansions eagerly,790    # according to make's variable expansion semantics.791 792    while True:793        m = re.search(_findvar1_rx, s) or re.search(_findvar2_rx, s)794        if m:795            (beg, end) = m.span()796            s = s[0:beg] + vars.get(m.group(1)) + s[end:]797        else:798            break799    return s800 
codekingpro/portable-devtools · Team Ai