I can't seem to wrap my head around managing Python versions. When I run tox
, I can immediately see that it's using Python 3.7.9:
$ tox
py39: commands[0]> coverage run -m pytest
================================================================================== test session starts ==================================================================================
platform darwin -- Python 3.7.9, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 -- /usr/local/bin/python3
But it's configured to use 3.9:
[tox]
envlist = py39,manifest,check-formatting,lint
skipsdist = True
usedevelop = True
indexserver =
spotify = https://artifactory.spotify.net/artifactory/api/pypi/pypi/simple
[testenv]
basepython = python3.9
deps =
:spotify:-r{toxinidir}/dev-requirements.txt
commands =
coverage run -m pytest {posargs}
allowlist_externals = coverage
[testenv:manifest]
; a safety check for source distributions
basepython = python3.9
deps = check-manifest
skip_install = true
commands = check-manifest
Here's what I see with which
:
$ pyenv local 3.9.10
$ which python
/Users/acheong/.pyenv/shims/python
$ which python3
/Library/Frameworks/Python.framework/Versions/3.7/bin/python3
$ pyenv which python
/Users/acheong/.pyenv/versions/3.9.10/bin/python
pytest
also uses the wrong version:
$ pytest tests
================================================================================== test session starts ==================================================================================
platform darwin -- Python 3.7.9, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 -- /Library/Frameworks/Python.framework/Versions/3.7/bin/python3
cachedir: .pytest_cache
rootdir: /Users/acheong/src/spotify/protean/ezmode-cli, configfile: tox.ini, testpaths: tests
plugins: mock-3.10.0, cov-2.10.0
But in this case I learned I can do this:
$ pyenv exec pytest tests
================================================================================== test session starts ==================================================================================
platform darwin -- Python 3.9.10, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 -- /Users/acheong/.pyenv/versions/3.9.10/bin/python
cachedir: .pytest_cache
rootdir: /Users/acheong/src/spotify/protean/ezmode-cli, configfile: tox.ini, testpaths: tests
plugins: mock-3.10.0, cov-2.10.0
But when I try that with tox
, I get an error:
$ pyenv exec tox
Traceback (most recent call last):
File "/Users/acheong/.pyenv/versions/3.9.10/bin/tox", line 8, in <module>
sys.exit(run())
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/tox/run.py", line 19, in run
result = main(sys.argv[1:] if args is None else args)
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/tox/run.py", line 38, in main
state = setup_state(args)
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/tox/run.py", line 53, in setup_state
options = get_options(*args)
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/tox/config/cli/parse.py", line 38, in get_options
guess_verbosity, log_handler, source = _get_base(args)
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/tox/config/cli/parse.py", line 61, in _get_base
MANAGER.load_plugins(source.path)
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/tox/plugin/manager.py", line 90, in load_plugins
self._register_plugins(inline)
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/tox/plugin/manager.py", line 38, in _register_plugins
self.manager.load_setuptools_entrypoints(NAME)
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/pluggy/_manager.py", line 287, in load_setuptools_entrypoints
plugin = ep.load()
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/importlib/metadata.py", line 77, in load
module = import_module(match.group('module'))
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 850, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/tox_pyenv.py", line 48, in <module>
from tox import hookimpl as tox_hookimpl
ImportError: cannot import name 'hookimpl' from 'tox' (/Users/acheong/.pyenv/versions/3.9.10/lib/python3.9/site-packages/tox/__init__.py)
I've tried a lot of things I found online but I'm afraid if anything I've only messed up my environment even more. What steps can I take to diagnose the problem and get tox
to use my pyenv
version?
Although this is an old question and it has already been marked as solved, I dare to give another answer since this post appears on the first page of Google search results of the "tox pyenv" query.
As already noted, tox-pyenv
is not compatible with tox
version 4. Moreover, tox
no longer discovers Python executables by itself, this job is now delegated to virtualenv
. That being said, a special tox
plugin like tox-pyenv
is no longer needed, the discovery machinery is extended via virtualenv
plugins, not tox
plugins. Here is an explanation in the tox-pyenv
issues, and here is a more detailed migration guide.
For those who don't want to configure virtualenv
and are looking for a simpler solution, there is another tox
plugin — tox-pyenv-redux (not related to tox-pyenv
). It is compatible with tox
4, uses virtualenv-pyenv
under the hood, and does not require any configuration to work (though, it has a configuration setting).