Hello!
I use Python’s tox
to orchestrate a lot of my tests. It lets you set a list of versions in a tox.ini
file (in the same directory as your setup.py
), like this:
[tox] envlist = py37, py38 [testenv] allowlist_externals = echo commands = echo "success"
Then you can run the tox
command, it’ll create a venv
for each version, and run your tests in each of those environments. It’s an easy way to ensure your code works across all the versions of Python you want to support.
But, if I install tox
into a 3.8 environment and run the tox
command in the directory where we created the tox.ini
above, I get this:
tox GLOB sdist-make: /Users/adam/Local/fiddle/setup.py py37 create: /Users/adam/Local/fiddle/.tox/py37 ERROR: InterpreterNotFound: python3.7 py38 create: /Users/adam/Local/fiddle/.tox/py38 py38 inst: /Users/adam/Local/fiddle/.tox/.tmp/package/1/example-0.0.0.zip py38 installed: example @ file:///Users/adam/Local/fiddle/.tox/.tmp/package/1/example-0.0.0.zip py38 run-test-pre: PYTHONHASHSEED='2325607949' py38 run-test: commands[0] | echo success success ___________________________________________________________________________ summary ____________________________________________________________________________ ERROR: py37: InterpreterNotFound: python3.7 py38: commands succeeded
It found the 3.8 interpreter I ran it with, but it couldn’t find 3.7.
pyenv
can get you past this. It’s a utility for installing and switching between multiple Python versions. I use it on OS X (⬅️ instructions to get set up, if you’re not already). Here’s how it looks when I have Python 3.6, 3.7, and 3.8 installed, and I’m using 3.8:
pyenv versions system 3.6.11 3.7.9 * 3.8.5 (set by /Users/adam/.pyenv/version)
Just having those versions installed isn’t enough, though. You still get the error from tox
about missing versions. You have to specifically enable each version:
pyenv local 3.8.5 3.7.9 pyenv versions system 3.6.11 * 3.7.9 (set by /Users/adam/Local/fiddle/.python-version) * 3.8.5 (set by /Users/adam/Local/fiddle/.python-version)
This will create a .python-version
file in the current directory that sets your Python versions. pyenv
will read that file whenever you’re in that directory. You can also set versions that’ll be picked up in any folder with the pyenv global
command.
Now, tox
will pick up both versions:
tox GLOB sdist-make: /Users/adam/Local/fiddle/setup.py py37 inst-nodeps: /Users/adam/Local/fiddle/.tox/.tmp/package/1/example-0.0.0.zip py37 installed: example @ file:///Users/adam/Local/fiddle/.tox/.tmp/package/1/example-0.0.0.zip py37 run-test-pre: PYTHONHASHSEED='1664367937' py37 run-test: commands[0] | echo success success py38 inst-nodeps: /Users/adam/Local/fiddle/.tox/.tmp/package/1/example-0.0.0.zip py38 installed: example @ file:///Users/adam/Local/fiddle/.tox/.tmp/package/1/example-0.0.0.zip py38 run-test-pre: PYTHONHASHSEED='1664367937' py38 run-test: commands[0] | echo success success ___________________________________________________________________________ summary ____________________________________________________________________________ py37: commands succeeded py38: commands succeeded congratulations :)
That’s it! Now you can run your tests in as many verions of Python as you need.
Happy testing,
Adam
Need more than just this article? We’re available to consult.
You might also want to check out these related articles: