- This chapter is part of the series:
- This tutorial builds upon the project structure from Chapter 3 and Chapter 4. I suggest understanding Chapter 3 and Chapter 4 before moving forward in order to understand the project structure.
- Chapter 3:
- Chapter 4:
 
- 
So far, this is the structure of our code. 
 - src/ - something/ - __init__.py - py.typed - app.py - tests/ - __init__.py - conftest.py - test_app.py - .gitignore - LICENSE - pyproject.toml - README.md - requirements.txt - setup.cfg - setup.py
- 
Table of contents:
5.1 The Need for Tox
- The code so far has run on our local environment.
- How do we know that the code runs on multiple environments? Since we are building packages, we should know which versions of python can install our package and run it.
- This is where Toxcomes in. To work withToxwe need atox.inifile which isTox's own configuration file.
- 
Let’s consider the following tox.inifile in the root directory of the project.
 [tox] minversion = 3.8.0 envlist = py36, py37, py38, py39, flake8, mypy isolated_build = true [gh-actions] python = 3.6: py36, mypy, flake8 3.7: py37 3.8: py38 3.9: py39 [testenv] setenv = PYTHONPATH = {toxinidir} deps = -r{toxinidir}/requirements_dev.txt commands = pytest --basetemp={envtmpdir} [testenv:flake8] basepython = python3.6 deps = flake8 commands = flake8 src tests [testenv:mypy] basepython = python3.6 deps = -r{toxinidir}/requirements_dev.txt commands = mypy src
- To read more about - toxfile structure, we can read: https://tox.wiki/en/latest/config.html.
5.2 Understanding the Tox environments and variables
- We can read about all of this from [tox.wiki](http://tox.wiki), https://tox.wiki/en/latest/config.html.
- 
All global settings are defined in the [tox]section. In our case,
 [tox] minversion = 3.8.0 envlist = py36, py37, py38, py39, flake8, mypy isolated_build = true- 
minversionis the minimum version oftox-libraryrequired to parse thistoxfile.- 
3.8.0is the minimum version oftox-libraryrequired to parse thistoxfile.
 
- 
- 
envlistis for determining the environment list thattoxis to operate on and so on.
- There are many other global setting variables that are available in the tox.wikiwebsite. We do not need to understand everything as of now.
 
- 
- 
Test environments are defined under the testenvsection and individualtestenv:NAMEsections, whereNAMEis the name of a specific environment. This section also has a lot of options to set. For our case, we will go through:- 
basepython: Name or path to a Python interpreter which will be used for creating the virtual environment.
- 
deps: Environment dependencies. Installed usually from requirements file or manually written.
- 
commands: The commands to be called for testing. Only execute if[commands_pre](https://tox.wiki/en/latest/config.html#conf-commands_pre)succeeds.commands_preis another option we have not talked about.
- 
setenv: Each line contains a NAME=VALUE environment variable setting which will be used for all test command invocations.
 
- 
- 
We might also notice {toxinidir}which is a variable inbuilt intox. We can learning more about changing its working directory: https://stackoverflow.com/questions/52503796/change-tox-workdir.- For now, we just need to understand that: from tox global settingssection fromtoxdocumentation, the.toxdirectory which is working dir, is created in directory wheretox.iniis located.
- Turns out toxalso creates a working directory just likegitdoes.
 
- For now, we just need to understand that: from 
- 
We also have {envtmpdir}which is another variable inbuilt intox.- 
{envdir}basically points to thevirtualenvdirectory thattoxcreates.
- If we do {envdir}/tmpit points to thetmpdirectory inside thevirtualenv.
- This is what {envtmpdir}points to. Basically{envtmpdir} = {envdir}/tmp.
- It will be cleared each time before the group of test commands is invoked. In our case, we have three group of test commands: a [test]which is inbuilt intoxand twotest:NAMEwhich are our custom test groups.
- There are other similar variables: {envlogdir}={envdir/log}. It defines a directory for logging wheretoxwill put logs oftool invocation.
 
- 
- tox-gh-actionsis a- toxplugin which helps running- toxon- GitHub Actionswith multiple different- Python versionson multiple workers in parallel.
5.3 Understanding the flow of Tox environments
- 
Toxallows us to create a bunch of differentvirtual environments,installourpackageinto thoseenvironmentsand then run thetest groupson each of thoseenvironments.
- 
The first four py36, py37, py38, py39,arebuilt-inversions ofpythonthattoxalready knows about.
 [tox] minversion = 3.8.0 envlist = py36, py37, py38, py39, flake8, mypy isolated_build = true
- 
Their configuration goes in the testenvblock and the tests are run in those environments with the following commands.
 [testenv] setenv = PYTHONPATH = {toxinidir} deps = -r{toxinidir}/requirements_dev.txt commands = pytest --basetemp={envtmpdir}- We set the PYTHONPATHto{toxinidir}. From the previous section we know it equals toPYTHONPATH=<top level of project directory>. Since, we knowtoxinidirpoints to wherever thetox.inifile is located. In our case, it is located at the top level of the project directory.
- As you can see, in testenv, we have setdeps=-r{toxinidir}/requirements_dev.txt. From the previous section we know it equals todeps=-r <project_directory>/requirements_dev.txt. Since, we knowtoxinidirpoints to wherever thetox.inifile is located. In our case, it is located at the top level of the project directory.
- We install the requirements and then run the pytest --basetemp=<virtualenv>/tmpcommand in all of the environments passed along. Since, we know that{envtmpdir}points to<virtualenv>/tmpdirectory.
 
- We set the 
- 
Then we have the last two environments: flake8,mypy.
 [tox] minversion = 3.8.0 envlist = py36, py37, py38, py39, flake8, mypy isolated_build = true
- 
flake8andmypyare notbuilt-inenvironments intox. Therefore, we have to create separatetestenv:NAMEblock for them. Which is why we added:
 [testenv:flake8] basepython = python3.6 deps = flake8 commands = flake8 src tests [testenv:mypy] basepython = python3.6 deps = -r{toxinidir}/requirements_dev.txt commands = mypy src
- Here, - testenv:flake8is the- flake8virtual environment and- testenv:mypyis the- mypyvirtual environment.
- Since - flake8and- mypyare not versions of python and only commands that we want to run, we need to specify which version of python we want to run on. We do this on- basepython.
- depsagain are all the dependencies. We can specify individual dependencies or we can specify the requirements file.
- commandsis the actual command that runs in these blocks.
- We also have, - gh-actionsblock which we will discuss in the next chapter.
5.4 Executing TOX
- Once we have the tox.inifile and thetoxcommand.
- To get the toxcommand,pip install tox.
- 
We can now just run the toxcommand and everything will be automated.
 $ tox
- 
When we run it, we notice that it takes very long. Why is that? - When we run the tests locally, it runs on our virtual environment.
- But like we discussed, toxcreates a new virtual environment, install everything into that and run tests in all of those environments.
 
- It is advised to run - toxonly before commit and push. Otherwise, just use- pytest, to save time during development.
 

 
     
    
Top comments (0)