Repository navigation
feat(python): match the Python version of a project's .venv - #292
Merged
Merged
Conversation
In a project with a .venv but no version file, a bare python ran the global version, which matched the venv only while the global happened to be the version the venv was built from. Version resolution now reads the venv's pyvenv.cfg and uses that version. - It is the last local source for Python in a directory: after .dtvem/runtimes.json, .tool-versions and .python-version, since a venv is inferred rather than a declared pin. The nearest directory still wins. - The version comes from pyvenv.cfg's version key (python -m venv), else version_info (uv), keeping the leading major.minor[.patch]. - dtvem runs its own install of that version, not the venv's interpreter. It prefers the exact version, else the highest installed with the same major.minor, since compiled packages depend on the minor version. With none installed, the major.minor is reported as not installed. - A .venv without pyvenv.cfg, a .venv that is a file, and a .venv in the home directory, which is a user-wide environment rather than a project's, are passed over. A pyvenv.cfg without a usable version is reported.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
In a project that has a
.venvbut no version file, such asagent_c_framework(a uv workspace whose.venvwas built from dtvem's Python 3.12.12), a barepythonran the global version. That matched the venv only while the global happened to be the venv's version. dtvem now reads the venv'spyvenv.cfgand uses the version it was built from.It picks the version only: dtvem runs its own install of that version, not the venv's interpreter. The project's packages are still available only through an activated venv or
uv run, both of which bypass dtvem's shims as before. Running the venv itself was the other option and is left as a possible follow-up.Type of Change
Related Issues
Resolves #289
Relates to #284, #287
Changes Made
Precedence: same upward walk; the nearest directory wins. Within one directory the order is
.dtvem/runtimes.json, then.tool-versions, then.python-version, and only then.venv/pyvenv.cfg. A venv is inferred, so every declared pin in the same directory beats it. The global version stays the fallback.Reading the version: the
versionkey (python -m venv), elseversion_info(uv). dtvem keeps the leadingmajor.minor[.patch], so3.12.1.final.0→3.12.1and3.13.0rc1→3.13.0.Matching: the exact version if installed, otherwise the highest installed version with the same
major.minor. A venv's compiled packages depend on the minor version, so a venv built from a system or uv-managed 3.12.7 runs on dtvem's 3.12.12 rather than failing.Not installed: if nothing installed shares the
major.minor, the shim reportsPython 3.11 is configured but not installed, names.venv\pyvenv.cfgas the source, and suggestsdtvem install python 3.11.Passed over:
.venvwithoutpyvenv.cfg(not a virtual environment).venvthat is a file (some tools use one to name a virtualenv).venvin the home directoryThe home-directory rule isn't in the issue; I added it. The upward walk passes through
$HOME, and a~/.venv(e.g.python -m venv ~/.venvfor personal tools) is a user-wide environment, not a project's. Without the rule it would silently set the Python version for everything under the home directory, unlike~/.python-version, which a user writes on purpose as a default.Reported: a
pyvenv.cfgwith no usable version, like an empty version file, and a.venvthat exists but can't be read.Code:
internal/config/venv.goholds the venv handling.versionFileRulesgainsvenv, set only for Python.Docs: README feature line,
dtvem current --help, and the CLAUDE.md "Version Resolution" section.Testing
Test Environment
Test Steps
./rnr check: gofmt, golangci-lint (0 issues), and all tests pass.src/internal/config/venv_test.go:pyvenv.cfgparsing:python -m venvand uv formats,versionoverversion_info, release-level and pre-release suffixes, spacing, CRLF,major.minoronly.major.minor, from a subdirectory..venvin one directory, and a nearer.venvbeats a parent.python-version.pyvenv.cfg,.venvas a file,.venvin$HOME, other runtimes.pyvenv.cfgwith no version is reported.python.exe, and ran it with the venv not activated, against real venvs and the real install.Test Results
python(venv not activated)uv venvfrom 3.8.9, run fromsrc/pkg3.8.9(global is 3.12.12)uv venvfrom 3.9.9 (version_info = 3.9.9)3.9.9pyvenv.cfgversion = 3.9.4(not installed)3.9.9, same minorpyvenv.cfgversion = 3.11.9(no 3.11 installed)Set by:.venv\pyvenv.cfg,dtvem install python 3.11, exit 1.python-version3.9in the same folder3.9.9C:\code\agent_c_framework(read-only check; venv made bypython -m venvfrom 3.12.12)3.12.12;dtvem current pythonshows…\agent_c_framework\.venv\pyvenv.cfgas the SourceChecklist
golangci-lint runand fixed all issues (includes gofmt, govet, and 40+ linters)go mod tidyto clean up dependencies (no dependency changes in this PR)go test ./...)Breaking Changes
None intended. In a project whose
.venvwas built from a Python minor version dtvem doesn't have,pythonnow stops with an install hint instead of running the global version.Additional Notes
venv/,env/, Poetry/pipenv central venvs), andVIRTUAL_ENV.python38.zip+python38._pth, noLib\venv), sopython -m venvfails on them withNo module named venv. 3.12.12 is a full build. That's an install/mirror issue (possibly related to pip installation fails for older Python versions (3.8, 3.7) #113), not something this PR touches; the end-to-end test built those venvs with uv instead.