Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-findpython for openSUSE:Factory checked in at 2023-12-11 21:51:13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-findpython (Old) and /work/SRC/openSUSE:Factory/.python-findpython.new.25432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-findpython" Mon Dec 11 21:51:13 2023 rev:8 rq:1132417 version:0.4.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-findpython/python-findpython.changes 2023-06-16 16:56:05.918151457 +0200 +++ /work/SRC/openSUSE:Factory/.python-findpython.new.25432/python-findpython.changes 2023-12-11 21:51:21.969339808 +0100 @@ -1,0 +2,14 @@ +Mon Dec 11 07:18:35 UTC 2023 - Steve Kowalik <steven.kowa...@suse.com> + +- Update 0.4.1: + * feat: provider selector by @frostming in #20 + * feat: add support for RyeProvider + * feat: Add way to filter providers by @bluss in #18 + * feat: add register_provider function and change ALL_PROVIDERS to a map + * fix: don't import site-packages when running in-process scripts + * Make GET_VERSION_TIMEOUT settable via env vars + * Support allow_prereleases option +- Add patch revert-back-to-pdm-pep517.patch: + * We need to use pdm-pep517, to avoid circular requirements. + +------------------------------------------------------------------- Old: ---- findpython-0.2.5.tar.gz New: ---- findpython-0.4.1.tar.gz revert-back-to-pdm-pep517.patch BETA DEBUG BEGIN: New: * Support allow_prereleases option - Add patch revert-back-to-pdm-pep517.patch: * We need to use pdm-pep517, to avoid circular requirements. BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-findpython.spec ++++++ --- /var/tmp/diff_new_pack.iwTyNt/_old 2023-12-11 21:51:22.929375430 +0100 +++ /var/tmp/diff_new_pack.iwTyNt/_new 2023-12-11 21:51:22.933375580 +0100 @@ -18,12 +18,14 @@ %{?sle15_python_module_pythons} Name: python-findpython -Version: 0.2.5 +Version: 0.4.1 Release: 0 Summary: Utility to find python versions on your system License: MIT URL: https://github.com/frostming/findpython Source: https://files.pythonhosted.org/packages/source/f/findpython/findpython-%{version}.tar.gz +# PATCH-FIX-OPENSUSE pdm requires findpython, so we need to use pdm-pep517 +Patch0: revert-back-to-pdm-pep517.patch BuildRequires: %{python_module base >= 3.7} BuildRequires: %{python_module packaging >= 20} BuildRequires: %{python_module pdm-pep517} ++++++ findpython-0.2.5.tar.gz -> findpython-0.4.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/PKG-INFO new/findpython-0.4.1/PKG-INFO --- old/findpython-0.2.5/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/findpython-0.4.1/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,16 +1,18 @@ Metadata-Version: 2.1 Name: findpython -Version: 0.2.5 +Version: 0.4.1 Summary: A utility to find python versions on your system +Author-Email: Frost Ming <miangh...@gmail.com> License: MIT -Author-email: Frost Ming <miangh...@gmail.com> -Requires-Python: >=3.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 Project-URL: Homepage, https://github.com/frostming/findpython +Requires-Python: >=3.7 +Requires-Dist: packaging>=20 Description-Content-Type: text/markdown # FindPython @@ -69,21 +71,24 @@ In addition, FindPython provides a CLI interface to find python versions: ``` -usage: findpython [-h] [-V] [-a] [--resolve-symlink] [-v] [--no-same-file] [--no-same-python] [version_spec] +usage: findpython [-h] [-V] [-a] [--resolve-symlink] [-v] [--no-same-file] [--no-same-python] [--providers PROVIDERS] + [version_spec] -Find python files in a directory +A utility to find python versions on your system positional arguments: - version_spec Python version spec or name + version_spec Python version spec or name options: - -h, --help show this help message and exit - -V, --version show program's version number and exit - -a, --all Show all matching python versions - --resolve-symlink Resolve all symlinks - -v, --verbose Verbose output - --no-same-file Eliminate the duplicated results with the same file contents - --no-same-python Eliminate the duplicated results with the same sys.executable + -h, --help show this help message and exit + -V, --version show program's version number and exit + -a, --all Show all matching python versions + --resolve-symlink Resolve all symlinks + -v, --verbose Verbose output + --no-same-file Eliminate the duplicated results with the same file contents + --no-same-python Eliminate the duplicated results with the same sys.executable + --providers PROVIDERS + Select provider(s) to use ``` ## Integration @@ -91,12 +96,12 @@ FindPython finds Python from the following places: - `PATH` environment variable -- pyenv -- asdf +- pyenv install root +- asdf python install root +- [rye](https://rye-up.com) toolchain install root - `/Library/Frameworks/Python.framework/Versions` (MacOS) -- winreg (Windows) +- Windows registry (Windows only) ## License FindPython is released under MIT License. - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/README.md new/findpython-0.4.1/README.md --- old/findpython-0.2.5/README.md 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/README.md 2023-12-07 05:39:09.105851000 +0100 @@ -54,21 +54,24 @@ In addition, FindPython provides a CLI interface to find python versions: ``` -usage: findpython [-h] [-V] [-a] [--resolve-symlink] [-v] [--no-same-file] [--no-same-python] [version_spec] +usage: findpython [-h] [-V] [-a] [--resolve-symlink] [-v] [--no-same-file] [--no-same-python] [--providers PROVIDERS] + [version_spec] -Find python files in a directory +A utility to find python versions on your system positional arguments: - version_spec Python version spec or name + version_spec Python version spec or name options: - -h, --help show this help message and exit - -V, --version show program's version number and exit - -a, --all Show all matching python versions - --resolve-symlink Resolve all symlinks - -v, --verbose Verbose output - --no-same-file Eliminate the duplicated results with the same file contents - --no-same-python Eliminate the duplicated results with the same sys.executable + -h, --help show this help message and exit + -V, --version show program's version number and exit + -a, --all Show all matching python versions + --resolve-symlink Resolve all symlinks + -v, --verbose Verbose output + --no-same-file Eliminate the duplicated results with the same file contents + --no-same-python Eliminate the duplicated results with the same sys.executable + --providers PROVIDERS + Select provider(s) to use ``` ## Integration @@ -76,10 +79,11 @@ FindPython finds Python from the following places: - `PATH` environment variable -- pyenv -- asdf +- pyenv install root +- asdf python install root +- [rye](https://rye-up.com) toolchain install root - `/Library/Frameworks/Python.framework/Versions` (MacOS) -- winreg (Windows) +- Windows registry (Windows only) ## License diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/pyproject.toml new/findpython-0.4.1/pyproject.toml --- old/findpython-0.2.5/pyproject.toml 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/pyproject.toml 2023-12-07 05:39:20.101811400 +0100 @@ -16,8 +16,9 @@ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ] -version = "0.2.5" +version = "0.4.1" [project.license] text = "MIT" @@ -46,16 +47,40 @@ include = "\\.pyi?$" exclude = "/(\n \\.eggs\n | \\.git\n | \\.hg\n | \\.mypy_cache\n | \\.tox\n | \\.venv\n | build\n | dist\n | src/pythonfinder/_vendor\n)\n" -[tool.isort] -profile = "black" -atomic = true -filter_files = true -known_first_party = [ +[tool.ruff] +line-length = 90 +select = [ + "B", + "C4", + "E", + "F", + "PGH", + "RUF", + "W", + "YTT", +] +extend-ignore = [ + "B018", + "B019", +] +src = [ + "src", +] +exclude = [ + "tests/fixtures", +] +target-version = "py37" + +[tool.ruff.mccabe] +max-complexity = 10 + +[tool.ruff.isort] +known-first-party = [ "findpython", ] [build-system] requires = [ - "pdm-pep517", + "pdm-backend", ] -build-backend = "pdm.pep517.api" +build-backend = "pdm.backend" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/__init__.py new/findpython-0.4.1/src/findpython/__init__.py --- old/findpython-0.2.5/src/findpython/__init__.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/__init__.py 2023-12-07 05:39:09.105851000 +0100 @@ -5,7 +5,11 @@ """ from __future__ import annotations +from typing import TYPE_CHECKING, TypeVar + from findpython.finder import Finder +from findpython.providers import ALL_PROVIDERS +from findpython.providers.base import BaseProvider from findpython.python import PythonVersion @@ -41,4 +45,18 @@ return Finder().find_all(*args, **kwargs) -__all__ = ["Finder", "find", "find_all", "PythonVersion"] +if TYPE_CHECKING: + P = TypeVar("P", bound=type[BaseProvider]) + + +def register_provider(provider: P) -> P: + """ + Register a provider to use when finding python versions. + + :param provider: A provider class + """ + ALL_PROVIDERS[provider.name()] = provider + return provider + + +__all__ = ["Finder", "find", "find_all", "PythonVersion", "register_provider"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/__main__.py new/findpython-0.4.1/src/findpython/__main__.py --- old/findpython-0.2.5/src/findpython/__main__.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/__main__.py 2023-12-07 05:39:09.105851000 +0100 @@ -3,7 +3,6 @@ import logging import sys from argparse import ArgumentParser -from typing import List from findpython import Finder from findpython.__version__ import __version__ @@ -21,11 +20,17 @@ logger.setLevel(level) -def cli(argv: List[str] | None = None) -> int: +def split_str(value: str) -> list[str]: + return value.split(",") + + +def cli(argv: list[str] | None = None) -> int: """ Command line interface for findpython. """ - parser = ArgumentParser("findpython", description="Find python files in a directory") + parser = ArgumentParser( + "findpython", description="A utility to find python versions on your system" + ) parser.add_argument( "-V", "--version", action="version", version=f"%(prog)s {__version__}" ) @@ -46,17 +51,27 @@ action="store_true", help="Eliminate the duplicated results with the same sys.executable", ) + parser.add_argument( + "--pre", "--prereleases", action="store_true", help="Allow prereleases" + ) + parser.add_argument("--providers", type=split_str, help="Select provider(s) to use") parser.add_argument("version_spec", nargs="?", help="Python version spec or name") args = parser.parse_args(argv) if args.verbose: setup_logger() - finder = Finder(resolve_symlinks=args.resolve_symlink, no_same_file=args.no_same_file) + + finder = Finder( + resolve_symlinks=args.resolve_symlink, + no_same_file=args.no_same_file, + selected_providers=args.providers, + ) if args.all: find_func = finder.find_all else: - find_func = finder.find - python_versions = find_func(args.version_spec) + find_func = finder.find # type: ignore[assignment] + + python_versions = find_func(args.version_spec, allow_prereleases=args.pre) if not python_versions: print("No matching python version found", file=sys.stderr) return 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/__version__.py new/findpython-0.4.1/src/findpython/__version__.py --- old/findpython-0.2.5/src/findpython/__version__.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/__version__.py 2023-12-07 05:39:20.101811400 +0100 @@ -1 +1 @@ -__version__ = "0.0.0" +__version__ = "0.4.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/finder.py new/findpython-0.4.1/src/findpython/finder.py --- old/findpython-0.2.5/src/findpython/finder.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/finder.py 2023-12-07 05:39:09.105851000 +0100 @@ -24,16 +24,22 @@ resolve_symlinks: bool = False, no_same_file: bool = False, no_same_interpreter: bool = False, + selected_providers: list[str] | None = None, ) -> None: self.resolve_symlinks = resolve_symlinks self.no_same_file = no_same_file self.no_same_interpreter = no_same_interpreter + self._providers = self.setup_providers(selected_providers) - self._providers = self.setup_providers() - - def setup_providers(self) -> list[BaseProvider]: + def setup_providers( + self, + selected_providers: list[str] | None = None, + ) -> list[BaseProvider]: providers: list[BaseProvider] = [] - for provider_class in ALL_PROVIDERS: + allowed_providers = ALL_PROVIDERS + if selected_providers is not None: + allowed_providers = {name: ALL_PROVIDERS[name] for name in selected_providers} + for provider_class in allowed_providers.values(): provider = provider_class.create() if provider is None: logger.debug("Provider %s is not available", provider_class.__name__) @@ -59,6 +65,7 @@ dev: bool | None = None, name: str | None = None, architecture: str | None = None, + allow_prereleases: bool = False, ) -> list[PythonVersion]: """ Return all Python versions matching the given version criteria. @@ -70,8 +77,13 @@ :param dev: Whether the python is a devrelease. :param name: The name of the python. :param architecture: The architecture of the python. + :param allow_prereleases: Whether to allow prereleases. :return: a list of PythonVersion objects """ + if allow_prereleases and (pre is False or dev is False): + raise ValueError( + "If allow_prereleases is True, pre and dev must not be False." + ) if isinstance(major, str): if any(v is not None for v in (minor, patch, pre, dev, name)): raise ValueError( @@ -85,6 +97,9 @@ patch = version_dict["patch"] pre = version_dict["pre"] dev = version_dict["dev"] + if allow_prereleases: + pre = pre or None + dev = dev or None architecture = version_dict["architecture"] else: name, major = major, None @@ -112,6 +127,7 @@ dev: bool | None = None, name: str | None = None, architecture: str | None = None, + allow_prereleases: bool = False, ) -> PythonVersion | None: """ Return the Python version that is closest to the given version criteria. @@ -123,10 +139,15 @@ :param dev: Whether the python is a devrelease. :param name: The name of the python. :param architecture: The architecture of the python. + :param allow_prereleases: Whether to allow prereleases. :return: a Python object or None """ return next( - iter(self.find_all(major, minor, patch, pre, dev, name, architecture)), + iter( + self.find_all( + major, minor, patch, pre, dev, name, architecture, allow_prereleases + ) + ), None, ) @@ -149,7 +170,7 @@ return python_version.real_path.as_posix() return python_version.executable.as_posix() - def sort_key(python_version: PythonVersion) -> tuple[int, int]: + def sort_key(python_version: PythonVersion) -> tuple[int, int, int]: return ( python_version.executable.is_symlink(), get_suffix_preference(python_version.name), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/pep514tools/__init__.py new/findpython-0.4.1/src/findpython/pep514tools/__init__.py --- old/findpython-0.2.5/src/findpython/pep514tools/__init__.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/pep514tools/__init__.py 2023-12-07 05:39:09.105851000 +0100 @@ -8,6 +8,6 @@ __author__ = "Steve Dower <steve.do...@python.org>" __version__ = "0.1.0" -from findpython.pep514tools.environment import findall, find, findone +from findpython.pep514tools.environment import find, findall, findone __all__ = ["findall", "find", "findone"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/pep514tools/_registry.py new/findpython-0.4.1/src/findpython/pep514tools/_registry.py --- old/findpython-0.2.5/src/findpython/pep514tools/_registry.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/pep514tools/_registry.py 2023-12-07 05:39:09.105851000 +0100 @@ -12,8 +12,8 @@ "REGISTRY_SOURCE_CU", ] -from itertools import count import re +from itertools import count try: import winreg @@ -86,10 +86,8 @@ key = self._attr_to_key(attr) try: return self._d[key] - except KeyError: - pass except Exception: - raise AttributeError(attr) + pass raise AttributeError(attr) def __setattr__(self, attr, value): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/pep514tools/environment.py new/findpython-0.4.1/src/findpython/pep514tools/environment.py --- old/findpython-0.2.5/src/findpython/pep514tools/environment.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/pep514tools/environment.py 2023-12-07 05:39:09.105851000 +0100 @@ -7,13 +7,14 @@ __all__ = ["Environment", "findall", "find", "findone"] +import sys + from findpython.pep514tools._registry import ( - open_source, + REGISTRY_SOURCE_CU, REGISTRY_SOURCE_LM, REGISTRY_SOURCE_LM_WOW6432, - REGISTRY_SOURCE_CU, + open_source, ) -import sys # These tags are treated specially when the Company is 'PythonCore' _PYTHONCORE_COMPATIBILITY_TAGS = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/providers/__init__.py new/findpython-0.4.1/src/findpython/providers/__init__.py --- old/findpython-0.2.5/src/findpython/providers/__init__.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/providers/__init__.py 2023-12-07 05:39:09.109851000 +0100 @@ -1,25 +1,29 @@ """ This package contains all the providers for the pythonfinder module. """ -from typing import List, Type +from __future__ import annotations from findpython.providers.asdf import AsdfProvider from findpython.providers.base import BaseProvider from findpython.providers.macos import MacOSProvider from findpython.providers.path import PathProvider -from findpython.providers.pep514 import Pep514Provider from findpython.providers.pyenv import PyenvProvider +from findpython.providers.rye import RyeProvider +from findpython.providers.winreg import WinregProvider -ALL_PROVIDERS: List[Type[BaseProvider]] = [ +_providers: list[type[BaseProvider]] = [ # General: PathProvider, # Tool Specific: AsdfProvider, PyenvProvider, + RyeProvider, # Windows only: - Pep514Provider, + WinregProvider, # MacOS only: MacOSProvider, ] -__all__ = [cls.__name__ for cls in ALL_PROVIDERS] + ["ALL_PROVIDERS", "BaseProvider"] +ALL_PROVIDERS = {cls.name(): cls for cls in _providers} + +__all__ = [cls.__name__ for cls in _providers] + ["ALL_PROVIDERS", "BaseProvider"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/providers/asdf.py new/findpython-0.4.1/src/findpython/providers/asdf.py --- old/findpython-0.2.5/src/findpython/providers/asdf.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/providers/asdf.py 2023-12-07 05:39:09.109851000 +0100 @@ -1,10 +1,10 @@ from __future__ import annotations import os +import typing as t from pathlib import Path -from typing import Iterable, Type -from findpython.providers.base import BaseProvider, T +from findpython.providers.base import BaseProvider from findpython.python import PythonVersion @@ -15,7 +15,7 @@ self.root = root @classmethod - def create(cls: Type[T]) -> T | None: + def create(cls) -> t.Self | None: asdf_root = os.path.expanduser( os.path.expandvars(os.getenv("ASDF_DATA_DIR", "~/.asdf")) ) @@ -23,7 +23,7 @@ return None return cls(Path(asdf_root)) - def find_pythons(self) -> Iterable[PythonVersion]: + def find_pythons(self) -> t.Iterable[PythonVersion]: python_dir = self.root / "installs/python" if not python_dir.exists(): return diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/providers/base.py new/findpython-0.4.1/src/findpython/providers/base.py --- old/findpython-0.2.5/src/findpython/providers/base.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/providers/base.py 2023-12-07 05:39:09.109851000 +0100 @@ -2,36 +2,46 @@ import abc import logging +import typing as t from pathlib import Path -from typing import Callable, Iterable, Type, TypeVar from findpython.python import PythonVersion from findpython.utils import path_is_python, safe_iter_dir -T = TypeVar("T", bound="BaseProvider") logger = logging.getLogger("findpython") class BaseProvider(metaclass=abc.ABCMeta): """The base class for python providers""" - version_maker: Callable[..., PythonVersion] = PythonVersion + version_maker: t.Callable[..., PythonVersion] = PythonVersion + + @classmethod + def name(cls) -> str: + """Configuration name for this provider. + + By default, the lowercase class name with 'provider' removed. + """ + self_name = cls.__name__.lower() + if self_name.endswith("provider"): + self_name = self_name[: -len("provider")] + return self_name @classmethod @abc.abstractmethod - def create(cls: Type[T]) -> T | None: + def create(cls) -> t.Self | None: """Return an instance of the provider or None if it is not available""" pass @abc.abstractmethod - def find_pythons(self) -> Iterable[PythonVersion]: + def find_pythons(self) -> t.Iterable[PythonVersion]: """Return the python versions found by the provider""" pass @classmethod def find_pythons_from_path( cls, path: Path, as_interpreter: bool = False - ) -> Iterable[PythonVersion]: + ) -> t.Iterable[PythonVersion]: """A general helper method to return pythons under a given path. :param path: The path to search for pythons diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/providers/macos.py new/findpython-0.4.1/src/findpython/providers/macos.py --- old/findpython-0.2.5/src/findpython/providers/macos.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/providers/macos.py 2023-12-07 05:39:09.109851000 +0100 @@ -1,9 +1,9 @@ from __future__ import annotations +import typing as t from pathlib import Path -from typing import Iterable, Type -from findpython.providers.base import BaseProvider, T +from findpython.providers.base import BaseProvider from findpython.python import PythonVersion @@ -15,12 +15,12 @@ INSTALL_BASE = Path("/Library/Frameworks/Python.framework/Versions/") @classmethod - def create(cls: Type[T]) -> T | None: + def create(cls) -> t.Self | None: if not cls.INSTALL_BASE.exists(): return None return cls() - def find_pythons(self) -> Iterable[PythonVersion]: + def find_pythons(self) -> t.Iterable[PythonVersion]: for version in self.INSTALL_BASE.iterdir(): if version.is_dir(): yield from self.find_pythons_from_path(version / "bin", True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/providers/path.py new/findpython-0.4.1/src/findpython/providers/path.py --- old/findpython-0.2.5/src/findpython/providers/path.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/providers/path.py 2023-12-07 05:39:09.109851000 +0100 @@ -1,11 +1,11 @@ from __future__ import annotations import os +import typing as t from dataclasses import dataclass from pathlib import Path -from typing import Iterable, Type -from findpython.providers.base import BaseProvider, T +from findpython.providers.base import BaseProvider from findpython.python import PythonVersion @@ -16,10 +16,10 @@ paths: list[Path] @classmethod - def create(cls: Type[T]) -> T | None: + def create(cls) -> t.Self | None: paths = [Path(path) for path in os.getenv("PATH", "").split(os.pathsep) if path] return cls(paths) - def find_pythons(self) -> Iterable[PythonVersion]: + def find_pythons(self) -> t.Iterable[PythonVersion]: for path in self.paths: yield from self.find_pythons_from_path(path) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/providers/pep514.py new/findpython-0.4.1/src/findpython/providers/pep514.py --- old/findpython-0.2.5/src/findpython/providers/pep514.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/providers/pep514.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,42 +0,0 @@ -from __future__ import annotations - -import platform -from pathlib import Path -from typing import Iterable, Type - -from findpython.providers.base import BaseProvider, T -from findpython.python import PythonVersion -from findpython.utils import WINDOWS - -SYS_ARCHITECTURE = platform.architecture()[0] - - -class Pep514Provider(BaseProvider): - """A provider that finds Python from the winreg.""" - - @classmethod - def create(cls: Type[T]) -> T | None: - if not WINDOWS: - return None - return cls() - - def find_pythons(self) -> Iterable[PythonVersion]: - from findpython.pep514tools import findall as pep514_findall - - env_versions = pep514_findall() - for version in env_versions: - install_path = getattr(version.info, "install_path", None) - if install_path is None: - continue - try: - path = Path(install_path.executable_path) - except AttributeError: - continue - if path.exists(): - py_ver = self.version_maker( - path, - None, - getattr(version.info, "sys_architecture", SYS_ARCHITECTURE), - path, - ) - yield py_ver diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/providers/pyenv.py new/findpython-0.4.1/src/findpython/providers/pyenv.py --- old/findpython-0.2.5/src/findpython/providers/pyenv.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/providers/pyenv.py 2023-12-07 05:39:09.109851000 +0100 @@ -1,10 +1,10 @@ from __future__ import annotations import os +import typing as t from pathlib import Path -from typing import Iterable, Type -from findpython.providers.base import BaseProvider, T +from findpython.providers.base import BaseProvider from findpython.python import PythonVersion @@ -15,7 +15,7 @@ self.root = root @classmethod - def create(cls: Type[T]) -> T | None: + def create(cls) -> t.Self | None: pyenv_root = os.path.expanduser( os.path.expandvars(os.getenv("PYENV_ROOT", "~/.pyenv")) ) @@ -23,7 +23,7 @@ return None return cls(Path(pyenv_root)) - def find_pythons(self) -> Iterable[PythonVersion]: + def find_pythons(self) -> t.Iterable[PythonVersion]: versions_path = self.root.joinpath("versions") if versions_path.exists(): for version in versions_path.iterdir(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/providers/rye.py new/findpython-0.4.1/src/findpython/providers/rye.py --- old/findpython-0.2.5/src/findpython/providers/rye.py 1970-01-01 01:00:00.000000000 +0100 +++ new/findpython-0.4.1/src/findpython/providers/rye.py 2023-12-07 05:39:09.109851000 +0100 @@ -0,0 +1,33 @@ +from __future__ import annotations + +import shutil +import typing as t +from pathlib import Path + +from findpython.providers.base import BaseProvider +from findpython.python import PythonVersion +from findpython.utils import WINDOWS, safe_iter_dir + + +class RyeProvider(BaseProvider): + def __init__(self) -> None: + self.root = Path.home() / ".rye" + self.rye_bin = shutil.which("rye") + + @classmethod + def create(cls) -> t.Self | None: + return cls() + + def find_pythons(self) -> t.Iterable[PythonVersion]: + py_root = self.root / "py" + if not py_root.exists(): + return + for child in safe_iter_dir(py_root): + if child.is_symlink(): # registered an existing python + continue + if WINDOWS: + python_bin = child / "install/python.exe" + else: + python_bin = child / "install/bin/python3" + if python_bin.exists(): + yield self.version_maker(python_bin, _interpreter=python_bin) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/providers/winreg.py new/findpython-0.4.1/src/findpython/providers/winreg.py --- old/findpython-0.2.5/src/findpython/providers/winreg.py 1970-01-01 01:00:00.000000000 +0100 +++ new/findpython-0.4.1/src/findpython/providers/winreg.py 2023-12-07 05:39:09.109851000 +0100 @@ -0,0 +1,42 @@ +from __future__ import annotations + +import platform +import typing as t +from pathlib import Path + +from findpython.providers.base import BaseProvider +from findpython.python import PythonVersion +from findpython.utils import WINDOWS + +SYS_ARCHITECTURE = platform.architecture()[0] + + +class WinregProvider(BaseProvider): + """A provider that finds Python from the winreg.""" + + @classmethod + def create(cls) -> t.Self | None: + if not WINDOWS: + return None + return cls() + + def find_pythons(self) -> t.Iterable[PythonVersion]: + from findpython.pep514tools import findall as pep514_findall + + env_versions = pep514_findall() + for version in env_versions: + install_path = getattr(version.info, "install_path", None) + if install_path is None: + continue + try: + path = Path(install_path.executable_path) + except AttributeError: + continue + if path.exists(): + py_ver = self.version_maker( + path, + None, + getattr(version.info, "sys_architecture", SYS_ARCHITECTURE), + path, + ) + yield py_ver diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/python.py new/findpython-0.4.1/src/findpython/python.py --- old/findpython-0.2.5/src/findpython/python.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/python.py 2023-12-07 05:39:09.109851000 +0100 @@ -2,6 +2,7 @@ import dataclasses as dc import logging +import os import subprocess from functools import lru_cache from pathlib import Path @@ -11,7 +12,22 @@ from findpython.utils import get_binary_hash logger = logging.getLogger("findpython") -GET_VERSION_TIMEOUT = 5 +GET_VERSION_TIMEOUT = float(os.environ.get("FINDPYTHON_GET_VERSION_TIMEOUT", 5)) + + +@lru_cache(maxsize=1024) +def _run_script(executable: str, script: str, timeout: float | None = None) -> str: + """Run a script and return the output.""" + command = [executable, "-EsSc", script] + logger.debug("Running script: %s", command) + return subprocess.run( + command, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + timeout=timeout, + check=True, + text=True, + ).stdout @dc.dataclass @@ -161,7 +177,9 @@ def _get_version(self) -> Version: """Get the version of the python.""" script = "import platform; print(platform.python_version())" - version = self._run_script(script, timeout=GET_VERSION_TIMEOUT).strip() + version = _run_script( + str(self.executable), script, timeout=GET_VERSION_TIMEOUT + ).strip() # Dev builds may produce version like `3.11.0+` and packaging.version # will reject it. Here we just remove the part after `+` # since it isn't critical for version comparison. @@ -170,25 +188,11 @@ def _get_architecture(self) -> str: script = "import platform; print(platform.architecture()[0])" - return self._run_script(script).strip() + return _run_script(str(self.executable), script).strip() def _get_interpreter(self) -> str: script = "import sys; print(sys.executable)" - return self._run_script(script).strip() - - @lru_cache(maxsize=1024) - def _run_script(self, script: str, timeout: float | None = None) -> str: - """Run a script and return the output.""" - command = [self.executable.as_posix(), "-c", script] - logger.debug("Running script: %s", command) - return subprocess.run( - command, - stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL, - timeout=timeout, - check=True, - text=True, - ).stdout + return _run_script(str(self.executable), script).strip() def __lt__(self, other: PythonVersion) -> bool: """Sort by the version, then by length of the executable path.""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/src/findpython/utils.py new/findpython-0.4.1/src/findpython/utils.py --- old/findpython-0.2.5/src/findpython/utils.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/src/findpython/utils.py 2023-12-07 05:39:09.109851000 +0100 @@ -7,7 +7,10 @@ import sys from functools import lru_cache from pathlib import Path -from typing import Generator +from typing import TYPE_CHECKING, cast + +if TYPE_CHECKING: + from typing import Generator, Sequence, TypedDict VERSION_RE = re.compile( r"(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>[0-9]+))?)?\.?" @@ -30,7 +33,7 @@ "micropython", ) if WINDOWS: - KNOWN_EXTS = (".exe", "", ".py", ".bat") + KNOWN_EXTS: Sequence[str] = (".exe", "", ".py", ".bat") else: KNOWN_EXTS = ("", ".sh", ".bash", ".csh", ".zsh", ".fish", ".py") PY_MATCH_STR = ( @@ -117,7 +120,18 @@ return hasher.hexdigest() -def parse_major(version: str) -> dict[str, int | bool | None] | None: +if TYPE_CHECKING: + + class VersionDict(TypedDict): + pre: bool + dev: bool + major: int | None + minor: int | None + patch: int | None + architecture: str | None + + +def parse_major(version: str) -> VersionDict | None: """Parse the version dict from the version string""" match = VERSION_RE.match(version) if not match: @@ -130,7 +144,7 @@ rv[int_values] = int(rv[int_values]) if rv["architecture"]: rv["architecture"] = f"{rv['architecture']}bit" - return rv + return cast("VersionDict", rv) def get_suffix_preference(name: str) -> int: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/tests/conftest.py new/findpython-0.4.1/tests/conftest.py --- old/findpython-0.2.5/tests/conftest.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/tests/conftest.py 2023-12-07 05:39:09.109851000 +0100 @@ -9,7 +9,7 @@ class _MockRegistry: def __init__(self) -> None: - self.versions = {} + self.versions: dict[Path, PythonVersion] = {} def add_python( self, @@ -51,7 +51,8 @@ monkeypatch.setattr( "findpython.providers.base.BaseProvider.version_maker", mocked.version_maker ) - ALL_PROVIDERS[:] = [PathProvider] + ALL_PROVIDERS.clear() + ALL_PROVIDERS["path"] = PathProvider monkeypatch.setenv("PATH", str(tmp_path)) return mocked diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/tests/test_finder.py new/findpython-0.4.1/tests/test_finder.py --- old/findpython-0.2.5/tests/test_finder.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/tests/test_finder.py 2023-12-07 05:39:09.109851000 +0100 @@ -4,8 +4,7 @@ import pytest from packaging.version import Version -from findpython import Finder -from findpython.providers import ALL_PROVIDERS +from findpython import Finder, register_provider from findpython.providers.pyenv import PyenvProvider @@ -117,7 +116,7 @@ def test_find_python_from_pyenv(mocked_python, tmp_path, monkeypatch): - ALL_PROVIDERS.append(PyenvProvider) + register_provider(PyenvProvider) python = mocked_python.add_python( tmp_path / ".pyenv/versions/3.8/bin/python", "3.8.0" ) @@ -128,7 +127,7 @@ def test_find_python_skips_empty_pyenv(mocked_python, tmp_path, monkeypatch): - ALL_PROVIDERS.append(PyenvProvider) + register_provider(PyenvProvider) pyenv_path = Path(tmp_path / ".pyenv") pyenv_path.mkdir() monkeypatch.setenv("PYENV_ROOT", str(pyenv_path)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/tests/test_posix.py new/findpython-0.4.1/tests/test_posix.py --- old/findpython-0.2.5/tests/test_posix.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/tests/test_posix.py 2023-12-07 05:39:09.109851000 +0100 @@ -4,9 +4,11 @@ import pytest +from findpython import register_provider from findpython.finder import Finder -from findpython.providers import ALL_PROVIDERS from findpython.providers.asdf import AsdfProvider +from findpython.providers.pyenv import PyenvProvider +from findpython.providers.rye import RyeProvider if sys.platform == "win32": pytest.skip("Skip POSIX tests on Windows", allow_module_level=True) @@ -23,7 +25,7 @@ def test_find_python_from_asdf(mocked_python, tmp_path, monkeypatch): - ALL_PROVIDERS.append(AsdfProvider) + register_provider(AsdfProvider) python = mocked_python.add_python( tmp_path / ".asdf/installs/python/3.8/bin/python", "3.8.0" ) @@ -43,3 +45,45 @@ assert python not in [version.executable for version in all_pythons] finally: python.chmod(0o744) + + +def test_find_python_from_provider(mocked_python, tmp_path, monkeypatch): + register_provider(AsdfProvider) + register_provider(PyenvProvider) + python38 = mocked_python.add_python( + tmp_path / ".asdf/installs/python/3.8/bin/python", "3.8.0" + ) + python381 = mocked_python.add_python( + tmp_path / ".pyenv/versions/3.8.1/bin/python", "3.8.1" + ) + python382 = mocked_python.add_python( + tmp_path / ".asdf/installs/python/3.8.2/bin/python", "3.8.2" + ) + monkeypatch.setenv("ASDF_DATA_DIR", str(tmp_path / ".asdf")) + monkeypatch.setenv("PYENV_ROOT", str(tmp_path / ".pyenv")) + + pythons = Finder(selected_providers=["pyenv", "asdf"]).find_all(3, 8) + assert len(pythons) == 3 + assert python38 in pythons + assert python381 in pythons + assert python382 in pythons + + asdf_pythons = Finder(selected_providers=["asdf"]).find_all(3, 8) + assert len(asdf_pythons) == 2 + assert python38 in asdf_pythons + assert python382 in asdf_pythons + + pyenv_pythons = Finder(selected_providers=["pyenv"]).find_all(3, 8) + assert len(pyenv_pythons) == 1 + assert python381 in pyenv_pythons + + +def test_find_python_from_rye_provider(mocked_python, tmp_path, monkeypatch): + python310 = mocked_python.add_python( + tmp_path / ".rye/py/cpython@3.10.9/install/bin/python3", "3.10.9" + ) + monkeypatch.setenv("HOME", str(tmp_path)) + + register_provider(RyeProvider) + pythons = Finder(selected_providers=["rye"]).find_all(3, 10) + assert python310 in pythons diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/findpython-0.2.5/tests/test_utils.py new/findpython-0.4.1/tests/test_utils.py --- old/findpython-0.2.5/tests/test_utils.py 2023-05-10 10:27:49.053817000 +0200 +++ new/findpython-0.4.1/tests/test_utils.py 2023-12-07 05:39:09.109851000 +0100 @@ -1,6 +1,6 @@ -from findpython.utils import WINDOWS, looks_like_python import pytest +from findpython.utils import WINDOWS, looks_like_python matrix = [ ("python", True), ++++++ revert-back-to-pdm-pep517.patch ++++++ Index: findpython-0.4.1/pyproject.toml =================================================================== --- findpython-0.4.1.orig/pyproject.toml +++ findpython-0.4.1/pyproject.toml @@ -81,6 +81,6 @@ known-first-party = [ [build-system] requires = [ - "pdm-backend", + "pdm-pep517", ] -build-backend = "pdm.backend" +build-backend = "pdm.pep517.api"