diff options
| author | Bernát Gábor <bgabor8@bloomberg.net> | 2020-01-18 17:07:49 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-01-18 17:07:49 +0000 |
| commit | 8d6af57d76edcf425beab6d53d4c14f1e49f7ca5 (patch) | |
| tree | de400611862464320c6a45a932e27c2bac0c63ea /src/virtualenv | |
| parent | 8f4128879b26921af2ec0f0f3f690ed2324bfb04 (diff) | |
| download | virtualenv-8d6af57d76edcf425beab6d53d4c14f1e49f7ca5.tar.gz | |
CentOs and Fedora support (#1500)
* CentOs support
Instead of hard coding patterns and guessing let's ask the host python
via the sysconfig.
Signed-off-by: Bernat Gabor <bgabor8@bloomberg.net>
* add isolated test
Signed-off-by: Bernat Gabor <bgabor8@bloomberg.net>
* fixes for Fedora
Signed-off-by: Bernat Gabor <bgabor8@bloomberg.net>
Diffstat (limited to 'src/virtualenv')
19 files changed, 172 insertions, 181 deletions
diff --git a/src/virtualenv/activation/python/__init__.py b/src/virtualenv/activation/python/__init__.py index b06af78..8d7e80e 100644 --- a/src/virtualenv/activation/python/__init__.py +++ b/src/virtualenv/activation/python/__init__.py @@ -14,6 +14,6 @@ class PythonActivator(ViaTemplateActivator): def replacements(self, creator, dest_folder): replacements = super(PythonActivator, self).replacements(creator, dest_folder) - site_dump = json.dumps([os.path.relpath(str(i), str(dest_folder)) for i in creator.site_packages], indent=2) + site_dump = json.dumps(list({os.path.relpath(str(i), str(dest_folder)) for i in creator.libs}), indent=2) replacements.update({"__SITE_PACKAGES__": site_dump}) return replacements diff --git a/src/virtualenv/activation/via_template.py b/src/virtualenv/activation/via_template.py index f707897..442776a 100644 --- a/src/virtualenv/activation/via_template.py +++ b/src/virtualenv/activation/via_template.py @@ -31,7 +31,7 @@ class ViaTemplateActivator(Activator): "__VIRTUAL_PROMPT__": "" if self.flag_prompt is None else self.flag_prompt, "__VIRTUAL_ENV__": six.ensure_text(str(creator.dest_dir)), "__VIRTUAL_NAME__": creator.env_name, - "__BIN_NAME__": six.ensure_text(str(creator.bin_name)), + "__BIN_NAME__": six.ensure_text(str(creator.bin_dir.relative_to(creator.dest_dir))), "__PATH_SEP__": os.pathsep, } diff --git a/src/virtualenv/info.py b/src/virtualenv/info.py index 573a97f..fbb7573 100644 --- a/src/virtualenv/info.py +++ b/src/virtualenv/info.py @@ -45,7 +45,7 @@ def is_fs_case_sensitive(): with tempfile.NamedTemporaryFile(prefix="TmP") as tmp_file: _FS_CASE_SENSITIVE = not os.path.exists(tmp_file.name.lower()) logging.debug( - "filesystem under is %r%s case-sensitive", tmp_file.name, "" if _FS_CASE_SENSITIVE else " not" + "filesystem under %r is %scase-sensitive", tmp_file.name, "" if _FS_CASE_SENSITIVE else "not " ) return _FS_CASE_SENSITIVE diff --git a/src/virtualenv/interpreters/create/builtin_way.py b/src/virtualenv/interpreters/create/builtin_way.py index 4134d7b..31ea9e4 100644 --- a/src/virtualenv/interpreters/create/builtin_way.py +++ b/src/virtualenv/interpreters/create/builtin_way.py @@ -13,22 +13,6 @@ class VirtualenvBuiltin(ViaGlobalRefApi): """A creator that does operations itself without delegation""" @property - def bin_name(self): - raise NotImplementedError - - @property - def bin_dir(self): - return self.dest_dir / self.bin_name - - @property - def lib_dir(self): - raise NotImplementedError - - @property - def site_packages(self): - return [self.lib_dir / "site-packages"] - - @property def exe_name(self): raise NotImplementedError diff --git a/src/virtualenv/interpreters/create/cpython/common.py b/src/virtualenv/interpreters/create/cpython/common.py index 490b0ad..ba921b1 100644 --- a/src/virtualenv/interpreters/create/cpython/common.py +++ b/src/virtualenv/interpreters/create/cpython/common.py @@ -24,18 +24,6 @@ class CPython(ViaGlobalRefVirtualenvBuiltin): class CPythonPosix(CPython, PosixSupports): """Create a CPython virtual environment on POSIX platforms""" - @property - def bin_name(self): - return "bin" - - @property - def lib_name(self): - return "lib" - - @property - def lib_base(self): - return Path(self.lib_name) / self.interpreter.python_name - def link_exe(self): host = Path(self.interpreter.system_executable) major, minor = self.interpreter.version_info.major, self.interpreter.version_info.minor @@ -44,18 +32,6 @@ class CPythonPosix(CPython, PosixSupports): @six.add_metaclass(abc.ABCMeta) class CPythonWindows(CPython, WindowsSupports): - @property - def bin_name(self): - return "Scripts" - - @property - def lib_name(self): - return "Lib" - - @property - def lib_base(self): - return Path(self.lib_name) - def link_exe(self): host = Path(self.interpreter.system_executable) return {p: [p.name] for p in (host.parent / n for n in ("python.exe", "pythonw.exe", host.name)) if p.exists()} diff --git a/src/virtualenv/interpreters/create/creator.py b/src/virtualenv/interpreters/create/creator.py index 1185b56..f0adf9e 100644 --- a/src/virtualenv/interpreters/create/creator.py +++ b/src/virtualenv/interpreters/create/creator.py @@ -36,6 +36,55 @@ class Creator(object): self.clear = options.clear self.pyenv_cfg = PyEnvCfg.from_folder(self.dest_dir) + self._stdlib = None + self._system_stdlib = None + self._conf_vars = None + + @property + def bin_dir(self): + return self.script_dir + + @property + def script_dir(self): + return self.dest_dir / Path(self.interpreter.distutils_install["scripts"]) + + @property + def purelib(self): + return self.dest_dir / self.interpreter.distutils_install["purelib"] + + @property + def platlib(self): + return self.dest_dir / self.interpreter.distutils_install["platlib"] + + @property + def libs(self): + return list(OrderedDict(((self.platlib, None), (self.purelib, None))).keys()) + + @property + def stdlib(self): + if self._stdlib is None: + self._stdlib = Path(self.interpreter.sysconfig_path("stdlib", config_var=self._config_vars)) + return self._stdlib + + @property + def system_stdlib(self): + if self._system_stdlib is None: + conf_vars = self._calc_config_vars(self.interpreter.system_prefix) + self._system_stdlib = Path(self.interpreter.sysconfig_path("stdlib", conf_vars)) + return self._system_stdlib + + @property + def _config_vars(self): + if self._conf_vars is None: + self._conf_vars = self._calc_config_vars(six.ensure_text(str(self.dest_dir))) + return self._conf_vars + + def _calc_config_vars(self, to): + return { + k: (to if v.startswith(self.interpreter.prefix) else v) + for k, v in self.interpreter.sysconfig_config_vars.items() + } + def __repr__(self): return six.ensure_str(self.__unicode__()) @@ -154,6 +203,7 @@ class Creator(object): "home": self.interpreter.system_exec_prefix, "include-system-site-packages": "true" if self.enable_system_site_package else "false", "implementation": self.interpreter.implementation, + "version_info": ".".join(str(i) for i in self.interpreter.version_info), "virtualenv": __version__, } diff --git a/src/virtualenv/interpreters/create/debug.py b/src/virtualenv/interpreters/create/debug.py index e2b1585..674d1bb 100644 --- a/src/virtualenv/interpreters/create/debug.py +++ b/src/virtualenv/interpreters/create/debug.py @@ -66,6 +66,14 @@ def run(): except ImportError as exception: # pragma: no cover result["datetime"] = repr(exception) # pragma: no cover + try: + # noinspection PyUnresolvedReferences + import math # site + + result["math"] = repr(math) + except ImportError as exception: # pragma: no cover + result["math"] = repr(exception) # pragma: no cover + # try to print out, this will validate if other core modules are available (json in this case) try: import json diff --git a/src/virtualenv/interpreters/create/pypy/common.py b/src/virtualenv/interpreters/create/pypy/common.py index 1c98064..72dfb21 100644 --- a/src/virtualenv/interpreters/create/pypy/common.py +++ b/src/virtualenv/interpreters/create/pypy/common.py @@ -14,10 +14,6 @@ class PyPy(ViaGlobalRefVirtualenvBuiltin): def supports(cls, interpreter): return interpreter.implementation == "PyPy" and super(PyPy, cls).supports(interpreter) - @property - def site_packages(self): - return [self.dest_dir / "site-packages"] - def link_exe(self): host = Path(self.interpreter.system_executable) return {host: sorted("{}{}".format(name, self.suffix) for name in self.exe_names())} diff --git a/src/virtualenv/interpreters/create/pypy/pypy2.py b/src/virtualenv/interpreters/create/pypy/pypy2.py index fe34cdc..b16b53d 100644 --- a/src/virtualenv/interpreters/create/pypy/pypy2.py +++ b/src/virtualenv/interpreters/create/pypy/pypy2.py @@ -6,7 +6,6 @@ import six from virtualenv.interpreters.create.support import PosixSupports, WindowsSupports from virtualenv.interpreters.create.via_global_ref.python2 import Python2 -from virtualenv.util.path import Path from .common import PyPy @@ -20,21 +19,17 @@ class PyPy2(PyPy, Python2): return "pypy" @property - def lib_name(self): - return "lib-python" - - @property def lib_pypy(self): return self.dest_dir / "lib_pypy" - @property - def lib_base(self): - return Path(self.lib_name) / self.interpreter.version_release_str + def _calc_config_vars(self, to): + base = super(PyPy, self)._calc_config_vars(to) + # for some reason pypy seems to provide the wrong information for implementation_lower, fix it + base["implementation_lower"] = "python" + return base def ensure_directories(self): - dirs = super(PyPy, self).ensure_directories() - dirs.add(self.lib_pypy) - return dirs + return super(PyPy, self).ensure_directories() | {self.lib_pypy} def modules(self): return [ @@ -51,10 +46,6 @@ class PyPy2(PyPy, Python2): class PyPy2Posix(PyPy2, PosixSupports): """PyPy 2 on POSIX""" - @property - def bin_name(self): - return "bin" - def modules(self): return super(PyPy2Posix, self).modules() + ["posixpath"] @@ -66,10 +57,6 @@ class PyPy2Posix(PyPy2, PosixSupports): class Pypy2Windows(PyPy2, WindowsSupports): """PyPy 2 on Windows""" - @property - def bin_name(self): - return "Scripts" - def modules(self): return super(Pypy2Windows, self).modules() + ["ntpath"] diff --git a/src/virtualenv/interpreters/create/pypy/pypy3.py b/src/virtualenv/interpreters/create/pypy/pypy3.py index 6b759cb..724f0fb 100644 --- a/src/virtualenv/interpreters/create/pypy/pypy3.py +++ b/src/virtualenv/interpreters/create/pypy/pypy3.py @@ -5,67 +5,48 @@ import abc import six from virtualenv.interpreters.create.support import PosixSupports, Python3Supports, WindowsSupports -from virtualenv.util.path import Path from .common import PyPy @six.add_metaclass(abc.ABCMeta) class PyPy3(PyPy, Python3Supports): - """""" - @property def exe_base(self): return "pypy3" + @property + def stdlib(self): + """ + PyPy3 seems to respect sysconfig only for the host python... + virtual environments purelib is instead lib/pythonx.y + """ + return self.dest_dir / "lib" / "python{}".format(self.interpreter.version_release_str) / "site-packages" + def exe_names(self): base = super(PyPy3, self).exe_names() base.add("pypy") return base - def ensure_directories(self): - dirs = super(PyPy, self).ensure_directories() - dirs.add(self.lib_dir / "site-packages") - return dirs - class PyPy3Posix(PyPy3, PosixSupports): """PyPy 2 on POSIX""" @property - def bin_name(self): - return "bin" - - @property - def lib_name(self): - return "lib" - - @property - def lib_base(self): - return Path(self.lib_name) / self.interpreter.python_name - - @property def _shared_libs(self): return ["libpypy3-c.so", "libpypy3-c.dylib"] def _shared_lib_to(self): - return super(PyPy3, self)._shared_lib_to() + [self.dest_dir / self.lib_name] + return super(PyPy3, self)._shared_lib_to() + [self.stdlib.parent.parent] class Pypy3Windows(PyPy3, WindowsSupports): """PyPy 2 on Windows""" @property - def bin_name(self): - return "Scripts" - - @property - def lib_name(self): - return "Lib" - - @property - def lib_base(self): - return Path(self.lib_name) + def bin_dir(self): + """PyPy3 needs to fallback to pypy definition""" + return self.dest_dir / "Scripts" @property def _shared_libs(self): diff --git a/src/virtualenv/interpreters/create/venv.py b/src/virtualenv/interpreters/create/venv.py index afb9471..78d4622 100644 --- a/src/virtualenv/interpreters/create/venv.py +++ b/src/virtualenv/interpreters/create/venv.py @@ -13,10 +13,10 @@ from .via_global_ref.api import ViaGlobalRefApi class Venv(ViaGlobalRefApi): def __init__(self, options, interpreter): + self.builtin_way = options.builtin_way super(Venv, self).__init__(options, interpreter) self.can_be_inline = interpreter is CURRENT and interpreter.executable == interpreter.system_executable self._context = None - self.builtin_way = options.builtin_way def _args(self): return super(Venv, self)._args() + ( @@ -33,9 +33,8 @@ class Venv(ViaGlobalRefApi): else: self.create_via_sub_process() # TODO: cleanup activation scripts - if self.builtin_way is not None: - for site_package in self.builtin_way.site_packages: - ensure_dir(site_package) + for lib in self.libs: + ensure_dir(lib) def create_inline(self): from venv import EnvBuilder @@ -66,27 +65,10 @@ class Venv(ViaGlobalRefApi): super(Venv, self).set_pyenv_cfg() self.pyenv_cfg.update(venv_content) - def _proxy_builtin_way(self, key): - if self.builtin_way is None: - return None - return getattr(self.builtin_way, key) - - @property - def exe(self): - return self._proxy_builtin_way("exe") - - @property - def site_packages(self): - return self._proxy_builtin_way("site_packages") - - @property - def bin_dir(self): - return self._proxy_builtin_way("bin_dir") - - @property - def bin_name(self): - return self._proxy_builtin_way("bin_name") - - @property - def lib_dir(self): - return self._proxy_builtin_way("lib_dir") + def __getattribute__(self, item): + builtin = object.__getattribute__(self, "builtin_way") + if builtin is not None and hasattr(builtin, item): + element = getattr(builtin, item) + if not callable(element): + return element + return object.__getattribute__(self, item) diff --git a/src/virtualenv/interpreters/create/via_global_ref/python2.py b/src/virtualenv/interpreters/create/via_global_ref/python2.py index 4ff6e84..9c7222a 100644 --- a/src/virtualenv/interpreters/create/via_global_ref/python2.py +++ b/src/virtualenv/interpreters/create/via_global_ref/python2.py @@ -27,16 +27,16 @@ class Python2(ViaGlobalRefVirtualenvBuiltin, Python2Supports): self.add_module(module) # 2. install a patched site-package, the default Python 2 site.py is not smart enough to understand pyvenv.cfg, # so we inject a small shim that can do this - site_py = self.lib_dir / "site.py" - relative_site_packages = [ - os.path.relpath(six.ensure_text(str(s)), six.ensure_text(str(site_py))) for s in self.site_packages - ] + site_py = self.stdlib / "site.py" custom_site = get_custom_site() if IS_ZIPAPP: custom_site_text = read_from_zipapp(custom_site) else: custom_site_text = custom_site.read_text() - site_py.write_text(custom_site_text.replace("___EXPECTED_SITE_PACKAGES___", json.dumps(relative_site_packages))) + expected = json.dumps( + [os.path.relpath(six.ensure_text(str(i)), six.ensure_text(str(site_py))) for i in self.libs] + ) + site_py.write_text(custom_site_text.replace("___EXPECTED_SITE_PACKAGES___", expected)) @abc.abstractmethod def modules(self): @@ -48,10 +48,10 @@ class Python2(ViaGlobalRefVirtualenvBuiltin, Python2Supports): def add_module(self, req): for ext in ["py", "pyc"]: file_path = "{}.{}".format(req, ext) - self.copier(self.system_stdlib / file_path, self.lib_dir / file_path) + self.copier(self.system_stdlib / file_path, self.stdlib / file_path) def add_folder(self, folder): - self.copier(self.system_stdlib / folder, self.lib_dir / folder) + self.copier(self.system_stdlib / folder, self.stdlib / folder) def get_custom_site(): diff --git a/src/virtualenv/interpreters/create/via_global_ref/via_global_self_do.py b/src/virtualenv/interpreters/create/via_global_ref/via_global_self_do.py index 7e259f3..5844a92 100644 --- a/src/virtualenv/interpreters/create/via_global_ref/via_global_self_do.py +++ b/src/virtualenv/interpreters/create/via_global_ref/via_global_self_do.py @@ -9,7 +9,7 @@ from six import add_metaclass from virtualenv.info import is_fs_case_sensitive from virtualenv.interpreters.create.builtin_way import VirtualenvBuiltin -from virtualenv.util.path import Path, copy, ensure_dir, make_exe, symlink +from virtualenv.util.path import copy, ensure_dir, make_exe, symlink @add_metaclass(ABCMeta) @@ -42,9 +42,7 @@ class ViaGlobalRefVirtualenvBuiltin(VirtualenvBuiltin): self.pyenv_cfg["base-executable"] = self.interpreter.system_executable def ensure_directories(self): - dirs = {self.dest_dir, self.bin_dir, self.lib_dir} - dirs.update(self.site_packages) - return dirs + return {self.dest_dir, self.bin_dir, self.script_dir, self.stdlib} | set(self.libs) def setup_python(self): aliases = method = self.add_exe_method() @@ -79,19 +77,3 @@ class ViaGlobalRefVirtualenvBuiltin(VirtualenvBuiltin): def symlink_exe(src, dest): symlink(src, dest) make_exe(dest) - - @property - def lib_base(self): - raise NotImplementedError - - @property - def system_stdlib(self): - return Path(self.interpreter.system_prefix) / self.lib_base - - @property - def lib_dir(self): - return self.dest_dir / self.lib_base - - @abc.abstractmethod - def lib_name(self): - raise NotImplementedError diff --git a/src/virtualenv/interpreters/discovery/py_info.py b/src/virtualenv/interpreters/discovery/py_info.py index 9feecb4..0aebece 100644 --- a/src/virtualenv/interpreters/discovery/py_info.py +++ b/src/virtualenv/interpreters/discovery/py_info.py @@ -10,8 +10,12 @@ import logging import os import pipes import platform +import re import sys +import sysconfig from collections import OrderedDict, namedtuple +from distutils.command.install import SCHEME_KEYS +from distutils.dist import Distribution VersionInfo = namedtuple("VersionInfo", ["major", "minor", "micro", "releaselevel", "serial"]) @@ -21,36 +25,41 @@ def _get_path_extensions(): EXTENSIONS = _get_path_extensions() +_CONF_VAR_RE = re.compile(r"\{\w+\}") class PythonInfo(object): """Contains information for a Python interpreter""" def __init__(self): + def u(v): + return v.decode("utf-8") if isinstance(v, bytes) else v + # qualifies the python - self.platform = sys.platform - self.implementation = platform.python_implementation() - self.pypy_version_info = tuple(sys.pypy_version_info) if self.implementation == "PyPy" else None + self.platform = u(sys.platform) + self.implementation = u(platform.python_implementation()) + if self.implementation == "PyPy": + self.pypy_version_info = tuple(u(i) for i in sys.pypy_version_info) # this is a tuple in earlier, struct later, unify to our own named tuple - self.version_info = VersionInfo(*list(sys.version_info)) + self.version_info = VersionInfo(*list(u(i) for i in sys.version_info)) self.architecture = 64 if sys.maxsize > 2 ** 32 else 32 - self.executable = sys.executable # executable we were called with - self.original_executable = self.executable - self.base_executable = getattr(sys, "_base_executable", None) # some platforms may set this + self.executable = u(sys.executable) # executable we were called with + self.original_executable = u(self.executable) + self.base_executable = u(getattr(sys, "_base_executable", None)) # some platforms may set this - self.version = sys.version - self.os = os.name + self.version = u(sys.version) + self.os = u(os.name) # information about the prefix - determines python home - self.prefix = getattr(sys, "prefix", None) # prefix we think - self.base_prefix = getattr(sys, "base_prefix", None) # venv - self.real_prefix = getattr(sys, "real_prefix", None) # old virtualenv + self.prefix = u(getattr(sys, "prefix", None)) # prefix we think + self.base_prefix = u(getattr(sys, "base_prefix", None)) # venv + self.real_prefix = u(getattr(sys, "real_prefix", None)) # old virtualenv # information about the exec prefix - dynamic stdlib modules - self.base_exec_prefix = getattr(sys, "base_exec_prefix", None) - self.exec_prefix = getattr(sys, "exec_prefix", None) + self.base_exec_prefix = u(getattr(sys, "base_exec_prefix", None)) + self.exec_prefix = u(getattr(sys, "exec_prefix", None)) try: __import__("venv") @@ -58,9 +67,28 @@ class PythonInfo(object): except ImportError: has = False self.has_venv = has - self.path = sys.path - self.file_system_encoding = sys.getfilesystemencoding() - self.stdout_encoding = getattr(sys.stdout, "encoding", None) + self.path = [u(i) for i in sys.path] + self.file_system_encoding = u(sys.getfilesystemencoding()) + self.stdout_encoding = u(getattr(sys.stdout, "encoding", None)) + + self.sysconfig_paths = {u(i): u(sysconfig.get_path(i, expand=False)) for i in sysconfig.get_path_names()} + config_var_keys = set() + for element in self.sysconfig_paths.values(): + for k in _CONF_VAR_RE.findall(element): + config_var_keys.add(u(k[1:-1])) + self.sysconfig_config_vars = {u(i): u(sysconfig.get_config_var(i)) for i in config_var_keys} + + self.distutils_install = {u(k): u(v) for k, v in self._distutils_install().items()} + + def _distutils_install(self): + # follow https://github.com/pypa/pip/blob/master/src/pip/_internal/locations.py#L95 + d = Distribution({"script_args": "--no-user-cfg"}) + d.parse_config_files() + i = d.get_command_obj("install", create=True) + i.prefix = "a" + i.finalize_options() + result = {key: (getattr(i, "install_{}".format(key))[1:]).lstrip(os.sep) for key in SCHEME_KEYS} + return result @property def version_str(self): @@ -132,8 +160,7 @@ class PythonInfo(object): data = json.loads(payload) data["version_info"] = VersionInfo(**data["version_info"]) # restore this to a named tuple structure result = cls() - for var in vars(result): - setattr(result, var, data[var]) + result.__dict__ = {k: v for k, v in data.items()} return result @property @@ -249,7 +276,7 @@ class PythonInfo(object): cmd = cls._get_exe_cmd(exe) # noinspection DuplicatedCode # this is duplicated here because this file is executed on its own, so cannot be refactored otherwise - logging.debug("get interpreter info via cmd: %s", Cmd(cmd)) + logging.debug(u"get interpreter info via cmd: %s", Cmd(cmd)) try: process = Popen( cmd, universal_newlines=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE @@ -307,6 +334,16 @@ class PythonInfo(object): return False return True + def sysconfig_path(self, key, config_var=None, sep=os.sep): + pattern = self.sysconfig_paths[key] + if config_var is None: + config_var = self.sysconfig_config_vars + else: + base = {k: v for k, v in self.sysconfig_config_vars.items()} + base.update(config_var) + config_var = base + return pattern.format(**config_var).replace(u"/", sep) + class Cmd(object): def __init__(self, cmd, env=None): @@ -314,9 +351,12 @@ class Cmd(object): self.env = env def __repr__(self): - cmd_repr = " ".join(pipes.quote(c) for c in self.cmd) + def e(v): + return v.decode("utf-8") if isinstance(v, bytes) else v + + cmd_repr = e(" ").join(pipes.quote(e(c)) for c in self.cmd) if self.env is not None: - cmd_repr += " env of {!r}".format(self.env) + cmd_repr += e(" env of {!r}").format(self.env) return cmd_repr diff --git a/src/virtualenv/pyenv_cfg.py b/src/virtualenv/pyenv_cfg.py index 05daa5a..218c759 100644 --- a/src/virtualenv/pyenv_cfg.py +++ b/src/virtualenv/pyenv_cfg.py @@ -54,3 +54,6 @@ class PyEnvCfg(object): def update(self, other): self.content.update(other) return self + + def __repr__(self): + return "{}(path={})".format(self.__class__.__name__, self.path) diff --git a/src/virtualenv/seed/via_app_data/pip_install/base.py b/src/virtualenv/seed/via_app_data/pip_install/base.py index ba65e9a..7082cf6 100644 --- a/src/virtualenv/seed/via_app_data/pip_install/base.py +++ b/src/virtualenv/seed/via_app_data/pip_install/base.py @@ -34,9 +34,8 @@ class PipInstall(object): def install(self): self._extracted = True # sync image - site_package = self._creator.site_packages[0] for filename in self._image_dir.iterdir(): - into = site_package / filename.name + into = self._creator.purelib / filename.name logging.debug("%s %s from %s", self.__class__.__name__, into, filename) if into.exists(): if into.is_dir() and not into.is_symlink(): @@ -46,9 +45,9 @@ class PipInstall(object): self._sync(filename, into) # generate console executables consoles = set() - bin_dir = self._creator.bin_dir + script_dir = self._creator.script_dir for name, module in self._console_scripts.items(): - consoles.update(self._create_console_entry_point(name, module, bin_dir)) + consoles.update(self._create_console_entry_point(name, module, script_dir)) logging.debug("generated console scripts %s", " ".join(i.name for i in consoles)) def build_image(self): @@ -83,7 +82,7 @@ class PipInstall(object): try: to_folder = Path(folder) rel = os.path.relpath( - six.ensure_text(str(self._creator.bin_dir)), six.ensure_text(str(self._creator.site_packages[0])) + six.ensure_text(str(self._creator.script_dir)), six.ensure_text(str(self._creator.purelib)) ) for name, module in self._console_scripts.items(): new_files.update( diff --git a/src/virtualenv/util/path/_permission.py b/src/virtualenv/util/path/_permission.py index 1356b6d..85f93b8 100644 --- a/src/virtualenv/util/path/_permission.py +++ b/src/virtualenv/util/path/_permission.py @@ -13,7 +13,7 @@ def make_exe(filename): mode |= level filename.chmod(mode) break - except PermissionError: + except OSError: continue diff --git a/src/virtualenv/util/path/_sync.py b/src/virtualenv/util/path/_sync.py index 860aee1..4c5aa86 100644 --- a/src/virtualenv/util/path/_sync.py +++ b/src/virtualenv/util/path/_sync.py @@ -23,6 +23,10 @@ def symlink_or_copy(do_copy, src, dst, relative_symlinks_ok=False): """ Try symlinking a target, and if that fails, fall back to copying. """ + if not src.exists(): + raise RuntimeError("source {} does not exists".format(src)) + if src == dst: + raise RuntimeError("source {} is same as destination ".format(src)) def norm(val): if IS_PYPY and six.PY3: diff --git a/src/virtualenv/util/subprocess/_win_subprocess.py b/src/virtualenv/util/subprocess/_win_subprocess.py index e8fdaf0..f30344d 100644 --- a/src/virtualenv/util/subprocess/_win_subprocess.py +++ b/src/virtualenv/util/subprocess/_win_subprocess.py @@ -5,7 +5,6 @@ import ctypes import os import subprocess -import sys from ctypes import Structure, WinError, byref, c_char_p, c_void_p, c_wchar, c_wchar_p, sizeof, windll from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPVOID, LPWSTR, WORD |
