Skip to content

🐛 fix(discovery): tolerate unreadable .python-version files - #173

Merged
gaborbernat merged 3 commits into
tox-dev:mainfrom
darrenhuai:fix/unreadable-python-version
Oct 30, 2026
Merged

gaborbernat merged 3 commits into
tox-dev:mainfrom
darrenhuai:fix/unreadable-python-version

Conversation

@darrenhuai

@darrenhuai darrenhuai commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

A .python-version that isn't valid UTF-8, or that the user can't read, made discovery through a pyenv, mise or asdf shim raise instead of finding an interpreter. 🐛 With a Latin-1 comment such as # für das Projekt above 3.11.9, get_interpreter("3.11") stopped with UnicodeDecodeError, and so did virtualenv, which passes -p to it without a guard. A file without read permission, or a working directory below a folder without search permission, raised PermissionError the same way. Once this merges, discovery reads 3.11.9 from the Latin-1 file, as pyenv does, and skips an unreadable file like a missing one.

This only affects shim resolution with PYENV_VERSION unset. Discovery then walks from the working directory up to the filesystem root looking for a .python-version that names a version, and falls back to the pyenv global version file. pyenv reads these files with bash read, which never decodes, so discovery now tolerates undecodable bytes. A file or directory it can't access counts as naming no version, and the walk moves on to the parent and the global file, the same path a comments-only file already takes. Read failures go to the debug log.

A UTF-16 file, which Windows PowerShell 5.1 writes for "3.12" > .python-version, no longer raises either. pyenv can't read that file and neither can discovery, so the shim is probed as is.

darrenhuai and others added 3 commits October 28, 2026 21:10
…ting discovery

Resolving a pyenv, mise or asdf shim reads .python-version from the working directory up to the filesystem root, then
$PYENV_ROOT/version, and each file was opened as strict UTF-8 with no error handling. A file holding a byte that is not
UTF-8, such as a Latin-1 comment or the UTF-16 that Windows PowerShell 5.1 writes for `"3.12" > .python-version`,
raised UnicodeDecodeError, and one the user may not read raised PermissionError. Both escaped get_interpreter and
iter_interpreters, so virtualenv and tox stopped with a traceback for anyone with a shim on PATH who asked for an
interpreter other than the running one. pyenv reads the file as bytes, so it takes the version from the Latin-1 file
without complaint.

The file is now decoded with errors="replace", so a byte that does not decode no longer hides the versions around it,
the same result pyenv's reader gives. A file that cannot be opened or read is treated like one that names no version:
it is logged at debug level and the search moves on, as the rest of the module does with filesystem errors.
On Python 3.9 to 3.13, Path.is_dir and Path.is_file re-raise a PermissionError from stat, so a working directory
under a folder without search permission still aborted the .python-version walk. os.path.isdir and os.path.isfile
return False there. The shim test now pins with a Latin-1 comment and checks that the pinned interpreter is probed.
Exercise the unreadable file and unsearchable directory through
get_interpreter with real file permissions instead of calling the private
reader and patching Path.open, and drop the reader-level Latin-1 test that
the shim test already covers. Relabel the docs flowchart: a file that exists
but names no readable version now falls through to the parent directories.
@gaborbernat gaborbernat added the bug Something isn't working label Oct 30, 2026
@gaborbernat gaborbernat changed the title 🐛 fix(discovery): stop a non-UTF-8 or unreadable .python-version aborting discovery 🐛 fix(discovery): tolerate unreadable .python-version files Oct 30, 2026

@gaborbernat gaborbernat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaborbernat
gaborbernat enabled auto-merge (squash) October 30, 2026 18:19
@gaborbernat
gaborbernat merged commit 7d18e8a into tox-dev:main Oct 30, 2026
20 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants