• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Access to Python's configuration information."""
2
3import os
4import sys
5from os.path import pardir, realpath
6
7__all__ = [
8    'get_config_h_filename',
9    'get_config_var',
10    'get_config_vars',
11    'get_makefile_filename',
12    'get_path',
13    'get_path_names',
14    'get_paths',
15    'get_platform',
16    'get_python_version',
17    'get_scheme_names',
18    'parse_config_h',
19]
20
21_INSTALL_SCHEMES = {
22    'posix_prefix': {
23        'stdlib': '{installed_base}/lib/python{py_version_short}',
24        'platstdlib': '{platbase}/lib/python{py_version_short}',
25        'purelib': '{base}/lib/python{py_version_short}/site-packages',
26        'platlib': '{platbase}/lib/python{py_version_short}/site-packages',
27        'include':
28            '{installed_base}/include/python{py_version_short}{abiflags}',
29        'platinclude':
30            '{installed_platbase}/include/python{py_version_short}{abiflags}',
31        'scripts': '{base}/bin',
32        'data': '{base}',
33        },
34    'posix_home': {
35        'stdlib': '{installed_base}/lib/python',
36        'platstdlib': '{base}/lib/python',
37        'purelib': '{base}/lib/python',
38        'platlib': '{base}/lib/python',
39        'include': '{installed_base}/include/python',
40        'platinclude': '{installed_base}/include/python',
41        'scripts': '{base}/bin',
42        'data': '{base}',
43        },
44    'nt': {
45        'stdlib': '{installed_base}/Lib',
46        'platstdlib': '{base}/Lib',
47        'purelib': '{base}/Lib/site-packages',
48        'platlib': '{base}/Lib/site-packages',
49        'include': '{installed_base}/Include',
50        'platinclude': '{installed_base}/Include',
51        'scripts': '{base}/Scripts',
52        'data': '{base}',
53        },
54    # NOTE: When modifying "purelib" scheme, update site._get_path() too.
55    'nt_user': {
56        'stdlib': '{userbase}/Python{py_version_nodot}',
57        'platstdlib': '{userbase}/Python{py_version_nodot}',
58        'purelib': '{userbase}/Python{py_version_nodot}/site-packages',
59        'platlib': '{userbase}/Python{py_version_nodot}/site-packages',
60        'include': '{userbase}/Python{py_version_nodot}/Include',
61        'scripts': '{userbase}/Python{py_version_nodot}/Scripts',
62        'data': '{userbase}',
63        },
64    'posix_user': {
65        'stdlib': '{userbase}/lib/python{py_version_short}',
66        'platstdlib': '{userbase}/lib/python{py_version_short}',
67        'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
68        'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
69        'include': '{userbase}/include/python{py_version_short}',
70        'scripts': '{userbase}/bin',
71        'data': '{userbase}',
72        },
73    'osx_framework_user': {
74        'stdlib': '{userbase}/lib/python',
75        'platstdlib': '{userbase}/lib/python',
76        'purelib': '{userbase}/lib/python/site-packages',
77        'platlib': '{userbase}/lib/python/site-packages',
78        'include': '{userbase}/include',
79        'scripts': '{userbase}/bin',
80        'data': '{userbase}',
81        },
82    }
83
84_SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
85                'scripts', 'data')
86
87 # FIXME don't rely on sys.version here, its format is an implementation detail
88 # of CPython, use sys.version_info or sys.hexversion
89_PY_VERSION = sys.version.split()[0]
90_PY_VERSION_SHORT = '%d.%d' % sys.version_info[:2]
91_PY_VERSION_SHORT_NO_DOT = '%d%d' % sys.version_info[:2]
92_PREFIX = os.path.normpath(sys.prefix)
93_BASE_PREFIX = os.path.normpath(sys.base_prefix)
94_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
95_BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
96_CONFIG_VARS = None
97_USER_BASE = None
98
99
100def _safe_realpath(path):
101    try:
102        return realpath(path)
103    except OSError:
104        return path
105
106if sys.executable:
107    _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
108else:
109    # sys.executable can be empty if argv[0] has been changed and Python is
110    # unable to retrieve the real program name
111    _PROJECT_BASE = _safe_realpath(os.getcwd())
112
113if (os.name == 'nt' and
114    _PROJECT_BASE.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))):
115    _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
116
117# set for cross builds
118if "_PYTHON_PROJECT_BASE" in os.environ:
119    _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"])
120
121def _is_python_source_dir(d):
122    for fn in ("Setup", "Setup.local"):
123        if os.path.isfile(os.path.join(d, "Modules", fn)):
124            return True
125    return False
126
127_sys_home = getattr(sys, '_home', None)
128
129if os.name == 'nt':
130    def _fix_pcbuild(d):
131        if d and os.path.normcase(d).startswith(
132                os.path.normcase(os.path.join(_PREFIX, "PCbuild"))):
133            return _PREFIX
134        return d
135    _PROJECT_BASE = _fix_pcbuild(_PROJECT_BASE)
136    _sys_home = _fix_pcbuild(_sys_home)
137
138def is_python_build(check_home=False):
139    if check_home and _sys_home:
140        return _is_python_source_dir(_sys_home)
141    return _is_python_source_dir(_PROJECT_BASE)
142
143_PYTHON_BUILD = is_python_build(True)
144
145if _PYTHON_BUILD:
146    for scheme in ('posix_prefix', 'posix_home'):
147        _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include'
148        _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.'
149
150
151def _subst_vars(s, local_vars):
152    try:
153        return s.format(**local_vars)
154    except KeyError:
155        try:
156            return s.format(**os.environ)
157        except KeyError as var:
158            raise AttributeError('{%s}' % var) from None
159
160def _extend_dict(target_dict, other_dict):
161    target_keys = target_dict.keys()
162    for key, value in other_dict.items():
163        if key in target_keys:
164            continue
165        target_dict[key] = value
166
167
168def _expand_vars(scheme, vars):
169    res = {}
170    if vars is None:
171        vars = {}
172    _extend_dict(vars, get_config_vars())
173
174    for key, value in _INSTALL_SCHEMES[scheme].items():
175        if os.name in ('posix', 'nt'):
176            value = os.path.expanduser(value)
177        res[key] = os.path.normpath(_subst_vars(value, vars))
178    return res
179
180
181def _get_default_scheme():
182    if os.name == 'posix':
183        # the default scheme for posix is posix_prefix
184        return 'posix_prefix'
185    return os.name
186
187
188# NOTE: site.py has copy of this function.
189# Sync it when modify this function.
190def _getuserbase():
191    env_base = os.environ.get("PYTHONUSERBASE", None)
192    if env_base:
193        return env_base
194
195    def joinuser(*args):
196        return os.path.expanduser(os.path.join(*args))
197
198    if os.name == "nt":
199        base = os.environ.get("APPDATA") or "~"
200        return joinuser(base, "Python")
201
202    if sys.platform == "darwin" and sys._framework:
203        return joinuser("~", "Library", sys._framework,
204                        "%d.%d" % sys.version_info[:2])
205
206    return joinuser("~", ".local")
207
208
209def _parse_makefile(filename, vars=None):
210    """Parse a Makefile-style file.
211
212    A dictionary containing name/value pairs is returned.  If an
213    optional dictionary is passed in as the second argument, it is
214    used instead of a new dictionary.
215    """
216    # Regexes needed for parsing Makefile (and similar syntaxes,
217    # like old-style Setup files).
218    import re
219    _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
220    _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
221    _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
222
223    if vars is None:
224        vars = {}
225    done = {}
226    notdone = {}
227
228    with open(filename, errors="surrogateescape") as f:
229        lines = f.readlines()
230
231    for line in lines:
232        if line.startswith('#') or line.strip() == '':
233            continue
234        m = _variable_rx.match(line)
235        if m:
236            n, v = m.group(1, 2)
237            v = v.strip()
238            # `$$' is a literal `$' in make
239            tmpv = v.replace('$$', '')
240
241            if "$" in tmpv:
242                notdone[n] = v
243            else:
244                try:
245                    v = int(v)
246                except ValueError:
247                    # insert literal `$'
248                    done[n] = v.replace('$$', '$')
249                else:
250                    done[n] = v
251
252    # do variable interpolation here
253    variables = list(notdone.keys())
254
255    # Variables with a 'PY_' prefix in the makefile. These need to
256    # be made available without that prefix through sysconfig.
257    # Special care is needed to ensure that variable expansion works, even
258    # if the expansion uses the name without a prefix.
259    renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
260
261    while len(variables) > 0:
262        for name in tuple(variables):
263            value = notdone[name]
264            m1 = _findvar1_rx.search(value)
265            m2 = _findvar2_rx.search(value)
266            if m1 and m2:
267                m = m1 if m1.start() < m2.start() else m2
268            else:
269                m = m1 if m1 else m2
270            if m is not None:
271                n = m.group(1)
272                found = True
273                if n in done:
274                    item = str(done[n])
275                elif n in notdone:
276                    # get it on a subsequent round
277                    found = False
278                elif n in os.environ:
279                    # do it like make: fall back to environment
280                    item = os.environ[n]
281
282                elif n in renamed_variables:
283                    if (name.startswith('PY_') and
284                        name[3:] in renamed_variables):
285                        item = ""
286
287                    elif 'PY_' + n in notdone:
288                        found = False
289
290                    else:
291                        item = str(done['PY_' + n])
292
293                else:
294                    done[n] = item = ""
295
296                if found:
297                    after = value[m.end():]
298                    value = value[:m.start()] + item + after
299                    if "$" in after:
300                        notdone[name] = value
301                    else:
302                        try:
303                            value = int(value)
304                        except ValueError:
305                            done[name] = value.strip()
306                        else:
307                            done[name] = value
308                        variables.remove(name)
309
310                        if name.startswith('PY_') \
311                        and name[3:] in renamed_variables:
312
313                            name = name[3:]
314                            if name not in done:
315                                done[name] = value
316
317            else:
318                # bogus variable reference (e.g. "prefix=$/opt/python");
319                # just drop it since we can't deal
320                done[name] = value
321                variables.remove(name)
322
323    # strip spurious spaces
324    for k, v in done.items():
325        if isinstance(v, str):
326            done[k] = v.strip()
327
328    # save the results in the global dictionary
329    vars.update(done)
330    return vars
331
332
333def get_makefile_filename():
334    """Return the path of the Makefile."""
335    if _PYTHON_BUILD:
336        return os.path.join(_sys_home or _PROJECT_BASE, "Makefile")
337    if hasattr(sys, 'abiflags'):
338        config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags)
339    else:
340        config_dir_name = 'config'
341    if hasattr(sys.implementation, '_multiarch'):
342        config_dir_name += '-%s' % sys.implementation._multiarch
343    return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
344
345
346def _get_sysconfigdata_name():
347    return os.environ.get('_PYTHON_SYSCONFIGDATA_NAME',
348        '_sysconfigdata_{abi}_{platform}_{multiarch}'.format(
349        abi=sys.abiflags,
350        platform=sys.platform,
351        multiarch=getattr(sys.implementation, '_multiarch', ''),
352    ))
353
354
355def _generate_posix_vars():
356    """Generate the Python module containing build-time variables."""
357    import pprint
358    vars = {}
359    # load the installed Makefile:
360    makefile = get_makefile_filename()
361    try:
362        _parse_makefile(makefile, vars)
363    except OSError as e:
364        msg = "invalid Python installation: unable to open %s" % makefile
365        if hasattr(e, "strerror"):
366            msg = msg + " (%s)" % e.strerror
367        raise OSError(msg)
368    # load the installed pyconfig.h:
369    config_h = get_config_h_filename()
370    try:
371        with open(config_h) as f:
372            parse_config_h(f, vars)
373    except OSError as e:
374        msg = "invalid Python installation: unable to open %s" % config_h
375        if hasattr(e, "strerror"):
376            msg = msg + " (%s)" % e.strerror
377        raise OSError(msg)
378    # On AIX, there are wrong paths to the linker scripts in the Makefile
379    # -- these paths are relative to the Python source, but when installed
380    # the scripts are in another directory.
381    if _PYTHON_BUILD:
382        vars['BLDSHARED'] = vars['LDSHARED']
383
384    # There's a chicken-and-egg situation on OS X with regards to the
385    # _sysconfigdata module after the changes introduced by #15298:
386    # get_config_vars() is called by get_platform() as part of the
387    # `make pybuilddir.txt` target -- which is a precursor to the
388    # _sysconfigdata.py module being constructed.  Unfortunately,
389    # get_config_vars() eventually calls _init_posix(), which attempts
390    # to import _sysconfigdata, which we won't have built yet.  In order
391    # for _init_posix() to work, if we're on Darwin, just mock up the
392    # _sysconfigdata module manually and populate it with the build vars.
393    # This is more than sufficient for ensuring the subsequent call to
394    # get_platform() succeeds.
395    name = _get_sysconfigdata_name()
396    if 'darwin' in sys.platform:
397        import types
398        module = types.ModuleType(name)
399        module.build_time_vars = vars
400        sys.modules[name] = module
401
402    pybuilddir = 'build/lib.%s-%s' % (get_platform(), _PY_VERSION_SHORT)
403    if hasattr(sys, "gettotalrefcount"):
404        pybuilddir += '-pydebug'
405    os.makedirs(pybuilddir, exist_ok=True)
406    destfile = os.path.join(pybuilddir, name + '.py')
407
408    with open(destfile, 'w', encoding='utf8') as f:
409        f.write('# system configuration generated and used by'
410                ' the sysconfig module\n')
411        f.write('build_time_vars = ')
412        pprint.pprint(vars, stream=f)
413
414    # Create file used for sys.path fixup -- see Modules/getpath.c
415    with open('pybuilddir.txt', 'w', encoding='utf8') as f:
416        f.write(pybuilddir)
417
418def _init_posix(vars):
419    """Initialize the module as appropriate for POSIX systems."""
420    # _sysconfigdata is generated at build time, see _generate_posix_vars()
421    name = _get_sysconfigdata_name()
422    _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
423    build_time_vars = _temp.build_time_vars
424    vars.update(build_time_vars)
425
426def _init_non_posix(vars):
427    """Initialize the module as appropriate for NT"""
428    # set basic install directories
429    vars['LIBDEST'] = get_path('stdlib')
430    vars['BINLIBDEST'] = get_path('platstdlib')
431    vars['INCLUDEPY'] = get_path('include')
432    vars['EXT_SUFFIX'] = '.pyd'
433    vars['EXE'] = '.exe'
434    vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
435    vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
436
437#
438# public APIs
439#
440
441
442def parse_config_h(fp, vars=None):
443    """Parse a config.h-style file.
444
445    A dictionary containing name/value pairs is returned.  If an
446    optional dictionary is passed in as the second argument, it is
447    used instead of a new dictionary.
448    """
449    if vars is None:
450        vars = {}
451    import re
452    define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
453    undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
454
455    while True:
456        line = fp.readline()
457        if not line:
458            break
459        m = define_rx.match(line)
460        if m:
461            n, v = m.group(1, 2)
462            try:
463                v = int(v)
464            except ValueError:
465                pass
466            vars[n] = v
467        else:
468            m = undef_rx.match(line)
469            if m:
470                vars[m.group(1)] = 0
471    return vars
472
473
474def get_config_h_filename():
475    """Return the path of pyconfig.h."""
476    if _PYTHON_BUILD:
477        if os.name == "nt":
478            inc_dir = os.path.join(_sys_home or _PROJECT_BASE, "PC")
479        else:
480            inc_dir = _sys_home or _PROJECT_BASE
481    else:
482        inc_dir = get_path('platinclude')
483    return os.path.join(inc_dir, 'pyconfig.h')
484
485
486def get_scheme_names():
487    """Return a tuple containing the schemes names."""
488    return tuple(sorted(_INSTALL_SCHEMES))
489
490
491def get_path_names():
492    """Return a tuple containing the paths names."""
493    return _SCHEME_KEYS
494
495
496def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
497    """Return a mapping containing an install scheme.
498
499    ``scheme`` is the install scheme name. If not provided, it will
500    return the default scheme for the current platform.
501    """
502    if expand:
503        return _expand_vars(scheme, vars)
504    else:
505        return _INSTALL_SCHEMES[scheme]
506
507
508def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
509    """Return a path corresponding to the scheme.
510
511    ``scheme`` is the install scheme name.
512    """
513    return get_paths(scheme, vars, expand)[name]
514
515
516def get_config_vars(*args):
517    """With no arguments, return a dictionary of all configuration
518    variables relevant for the current platform.
519
520    On Unix, this means every variable defined in Python's installed Makefile;
521    On Windows it's a much smaller set.
522
523    With arguments, return a list of values that result from looking up
524    each argument in the configuration variable dictionary.
525    """
526    global _CONFIG_VARS
527    if _CONFIG_VARS is None:
528        _CONFIG_VARS = {}
529        # Normalized versions of prefix and exec_prefix are handy to have;
530        # in fact, these are the standard versions used most places in the
531        # Distutils.
532        _CONFIG_VARS['prefix'] = _PREFIX
533        _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
534        _CONFIG_VARS['py_version'] = _PY_VERSION
535        _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
536        _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT
537        _CONFIG_VARS['installed_base'] = _BASE_PREFIX
538        _CONFIG_VARS['base'] = _PREFIX
539        _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX
540        _CONFIG_VARS['platbase'] = _EXEC_PREFIX
541        _CONFIG_VARS['projectbase'] = _PROJECT_BASE
542        try:
543            _CONFIG_VARS['abiflags'] = sys.abiflags
544        except AttributeError:
545            # sys.abiflags may not be defined on all platforms.
546            _CONFIG_VARS['abiflags'] = ''
547
548        if os.name == 'nt':
549            _init_non_posix(_CONFIG_VARS)
550        if os.name == 'posix':
551            _init_posix(_CONFIG_VARS)
552        # For backward compatibility, see issue19555
553        SO = _CONFIG_VARS.get('EXT_SUFFIX')
554        if SO is not None:
555            _CONFIG_VARS['SO'] = SO
556        # Setting 'userbase' is done below the call to the
557        # init function to enable using 'get_config_var' in
558        # the init-function.
559        _CONFIG_VARS['userbase'] = _getuserbase()
560
561        # Always convert srcdir to an absolute path
562        srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)
563        if os.name == 'posix':
564            if _PYTHON_BUILD:
565                # If srcdir is a relative path (typically '.' or '..')
566                # then it should be interpreted relative to the directory
567                # containing Makefile.
568                base = os.path.dirname(get_makefile_filename())
569                srcdir = os.path.join(base, srcdir)
570            else:
571                # srcdir is not meaningful since the installation is
572                # spread about the filesystem.  We choose the
573                # directory containing the Makefile since we know it
574                # exists.
575                srcdir = os.path.dirname(get_makefile_filename())
576        _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir)
577
578        # OS X platforms require special customization to handle
579        # multi-architecture, multi-os-version installers
580        if sys.platform == 'darwin':
581            import _osx_support
582            _osx_support.customize_config_vars(_CONFIG_VARS)
583
584    if args:
585        vals = []
586        for name in args:
587            vals.append(_CONFIG_VARS.get(name))
588        return vals
589    else:
590        return _CONFIG_VARS
591
592
593def get_config_var(name):
594    """Return the value of a single variable using the dictionary returned by
595    'get_config_vars()'.
596
597    Equivalent to get_config_vars().get(name)
598    """
599    if name == 'SO':
600        import warnings
601        warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)
602    return get_config_vars().get(name)
603
604
605def get_platform():
606    """Return a string that identifies the current platform.
607
608    This is used mainly to distinguish platform-specific build directories and
609    platform-specific built distributions.  Typically includes the OS name and
610    version and the architecture (as supplied by 'os.uname()'), although the
611    exact information included depends on the OS; on Linux, the kernel version
612    isn't particularly important.
613
614    Examples of returned values:
615       linux-i586
616       linux-alpha (?)
617       solaris-2.6-sun4u
618
619    Windows will return one of:
620       win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
621       win32 (all others - specifically, sys.platform is returned)
622
623    For other non-POSIX platforms, currently just returns 'sys.platform'.
624
625    """
626    if os.name == 'nt':
627        if 'amd64' in sys.version.lower():
628            return 'win-amd64'
629        if '(arm)' in sys.version.lower():
630            return 'win-arm32'
631        if '(arm64)' in sys.version.lower():
632            return 'win-arm64'
633        return sys.platform
634
635    if os.name != "posix" or not hasattr(os, 'uname'):
636        # XXX what about the architecture? NT is Intel or Alpha
637        return sys.platform
638
639    # Set for cross builds explicitly
640    if "_PYTHON_HOST_PLATFORM" in os.environ:
641        return os.environ["_PYTHON_HOST_PLATFORM"]
642
643    # Try to distinguish various flavours of Unix
644    osname, host, release, version, machine = os.uname()
645
646    # Convert the OS name to lowercase, remove '/' characters, and translate
647    # spaces (for "Power Macintosh")
648    osname = osname.lower().replace('/', '')
649    machine = machine.replace(' ', '_')
650    machine = machine.replace('/', '-')
651
652    if osname[:5] == "linux":
653        # At least on Linux/Intel, 'machine' is the processor --
654        # i386, etc.
655        # XXX what about Alpha, SPARC, etc?
656        return  "%s-%s" % (osname, machine)
657    elif osname[:5] == "sunos":
658        if release[0] >= "5":           # SunOS 5 == Solaris 2
659            osname = "solaris"
660            release = "%d.%s" % (int(release[0]) - 3, release[2:])
661            # We can't use "platform.architecture()[0]" because a
662            # bootstrap problem. We use a dict to get an error
663            # if some suspicious happens.
664            bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
665            machine += ".%s" % bitness[sys.maxsize]
666        # fall through to standard osname-release-machine representation
667    elif osname[:3] == "aix":
668        return "%s-%s.%s" % (osname, version, release)
669    elif osname[:6] == "cygwin":
670        osname = "cygwin"
671        import re
672        rel_re = re.compile(r'[\d.]+')
673        m = rel_re.match(release)
674        if m:
675            release = m.group()
676    elif osname[:6] == "darwin":
677        import _osx_support
678        osname, release, machine = _osx_support.get_platform_osx(
679                                            get_config_vars(),
680                                            osname, release, machine)
681
682    return "%s-%s-%s" % (osname, release, machine)
683
684
685def get_python_version():
686    return _PY_VERSION_SHORT
687
688
689def _print_dict(title, data):
690    for index, (key, value) in enumerate(sorted(data.items())):
691        if index == 0:
692            print('%s: ' % (title))
693        print('\t%s = "%s"' % (key, value))
694
695
696def _main():
697    """Display all information sysconfig detains."""
698    if '--generate-posix-vars' in sys.argv:
699        _generate_posix_vars()
700        return
701    print('Platform: "%s"' % get_platform())
702    print('Python version: "%s"' % get_python_version())
703    print('Current installation scheme: "%s"' % _get_default_scheme())
704    print()
705    _print_dict('Paths', get_paths())
706    print()
707    _print_dict('Variables', get_config_vars())
708
709
710if __name__ == '__main__':
711    _main()
712