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