diff options
| author | Bernát Gábor <bgabor8@bloomberg.net> | 2021-01-10 12:23:14 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-01-10 12:23:14 +0000 |
| commit | 684a632c714b06a76bb6ddc217eaa0df7b40976f (patch) | |
| tree | 1c7dde851d67b9619c606da89e740ace970389a2 /src | |
| parent | 9201a757d0582a8181914dc7a9c863daa136a4b8 (diff) | |
| download | virtualenv-684a632c714b06a76bb6ddc217eaa0df7b40976f.tar.gz | |
Improve discovery on Windows and provide escape hatchet (#2046)
Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
Diffstat (limited to 'src')
| -rw-r--r-- | src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py | 19 | ||||
| -rw-r--r-- | src/virtualenv/discovery/builtin.py | 28 | ||||
| -rw-r--r-- | src/virtualenv/discovery/windows/__init__.py | 5 |
3 files changed, 41 insertions, 11 deletions
diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py b/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py index 1938509..ad73eed 100644 --- a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py +++ b/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py @@ -55,20 +55,27 @@ class CPython3Windows(CPythonWindows, CPython3): def sources(cls, interpreter): for src in super(CPython3Windows, cls).sources(interpreter): yield src - if not cls.venv_37p(interpreter): + if not cls.has_shim(interpreter): for src in cls.include_dll_and_pyd(interpreter): yield src - @staticmethod - def venv_37p(interpreter): - return interpreter.version_info.minor >= 7 + @classmethod + def has_shim(cls, interpreter): + return interpreter.version_info.minor >= 7 and cls.shim(interpreter) is not None + + @classmethod + def shim(cls, interpreter): + shim = Path(interpreter.system_stdlib) / "venv" / "scripts" / "nt" / "python.exe" + if shim.exists(): + return shim + return None @classmethod def host_python(cls, interpreter): - if cls.venv_37p(interpreter): + if cls.has_shim(interpreter): # starting with CPython 3.7 Windows ships with a venvlauncher.exe that avoids the need for dll/pyd copies # it also means the wrapper must be copied to avoid bugs such as https://bugs.python.org/issue42013 - return Path(interpreter.system_stdlib) / "venv" / "scripts" / "nt" / "python.exe" + return cls.shim(interpreter) return super(CPython3Windows, cls).host_python(interpreter) @classmethod diff --git a/src/virtualenv/discovery/builtin.py b/src/virtualenv/discovery/builtin.py index b66ecb1..70ffbce 100644 --- a/src/virtualenv/discovery/builtin.py +++ b/src/virtualenv/discovery/builtin.py @@ -17,6 +17,7 @@ class Builtin(Discover): super(Builtin, self).__init__(options) self.python_spec = options.python if options.python else [sys.executable] self.app_data = options.app_data + self.try_first_with = options.try_first_with @classmethod def add_parser_arguments(cls, parser): @@ -31,10 +32,19 @@ class Builtin(Discover): help="interpreter based on what to create environment (path/identifier) " "- by default use the interpreter where the tool is installed - first found wins", ) + parser.add_argument( + "--try-first-with", + dest="try_first_with", + metavar="py_exe", + type=str, + action="append", + default=[], + help="try first these interpreters before starting the discovery", + ) def run(self): for python_spec in self.python_spec: - result = get_interpreter(python_spec, self.app_data) + result = get_interpreter(python_spec, self.try_first_with, self.app_data) if result is not None: return result return None @@ -47,11 +57,11 @@ class Builtin(Discover): return "{} discover of python_spec={!r}".format(self.__class__.__name__, spec) -def get_interpreter(key, app_data=None): +def get_interpreter(key, try_first_with, app_data=None): spec = PythonSpec.from_string_spec(key) logging.info("find interpreter for spec %r", spec) proposed_paths = set() - for interpreter, impl_must_match in propose_interpreters(spec, app_data): + for interpreter, impl_must_match in propose_interpreters(spec, try_first_with, app_data): key = interpreter.system_executable, impl_must_match if key in proposed_paths: continue @@ -62,7 +72,17 @@ def get_interpreter(key, app_data=None): proposed_paths.add(key) -def propose_interpreters(spec, app_data): +def propose_interpreters(spec, try_first_with, app_data): + # 0. try with first + for py_exe in try_first_with: + path = os.path.abspath(py_exe) + try: + os.lstat(path) # Windows Store Python does not work with os.path.exists, but does for os.lstat + except OSError: + pass + else: + yield PythonInfo.from_exe(os.path.abspath(path), app_data), True + # 1. if it's a path and exists if spec.path is not None: try: diff --git a/src/virtualenv/discovery/windows/__init__.py b/src/virtualenv/discovery/windows/__init__.py index 9063ab8..556ecf2 100644 --- a/src/virtualenv/discovery/windows/__init__.py +++ b/src/virtualenv/discovery/windows/__init__.py @@ -13,8 +13,11 @@ def propose_interpreters(spec, cache_dir): # see if PEP-514 entries are good # start with higher python versions in an effort to use the latest version available + # and prefer PythonCore over conda pythons (as virtualenv is mostly used by non conda tools) existing = list(discover_pythons()) - existing.sort(key=lambda i: tuple(-1 if j is None else j for j in i[1:4]), reverse=True) + existing.sort( + key=lambda i: tuple(-1 if j is None else j for j in i[1:4]) + (1 if i[0] == "PythonCore" else 0,), reverse=True + ) for name, major, minor, arch, exe, _ in existing: # pre-filter |
