From aeef98984134178475ccc5ebd58461421efc52b6 Mon Sep 17 00:00:00 2001 From: Ryan Clary <9618975+mrclary@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:25:34 -0800 Subject: [PATCH 1/3] Add condabin, relative to sys.executable and provided pyexec, to paths searched for conda executable. Add extra search paths for is_program_installed. --- spyder/utils/conda.py | 23 ++++++++++++++++++----- spyder/utils/programs.py | 12 ++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/spyder/utils/conda.py b/spyder/utils/conda.py index 3f909d89090..55a35ccf252 100644 --- a/spyder/utils/conda.py +++ b/spyder/utils/conda.py @@ -83,14 +83,17 @@ def get_conda_root_prefix(pyexec=None, quote=False): return root_prefix -def get_conda_activation_script(quote=False): +def get_conda_activation_script(pyexec=None, quote=False): """ Return full path to conda activation script. + `pyexec` is optional python executable, the relative location from which to + attempt to find the activation script. + If `quote` is True, then quotes are added if spaces are found in the path. """ # Use micromamba bundled with Spyder installers or find conda exe - exe = get_spyder_umamba_path() or find_conda() + exe = get_spyder_umamba_path() or find_conda(pyexec) if osp.basename(exe).startswith('micromamba'): # For Micromamba, use the executable @@ -130,14 +133,24 @@ def get_conda_env_path(pyexec, quote=False): return conda_env -def find_conda(): - """Find conda executable.""" +def find_conda(pyexec=None): + """ + Find conda executable. + + `pyexec` is a python executable, the relative location from which to + attempt to locate a conda executable. + """ # First try the environment variables conda = os.environ.get('CONDA_EXE') or os.environ.get('MAMBA_EXE') if conda is None: # Try searching for the executable conda_exec = 'conda.bat' if WINDOWS else 'conda' - conda = find_program(conda_exec) + extra_paths = [ + osp.join(get_conda_root_prefix(_pyexec), 'condabin') + for _pyexec in [sys.executable, pyexec] + ] + conda = find_program(conda_exec, extra_paths) + return conda diff --git a/spyder/utils/programs.py b/spyder/utils/programs.py index 3813473d1cd..cd1a99a73f7 100644 --- a/spyder/utils/programs.py +++ b/spyder/utils/programs.py @@ -68,7 +68,7 @@ def get_temp_dir(suffix=None): return tempdir -def is_program_installed(basename): +def is_program_installed(basename, extra_paths=[]): """ Return program absolute path if installed in PATH. Otherwise, return None. @@ -76,7 +76,7 @@ def is_program_installed(basename): Also searches specific platform dependent paths that are not already in PATH. This permits general use without assuming user profiles are sourced (e.g. .bash_Profile), such as when login shells are not used to - launch Spyder. + launch Spyder. Additionally, extra_paths are searched. On macOS systems, a .app is considered installed if it exists. """ @@ -107,15 +107,15 @@ def is_program_installed(basename): 'Miniconda3', 'Anaconda3', 'Miniconda', 'Anaconda'] conda = [osp.join(*p, 'condabin') for p in itertools.product(a, b)] - req_paths.extend(pyenv + conda) + req_paths.extend(pyenv + conda + extra_paths) - for path in os.environ['PATH'].split(os.pathsep) + req_paths: + for path in set(os.environ['PATH'].split(os.pathsep) + req_paths): abspath = osp.join(path, basename) if osp.isfile(abspath): return abspath -def find_program(basename): +def find_program(basename, extra_paths=[]): """ Find program in PATH and return absolute path @@ -129,7 +129,7 @@ def find_program(basename): if not basename.endswith(extensions): names = [basename + ext for ext in extensions] + [basename] for name in names: - path = is_program_installed(name) + path = is_program_installed(name, extra_paths) if path: return path From e103465d329753e3c24077423038bfe9d8c82121 Mon Sep 17 00:00:00 2001 From: Ryan Clary <9618975+mrclary@users.noreply.github.com> Date: Mon, 4 Mar 2024 09:23:09 -0800 Subject: [PATCH 2/3] Remove possible CONDA_EXE and MAMBA_EXE environment variables and make sure that a conda executable is still found. --- spyder/utils/tests/test_conda.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spyder/utils/tests/test_conda.py b/spyder/utils/tests/test_conda.py index c0c0804b84c..46d2fe6719f 100644 --- a/spyder/utils/tests/test_conda.py +++ b/spyder/utils/tests/test_conda.py @@ -65,8 +65,17 @@ def test_get_conda_root_prefix(): @pytest.mark.skipif(not running_in_ci(), reason="Only meant for CIs") def test_find_conda(): + # Temporarily remove CONDA_EXE and MAMBA_EXE, if present + conda_exe = os.environ.pop('CONDA_EXE', None) + mamba_exe = os.environ.pop('MAMBA_EXE', None) + assert find_conda() + if conda_exe is not None: + os.environ['CONDA_EXE'] = conda_exe + if mamba_exe is not None: + os.environ['MAMBA_EXE'] = mamba_exe + @pytest.mark.skipif(not running_in_ci(), reason="Only meant for CIs") def test_get_list_conda_envs(): From 1ed984c61e546a5feb1a6a6d2989483a67174dd0 Mon Sep 17 00:00:00 2001 From: Ryan Clary <9618975+mrclary@users.noreply.github.com> Date: Mon, 4 Mar 2024 22:39:22 -0800 Subject: [PATCH 3/3] Apply changes from code review --- spyder/utils/tests/test_conda.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spyder/utils/tests/test_conda.py b/spyder/utils/tests/test_conda.py index 46d2fe6719f..ab8b2f7afb2 100644 --- a/spyder/utils/tests/test_conda.py +++ b/spyder/utils/tests/test_conda.py @@ -17,12 +17,12 @@ # Local imports from spyder.config.base import running_in_ci from spyder.config.utils import is_anaconda +from spyder.plugins.ipythonconsole.tests.conftest import get_conda_test_env from spyder.utils.conda import ( add_quotes, find_conda, get_conda_activation_script, get_conda_env_path, get_conda_root_prefix, get_list_conda_envs, get_list_conda_envs_cache, get_spyder_conda_channel) - if not is_anaconda(): pytest.skip("Requires conda to be installed", allow_module_level=True) @@ -65,12 +65,19 @@ def test_get_conda_root_prefix(): @pytest.mark.skipif(not running_in_ci(), reason="Only meant for CIs") def test_find_conda(): + # Standard test + assert find_conda() + + # Test with test environment + pyexec = get_conda_test_env()[1] + # Temporarily remove CONDA_EXE and MAMBA_EXE, if present conda_exe = os.environ.pop('CONDA_EXE', None) mamba_exe = os.environ.pop('MAMBA_EXE', None) - assert find_conda() + assert find_conda(pyexec) + # Restore os.environ if conda_exe is not None: os.environ['CONDA_EXE'] = conda_exe if mamba_exe is not None: