diff --git a/news/137.bugfix.rst b/news/137.bugfix.rst new file mode 100644 index 0000000..0bc110c --- /dev/null +++ b/news/137.bugfix.rst @@ -0,0 +1 @@ +Corrected ``asdf`` and ``pyenv`` detection and usage which broke with the release of ``pythonfinder==2.0.0`` diff --git a/src/pythonfinder/environment.py b/src/pythonfinder/environment.py index 1eb9312..d168faf 100644 --- a/src/pythonfinder/environment.py +++ b/src/pythonfinder/environment.py @@ -3,6 +3,10 @@ import os import platform import sys +import posixpath +import ntpath +import re +import shutil def is_type_checking(): @@ -13,16 +17,19 @@ def is_type_checking(): return TYPE_CHECKING -PYENV_INSTALLED = bool(os.environ.get("PYENV_SHELL")) or bool( - os.environ.get("PYENV_ROOT") -) -ASDF_INSTALLED = bool(os.environ.get("ASDF_DIR")) PYENV_ROOT = os.path.expanduser( os.path.expandvars(os.environ.get("PYENV_ROOT", "~/.pyenv")) ) +# Check if the path is in Unix-style (Git Bash) +if PYENV_ROOT.startswith('/') and os.name == 'nt': + # Convert to Windows-style path + drive, tail = re.match(r"^/([a-zA-Z])/(.*)", PYENV_ROOT).groups() + PYENV_ROOT = drive.upper() + ":\\" + tail.replace('/', '\\') +PYENV_INSTALLED = shutil.which("pyenv") != None ASDF_DATA_DIR = os.path.expanduser( os.path.expandvars(os.environ.get("ASDF_DATA_DIR", "~/.asdf")) ) +ASDF_INSTALLED = shutil.which("asdf") != None IS_64BIT_OS = None SYSTEM_ARCH = platform.architecture()[0] @@ -41,10 +48,50 @@ def is_type_checking(): """ -def get_shim_paths(): - shim_paths = [] +def join_path_for_platform(path, path_parts): + # If we're on Unix or Unix-like system + if os.name == 'posix' or sys.platform == 'linux': + return posixpath.join(path, *path_parts) + # If we're on Windows + elif os.name == 'nt' or sys.platform == 'win32': + return ntpath.join(path, *path_parts) + else: + raise Exception("Unknown environment") + + +def set_asdf_paths(): if ASDF_INSTALLED: - shim_paths.append(os.path.join(ASDF_DATA_DIR, "shims")) + python_versions = join_path_for_platform(ASDF_DATA_DIR, ["installs", "python"]) + try: + # Get a list of all files and directories in the given path + all_files_and_dirs = os.listdir(python_versions) + # Filter out files and keep only directories + for name in all_files_and_dirs: + if os.path.isdir(os.path.join(python_versions, name)): + asdf_path = os.path.join(python_versions, name) + asdf_path = os.path.join(asdf_path, "bin") + os.environ['PATH'] = asdf_path + os.pathsep + os.environ['PATH'] + except FileNotFoundError: + pass + + +def set_pyenv_paths(): if PYENV_INSTALLED: - shim_paths.append(os.path.join(PYENV_ROOT, "shims")) - return [os.path.normpath(os.path.normcase(p)) for p in shim_paths] + is_windows = False + if os.name == "nt": + python_versions = join_path_for_platform(PYENV_ROOT, ["pyenv-win", "versions"]) + is_windows = True + else: + python_versions = join_path_for_platform(PYENV_ROOT, ["versions"]) + try: + # Get a list of all files and directories in the given path + all_files_and_dirs = os.listdir(python_versions) + # Filter out files and keep only directories + for name in all_files_and_dirs: + if os.path.isdir(os.path.join(python_versions, name)): + pyenv_path = os.path.join(python_versions, name) + if not is_windows: + pyenv_path = os.path.join(pyenv_path, "bin") + os.environ['PATH'] = pyenv_path + os.pathsep + os.environ['PATH'] + except FileNotFoundError: + pass diff --git a/src/pythonfinder/models/mixins.py b/src/pythonfinder/models/mixins.py index d92f768..fb252b4 100644 --- a/src/pythonfinder/models/mixins.py +++ b/src/pythonfinder/models/mixins.py @@ -14,16 +14,13 @@ from pydantic import BaseModel, Field, validator -from ..environment import get_shim_paths from ..exceptions import InvalidPythonVersion from ..utils import ( KNOWN_EXTS, ensure_path, expand_paths, filter_pythons, - is_in_path, looks_like_python, - normalize_path, path_is_known_executable, ) @@ -317,7 +314,6 @@ def _filter_children(self) -> Iterator[Path]: return children def _gen_children(self) -> Iterator: - shim_paths = get_shim_paths() pass_name = self.name != self.path.name pass_args = {"is_root": False, "only_python": self.only_python} if pass_name: @@ -330,8 +326,6 @@ def _gen_children(self) -> Iterator: yield (self.path.as_posix(), self) elif self.is_root: for child in self._filter_children(): - if any(is_in_path(str(child), shim) for shim in shim_paths): - continue if self.only_python: try: entry = PathEntry.create(path=child, **pass_args) @@ -372,7 +366,6 @@ def create( :param str name: Name of the python version, e.g. ``anaconda3-5.3.0`` :return: A new instance of the class. """ - target = ensure_path(path) guessed_name = False if not name: @@ -393,8 +386,6 @@ def create( if not guessed_name: child_creation_args["name"] = _new.name for pth, python in pythons.items(): - if any(shim in normalize_path(str(pth)) for shim in get_shim_paths()): - continue pth = ensure_path(pth) children[pth.as_posix()] = PathEntry( py_version=python, path=pth, **child_creation_args diff --git a/src/pythonfinder/models/path.py b/src/pythonfinder/models/path.py index 45e8d89..0b35af8 100644 --- a/src/pythonfinder/models/path.py +++ b/src/pythonfinder/models/path.py @@ -27,7 +27,6 @@ ASDF_INSTALLED, PYENV_INSTALLED, PYENV_ROOT, - get_shim_paths, ) from ..utils import ( dedup, @@ -180,10 +179,6 @@ def _run_setup(self) -> SystemPath: path_instances = [ ensure_path(p.strip('"')) for p in path_order - if not any( - is_in_path(normalize_path(str(p)), normalize_path(shim)) - for shim in get_shim_paths() - ) ] self.paths.update( { @@ -249,6 +244,16 @@ def _slice_in_paths(self, start_idx, paths) -> SystemPath: self.path_order = path_order return self + def _remove_shims(self): + path_copy = [p for p in self.path_order[:]] + new_order = [] + for current_path in path_copy: + if not current_path.endswith("shims"): + normalized = normalize_path(current_path) + new_order.append(normalized) + new_order = [ensure_path(p).as_posix() for p in new_order] + self.path_order = new_order + def _remove_path(self, path) -> SystemPath: path_copy = [p for p in reversed(self.path_order[:])] new_order = [] @@ -306,7 +311,6 @@ def _setup_pyenv(self) -> SystemPath: version_glob_path="versions/*", ignore_unsupported=self.ignore_unsupported, ) - pyenv_index = None try: pyenv_index = self._get_last_instance(PYENV_ROOT) except ValueError: @@ -321,7 +325,7 @@ def _setup_pyenv(self) -> SystemPath: self.paths[pyenv_finder.root] = pyenv_finder self.paths.update(pyenv_finder.roots) self.pyenv_finder = pyenv_finder - self._remove_path(os.path.join(PYENV_ROOT, "shims")) + self._remove_shims() self._register_finder("pyenv", pyenv_finder) return self @@ -518,9 +522,6 @@ def create( } ) paths = [path, *paths] - paths = [ - p for p in paths if not any(is_in_path(p, shim) for shim in get_shim_paths()) - ] _path_objects = [ensure_path(p.strip('"')) for p in paths] path_entries.update( { diff --git a/src/pythonfinder/models/python.py b/src/pythonfinder/models/python.py index 8ed796f..c5e0345 100644 --- a/src/pythonfinder/models/python.py +++ b/src/pythonfinder/models/python.py @@ -53,8 +53,6 @@ class PythonFinder(PathEntry): roots: Dict = Field(default_factory=lambda: defaultdict()) #: List of paths discovered during search paths: List = Field(default_factory=lambda: list()) - #: shim directory - shim_dir: str = "shims" #: Versions discovered in the specified paths _versions: Dict = Field(default_factory=lambda: defaultdict()) pythons_ref: Dict = Field(default_factory=lambda: defaultdict()) diff --git a/src/pythonfinder/pythonfinder.py b/src/pythonfinder/pythonfinder.py index 48bfd27..ab9ea30 100644 --- a/src/pythonfinder/pythonfinder.py +++ b/src/pythonfinder/pythonfinder.py @@ -7,6 +7,7 @@ from .models.common import FinderBaseModel from .models.path import PathEntry, SystemPath from .models.python import PythonVersion +from .environment import set_asdf_paths, set_pyenv_paths from .utils import Iterable, version_re @@ -32,6 +33,8 @@ def __eq__(self, other) -> bool: return self.__hash__ == other.__hash__ def create_system_path(self) -> SystemPath: + set_asdf_paths() + set_pyenv_paths() return SystemPath.create( path=self.path_prepend, system=self.system,