From 9ecfa2257d318dbf9013201405b3f62596ea3c06 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Sun, 14 May 2023 13:07:08 -0400 Subject: [PATCH 1/4] Fix pyenv usage for windows and linux. --- src/pythonfinder/environment.py | 48 ++++++++++++++++++++++++++++---- src/pythonfinder/models/path.py | 17 +++++++---- src/pythonfinder/pythonfinder.py | 2 ++ 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/pythonfinder/environment.py b/src/pythonfinder/environment.py index 1eb9312..a28354a 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,13 +17,16 @@ 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")) ) @@ -41,10 +48,41 @@ def is_type_checking(): """ +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 get_shim_paths(): shim_paths = [] if ASDF_INSTALLED: shim_paths.append(os.path.join(ASDF_DATA_DIR, "shims")) - 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] + + +def set_pyenv_paths(): + if PYENV_INSTALLED: + 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/path.py b/src/pythonfinder/models/path.py index 45e8d89..6200adf 100644 --- a/src/pythonfinder/models/path.py +++ b/src/pythonfinder/models/path.py @@ -180,10 +180,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 +245,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 +312,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 +326,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 diff --git a/src/pythonfinder/pythonfinder.py b/src/pythonfinder/pythonfinder.py index 48bfd27..d6b7aee 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_pyenv_paths from .utils import Iterable, version_re @@ -32,6 +33,7 @@ def __eq__(self, other) -> bool: return self.__hash__ == other.__hash__ def create_system_path(self) -> SystemPath: + set_pyenv_paths() return SystemPath.create( path=self.path_prepend, system=self.system, From 97f5923d1d4a0e685d73c4d3d2856292cc65b8e2 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Sun, 14 May 2023 13:12:02 -0400 Subject: [PATCH 2/4] Fix pyenv usage for windows and linux. --- news/137.bugfix.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/137.bugfix.rst diff --git a/news/137.bugfix.rst b/news/137.bugfix.rst new file mode 100644 index 0000000..fdb9665 --- /dev/null +++ b/news/137.bugfix.rst @@ -0,0 +1,2 @@ +Corrected pyenv detection and usage which broke with the release of ``pythonfinder==2.0.0`` + From 803371685d036de6a393cbb28ec70bae22626b3f Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Sun, 14 May 2023 21:36:01 -0400 Subject: [PATCH 3/4] Fix asd usage for windows and linux. --- src/pythonfinder/environment.py | 19 ++++++++++++++----- src/pythonfinder/models/mixins.py | 9 --------- src/pythonfinder/models/path.py | 4 ---- src/pythonfinder/models/python.py | 2 -- src/pythonfinder/pythonfinder.py | 3 ++- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/pythonfinder/environment.py b/src/pythonfinder/environment.py index a28354a..d168faf 100644 --- a/src/pythonfinder/environment.py +++ b/src/pythonfinder/environment.py @@ -17,7 +17,6 @@ def is_type_checking(): return TYPE_CHECKING -ASDF_INSTALLED = bool(os.environ.get("ASDF_DIR")) PYENV_ROOT = os.path.expanduser( os.path.expandvars(os.environ.get("PYENV_ROOT", "~/.pyenv")) ) @@ -30,6 +29,7 @@ def is_type_checking(): 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] @@ -59,11 +59,20 @@ def join_path_for_platform(path, path_parts): raise Exception("Unknown environment") -def get_shim_paths(): - shim_paths = [] +def set_asdf_paths(): if ASDF_INSTALLED: - shim_paths.append(os.path.join(ASDF_DATA_DIR, "shims")) - return [os.path.normpath(os.path.normcase(p)) for p in shim_paths] + 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(): 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 6200adf..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, @@ -523,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 d6b7aee..ab9ea30 100644 --- a/src/pythonfinder/pythonfinder.py +++ b/src/pythonfinder/pythonfinder.py @@ -7,7 +7,7 @@ from .models.common import FinderBaseModel from .models.path import PathEntry, SystemPath from .models.python import PythonVersion -from .environment import set_pyenv_paths +from .environment import set_asdf_paths, set_pyenv_paths from .utils import Iterable, version_re @@ -33,6 +33,7 @@ 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, From 3256756351c0e2552e5ec1d6423ec20d0c0da8fa Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Sun, 14 May 2023 21:36:53 -0400 Subject: [PATCH 4/4] Fix asd usage for windows and linux. --- news/137.bugfix.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/news/137.bugfix.rst b/news/137.bugfix.rst index fdb9665..0bc110c 100644 --- a/news/137.bugfix.rst +++ b/news/137.bugfix.rst @@ -1,2 +1 @@ -Corrected pyenv detection and usage which broke with the release of ``pythonfinder==2.0.0`` - +Corrected ``asdf`` and ``pyenv`` detection and usage which broke with the release of ``pythonfinder==2.0.0``