- Add
Finder(pyenv_only=True)to restrict discovery to pyenv-managed Python installations. #3855
- Convert away from pydantic to reduce complexity; simplify the path manipulation logics to use pathlib. #157
Fix full-version matching for Python installations discovered via the Windows py launcher.
py --list-pathsonly reportsmajor.minor(e.g.3.11), soPyLauncherFinderwas storingpatch=Nonefor every entry. Callers that searched for a specific full version such as3.11.9(e.g. frompython_full_versionin a Pipfile) received no match becausematches(patch=9)evaluatedNone == 9 → False.The finder now queries each discovered executable for its real version string (e.g.
3.11.9) viaget_python_version()after the py-launcher lookup, so that full-version searches succeed. If the executable cannot be queried the code falls back gracefully to themajor.minorstring reported by the py launcher. #158Treat any
Path.exists()OSErroras an inaccessible path during discovery, allowing FUSE and network mount failures to be skipped cleanly. #4898Refactor pythonfinder for improved efficiency and PEP 514 support Summary
This PR completely refactors the pythonfinder module to improve efficiency, reduce logical errors, and fix support for PEP 514 (Python registration in the Windows registry). The refactoring replaces the complex object hierarchy with a more modular, composition-based approach that is easier to maintain and extend. Motivation
The original pythonfinder implementation had several issues:
Complex object wrapping with paths as objects, leading to excessive recursion Tight coupling between classes making the code difficult to follow and maintain Broken Windows registry support (PEP 514) Performance issues due to redundant path scanning and inefficient caching
Changes
Architecture: Replaced inheritance-heavy design with a composition-based approach using specialized finders Data Model: Simplified the data model with a clean PythonInfo dataclass Windows Support: Implemented proper PEP 514 support for Windows registry Performance: Improved caching and reduced redundant operations Error Handling: Added more specific exceptions and better error handling
Features
The refactored implementation continues to support all required features:
System and user PATH searches pyenv installations asdf installations Windows registry (PEP 514) - now working correctly
Implementation Details
The new implementation is organized into three main components:
- Finders: Specialized classes for finding Python in different locations
SystemFinder: Searches in the system PATH PyenvFinder: Searches in pyenv installations AsdfFinder: Searches in asdf installations WindowsRegistryFinder: Implements PEP 514 for Windows registry
- Models: Simple data classes for storing Python information
PythonInfo: Stores information about a Python installation
- Utils: Utility functions for path and version handling
path_utils.py: Path-related utility functions version_utils.py: Version-related utility functions #rewrite-3.0
No significant changes.
No significant changes.
No significant changes.
- Fix edge case from refactor to pydantic -- only search for any python version when a specific version was not requested. #139
- Fix edge case with windows git bash and environment variables having backslash. #138
- Corrected
asdfandpyenvdetection and usage which broke with the release ofpythonfinder==2.0.0#137
- Include tests and tests data into the sdist. #116
- Include tests and tests data into the sdist. #116
- Fix: catch InvalidVersion instead of handling LegacyVersion #127
- Fix permissions on WSL
- Include tests and tests data into the sdist Close #116
- Make click optional dependency
- Remove six
- Drop Python2 Support
- Check the permission as well as the existence of path when finding Pythons. #111
- Fix an error of pythonfinder when PATH contains unreadable paths. #118
- Fix a bug that the version matcher ignores the version when patch number is 0. #110
- Ensure the path exists when initializing from the PATH env var. #105
No significant changes.
- Remove the deprecated usage of
cmpinattr. #94 - Fix a bug that version sort is performed on None objects.
- Skip invalid entries from Windows registry. Ensure paths are normalized with forward slashes. #89
- Filter out the None results of Windows python finder. #87
- Unnest the mixed output from
find_all_python_versions(). #85
- Non-core versions of python will no longer sort ahead of core python versions. #75
- Reduced dependencies by removing
vistir,,crayonsand intermediate calls. #78
- Fixed a bug which could cause python searches to fail when
pyenv globalwas set with repeated identical versions. #71 pythonfinderwill now avoid accidentally pathing intopythonw.exeon windows and using it as a python version. #73
- Added support for subprocess timeouts while discovering python paths. #62
- Dramatically improved performance and stability. #51
- Added typehints and refactored mixins, updated shims to only attempt to remove themselves if they detect their respectve installations (fixes Hynek's issue). #52
- Add resilient parsing to look only for
major.minor(.patch)?as a fallback parser and allow more graceful continuation if a path is not a real path to python. #40 - Added typehints and refactored mixins, updated shims to only attempt to remove themselves if they detect their respectve installations (fixes Hynek's issue). #52
- Fixed a bug which prevented parsing of numeric versions as inputs to pythonfinder. #59
- Windows path discovery now works correctly and does not attempt to assign cached properties. #61
- Fix a bug where version in version order file may not in global version paths #37
- Added further resilient version parser functionality to python version parser. #44
- Fixed an issue which prevented parsing single digit python versions as valid. #47
- Added performance enhancements and error handling to python search algorithms.
- Added support for
asdfinstallations via theASDF_DATA_DIRenvironment variable. #35
- Fix a bug where pyenv cannot be found when PYENV_ROOT is not set #29
- Fix a bug where pyenv python location is not properly got by sysconfig._get_default_scheme #31
- Fix finding pyenv's python versions issue when pyenv root version is not present #33
- Pyenv paths will now be ordered respecting global version settings and pyenv shims will be removed from the search path. #27
- Fixed an issue with unnesting paths when finding python versions. #24
- Fixed a bug with searching windows registry entries which sometimes caused errors for uninstalled python instances. #26
No significant changes.
- Fixed an issue with parsing python paths. #52
- Fixed a broken call to
vistir.misc.runwhich returned asubprocess.Popenobject instead of its output. #22
- Introduced lookup by name when searching for python versions, which allows searching for non-standard python releases such as
anaconda3-5.3.0. #20 - General improvements:
- Improved
pyenvsupport and architecture lookup support. - Improved overall performance and caching. #21
- Improved
- Switch to using
--ignore-unsupportedby default during lookups. #19
- Added support for non-CPython interpreters. #16
- Added support for ignoring unsupported python versions during version search with the flag
--ignore-unsupported. #14 - Added support for pyenv virtualenvs. #15
- Fixed an issue which prevented graceful parsing of debug releases of python, which will now be sorted the same as prereleases. #12
- Fixed a bug which caused inadvertent inclusion of previously removed python installations on windows. #11
- Fix a bug which caused failures when parsing patch releases. #10
- Fix input string parser when architecture is specified. #9
- Add support for explicitly searching the global pythonpath using the
global_searchargument at initialization. #4 - Allow bare calls to
find_all_python_versions()to return all python versions without specifying a major version. #5 - Added efficient crawling and caching when searching for python and other executables.
- Carry architecture support all the way through the search stack to only return available python which matches the desired architecture.
- Improve sub-path consolidations for searching for executables and pythons.
- Use lazy loading of python versions to avoid unnecessary subprocess calls. #8