diff options
-rw-r--r-- | setuptools/_distutils/command/install.py | 118 | ||||
-rw-r--r-- | setuptools/_distutils/tests/test_install.py | 2 | ||||
-rw-r--r-- | setuptools/_distutils/util.py | 39 |
3 files changed, 101 insertions, 58 deletions
diff --git a/setuptools/_distutils/command/install.py b/setuptools/_distutils/command/install.py index e98f0491..c756b6db 100644 --- a/setuptools/_distutils/command/install.py +++ b/setuptools/_distutils/command/install.py @@ -4,6 +4,9 @@ Implements the Distutils 'install' command.""" import sys import os +import contextlib +import sysconfig +import itertools from distutils import log from distutils.core import Command @@ -20,62 +23,62 @@ from site import USER_SITE HAS_USER_SITE = True WINDOWS_SCHEME = { - 'purelib': '$base/Lib/site-packages', - 'platlib': '$base/Lib/site-packages', - 'headers': '$base/Include/$dist_name', - 'scripts': '$base/Scripts', - 'data' : '$base', + 'purelib': '{base}/Lib/site-packages', + 'platlib': '{base}/Lib/site-packages', + 'headers': '{base}/Include/{dist_name}', + 'scripts': '{base}/Scripts', + 'data' : '{base}', } INSTALL_SCHEMES = { - 'unix_prefix': { - 'purelib': '$base/lib/$implementation_lower$py_version_short/site-packages', - 'platlib': '$platbase/$platlibdir/$implementation_lower$py_version_short/site-packages', - 'headers': '$base/include/$implementation_lower$py_version_short$abiflags/$dist_name', - 'scripts': '$base/bin', - 'data' : '$base', + 'posix_prefix': { + 'purelib': '{base}/lib/{implementation_lower}{py_version_short}/site-packages', + 'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}/site-packages', + 'headers': '{base}/include/{implementation_lower}{py_version_short}{abiflags}/{dist_name}', + 'scripts': '{base}/bin', + 'data' : '{base}', }, - 'unix_home': { - 'purelib': '$base/lib/$implementation_lower', - 'platlib': '$base/$platlibdir/$implementation_lower', - 'headers': '$base/include/$implementation_lower/$dist_name', - 'scripts': '$base/bin', - 'data' : '$base', + 'posix_home': { + 'purelib': '{base}/lib/{implementation_lower}', + 'platlib': '{base}/{platlibdir}/{implementation_lower}', + 'headers': '{base}/include/{implementation_lower}/{dist_name}', + 'scripts': '{base}/bin', + 'data' : '{base}', }, 'nt': WINDOWS_SCHEME, 'pypy': { - 'purelib': '$base/site-packages', - 'platlib': '$base/site-packages', - 'headers': '$base/include/$dist_name', - 'scripts': '$base/bin', - 'data' : '$base', + 'purelib': '{base}/site-packages', + 'platlib': '{base}/site-packages', + 'headers': '{base}/include/{dist_name}', + 'scripts': '{base}/bin', + 'data' : '{base}', }, 'pypy_nt': { - 'purelib': '$base/site-packages', - 'platlib': '$base/site-packages', - 'headers': '$base/include/$dist_name', - 'scripts': '$base/Scripts', - 'data' : '$base', + 'purelib': '{base}/site-packages', + 'platlib': '{base}/site-packages', + 'headers': '{base}/include/{dist_name}', + 'scripts': '{base}/Scripts', + 'data' : '{base}', }, } # user site schemes if HAS_USER_SITE: INSTALL_SCHEMES['nt_user'] = { - 'purelib': '$usersite', - 'platlib': '$usersite', - 'headers': '$userbase/$implementation$py_version_nodot/Include/$dist_name', - 'scripts': '$userbase/$implementation$py_version_nodot/Scripts', - 'data' : '$userbase', + 'purelib': '{usersite}', + 'platlib': '{usersite}', + 'headers': '{userbase}/{implementation}{py_version_nodot}/Include/{dist_name}', + 'scripts': '{userbase}/{implementation}{py_version_nodot}/Scripts', + 'data' : '{userbase}', } - INSTALL_SCHEMES['unix_user'] = { - 'purelib': '$usersite', - 'platlib': '$usersite', + INSTALL_SCHEMES['posix_user'] = { + 'purelib': '{usersite}', + 'platlib': '{usersite}', 'headers': - '$userbase/include/$implementation_lower$py_version_short$abiflags/$dist_name', - 'scripts': '$userbase/bin', - 'data' : '$userbase', + '{userbase}/include/{implementation_lower}{py_version_short}{abiflags}/{dist_name}', + 'scripts': '{userbase}/bin', + 'data' : '{userbase}', } # The keys to an installation scheme; if any new types of files are to be @@ -83,6 +86,31 @@ if HAS_USER_SITE: # and to SCHEME_KEYS here. SCHEME_KEYS = ('purelib', 'platlib', 'headers', 'scripts', 'data') + +def _load_sysconfig_schemes(): + with contextlib.suppress(AttributeError): + return { + scheme: sysconfig.get_paths(scheme, expand=False) + for scheme in sysconfig.get_scheme_names() + } + + +def _load_schemes(): + """ + Extend default schemes with schemes from sysconfig. + """ + + sysconfig_schemes = _load_sysconfig_schemes() or {} + + return { + scheme: { + **INSTALL_SCHEMES.get(scheme, {}), + **sysconfig_schemes.get(scheme, {}), + } + for scheme in set(itertools.chain(INSTALL_SCHEMES, sysconfig_schemes)) + } + + def _get_implementation(): if hasattr(sys, 'pypy_version_info'): return 'PyPy' @@ -284,7 +312,7 @@ class install(Command): # input a heady brew of prefix, exec_prefix, home, install_base, # install_platbase, user-supplied versions of # install_{purelib,platlib,lib,scripts,data,...}, and the - # INSTALL_SCHEME dictionary above. Phew! + # install schemes. Phew! self.dump_dirs("pre-finalize_{unix,other}") @@ -335,6 +363,8 @@ class install(Command): # everything else. self.config_vars['base'] = self.install_base self.config_vars['platbase'] = self.install_platbase + self.config_vars['installed_base'] = ( + sysconfig.get_config_vars()['installed_base']) if DEBUG: from pprint import pprint @@ -431,10 +461,10 @@ class install(Command): raise DistutilsPlatformError( "User base directory is not specified") self.install_base = self.install_platbase = self.install_userbase - self.select_scheme("unix_user") + self.select_scheme("posix_user") elif self.home is not None: self.install_base = self.install_platbase = self.home - self.select_scheme("unix_home") + self.select_scheme("posix_home") else: if self.prefix is None: if self.exec_prefix is not None: @@ -450,7 +480,7 @@ class install(Command): self.install_base = self.prefix self.install_platbase = self.exec_prefix - self.select_scheme("unix_prefix") + self.select_scheme("posix_prefix") def finalize_other(self): """Finalizes options for non-posix platforms""" @@ -462,7 +492,7 @@ class install(Command): self.select_scheme(os.name + "_user") elif self.home is not None: self.install_base = self.install_platbase = self.home - self.select_scheme("unix_home") + self.select_scheme("posix_home") else: if self.prefix is None: self.prefix = os.path.normpath(sys.prefix) @@ -484,7 +514,7 @@ class install(Command): name = 'pypy_nt' else: name = 'pypy' - scheme = INSTALL_SCHEMES[name] + scheme = _load_schemes()[name] for key in SCHEME_KEYS: attrname = 'install_' + key if getattr(self, attrname) is None: diff --git a/setuptools/_distutils/tests/test_install.py b/setuptools/_distutils/tests/test_install.py index eb684a09..cce973dc 100644 --- a/setuptools/_distutils/tests/test_install.py +++ b/setuptools/_distutils/tests/test_install.py @@ -94,7 +94,7 @@ class InstallTestCase(support.TempdirManager, self.addCleanup(cleanup) - for key in ('nt_user', 'unix_user'): + for key in ('nt_user', 'posix_user'): self.assertIn(key, INSTALL_SCHEMES) dist = Distribution({'name': 'xx'}) diff --git a/setuptools/_distutils/util.py b/setuptools/_distutils/util.py index afc23c4e..ac6d446d 100644 --- a/setuptools/_distutils/util.py +++ b/setuptools/_distutils/util.py @@ -242,30 +242,43 @@ def check_environ (): def subst_vars (s, local_vars): - """Perform shell/Perl-style variable substitution on 'string'. Every - occurrence of '$' followed by a name is considered a variable, and - variable is substituted by the value found in the 'local_vars' - dictionary, or in 'os.environ' if it's not in 'local_vars'. + """ + Perform variable substitution on 'string'. + Variables are indicated by format-style braces ("{var}"). + Variable is substituted by the value found in the 'local_vars' + dictionary or in 'os.environ' if it's not in 'local_vars'. 'os.environ' is first checked/augmented to guarantee that it contains certain values: see 'check_environ()'. Raise ValueError for any variables not found in either 'local_vars' or 'os.environ'. """ check_environ() - def _subst (match, local_vars=local_vars): - var_name = match.group(1) - if var_name in local_vars: - return str(local_vars[var_name]) - else: - return os.environ[var_name] - + lookup = dict(os.environ) + lookup.update((name, str(value)) for name, value in local_vars.items()) try: - return re.sub(r'\$([a-zA-Z_][a-zA-Z_0-9]*)', _subst, s) + return _subst_compat(s).format_map(lookup) except KeyError as var: - raise ValueError("invalid variable '$%s'" % var) + raise ValueError(f"invalid variable {var}") # subst_vars () +def _subst_compat(s): + """ + Replace shell/Perl-style variable substitution with + format-style. For compatibility. + """ + def _subst(match): + return f'{{{match.group(1)}}}' + repl = re.sub(r'\$([a-zA-Z_][a-zA-Z_0-9]*)', _subst, s) + if repl != s: + import warnings + warnings.warn( + "shell/Perl-style substitions are deprecated", + DeprecationWarning, + ) + return repl + + def grok_environment_error (exc, prefix="error: "): # Function kept for backward compatibility. # Used to try clever things with EnvironmentErrors, |