<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Tox on Haseeb Majid</title>
    <link>https://haseebmajid.dev/tags/tox/</link>
    <description>Recent content in Tox on Haseeb Majid</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Mon, 13 Jan 2020 00:00:00 +0000</lastBuildDate><atom:link href="https://haseebmajid.dev/tags/tox/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Using Tox with a Makefile to Automate Python related tasks</title>
      <link>https://haseebmajid.dev/posts/2020-01-13-using-tox-with-a-makefile-to-automate-python-related-tasks/</link>
      <pubDate>Mon, 13 Jan 2020 00:00:00 +0000</pubDate>
      
      <guid>https://haseebmajid.dev/posts/2020-01-13-using-tox-with-a-makefile-to-automate-python-related-tasks/</guid>
      <description>&lt;p&gt;In this article, we will go over how we can use a makefile and tox to automate various Python related tools.
This article assumes you are running bash (or equivalent).&lt;/p&gt;
&lt;h2 id=&#34;tox&#34;&gt;Tox&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://tox.readthedocs.io/en/latest/&#34;&gt;Tox&lt;/a&gt; is an automation tool used primarily to add in testing.
On the Tox website, it describes itself as&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;tox aims to automate and standardize testing in Python. It is part of a larger vision of easing the packaging, testing and release process of Python software.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In this article, we will go over how we can use a makefile and tox to automate various Python related tools.
This article assumes you are running bash (or equivalent).</p>
<h2 id="tox">Tox</h2>
<p><a href="https://tox.readthedocs.io/en/latest/">Tox</a> is an automation tool used primarily to add in testing.
On the Tox website, it describes itself as</p>
<blockquote>
<p>tox aims to automate and standardize testing in Python. It is part of a larger vision of easing the packaging, testing and release process of Python software.</p>
</blockquote>
<p>You define a configuration file <code>tox.ini</code> where you define all of your tox environments. In the example below,we have two environments, <code>testenv</code> to run our tests
and <code>testenv:lint</code> to lint our code with Flake8.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="k">[tox]</span>
</span></span><span class="line"><span class="cl"><span class="na">envlist</span> <span class="o">=</span> <span class="s">py36,py37,lint</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[testenv]</span>
</span></span><span class="line"><span class="cl"><span class="na">basepython</span> <span class="o">=</span><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">    {lint}: {env:TOXPYTHON:python3}
</span></span></span><span class="line"><span class="cl"><span class="s">    py36: {env:TOXPYTHON:python3.6}
</span></span></span><span class="line"><span class="cl"><span class="s">    py37: {env:TOXPYTHON:python3.7}</span>
</span></span><span class="line"><span class="cl"><span class="na">passenv</span> <span class="o">=</span> <span class="s">*</span>
</span></span><span class="line"><span class="cl"><span class="na">install_command</span> <span class="o">=</span> <span class="s">pip install {opts} {packages}</span>
</span></span><span class="line"><span class="cl"><span class="na">deps</span> <span class="o">=</span><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">    pytest
</span></span></span><span class="line"><span class="cl"><span class="s">    pytest-mock</span>
</span></span><span class="line"><span class="cl"><span class="na">usedevelop</span> <span class="o">=</span> <span class="s">false</span>
</span></span><span class="line"><span class="cl"><span class="na">commands</span> <span class="o">=</span> <span class="s">pytest -v {posargs} tests</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[testenv:lint]</span>
</span></span><span class="line"><span class="cl"><span class="na">skip_install</span> <span class="o">=</span> <span class="s">true</span>
</span></span><span class="line"><span class="cl"><span class="na">deps</span> <span class="o">=</span> <span class="s">flake8</span>
</span></span><span class="line"><span class="cl"><span class="na">commands</span> <span class="o">=</span> <span class="s">flake8 src/</span>
</span></span></code></pre></div><p>How Tox works is that it created a virtual environment (virtualenv) for each tox environment defined in the configuration file (<code>tox.ini</code>).
It then runs our command within that virtualenv, you can see these if you take a look in the <code>.tox</code> folder.
So in our lint example, it would create a virtualenv called lint in the .tox folder, install our dependencies <code>flake8</code> and finally run the command
<code>flake8 src/</code> (within the lint virtualenv). You can read more about how Tox works <a href="https://tox.readthedocs.io/en/latest/#system-overview">over here</a>.
So how do we run a tox environment, like so;</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Install Tox</span>
</span></span><span class="line"><span class="cl">pip install tox
</span></span><span class="line"><span class="cl"><span class="c1"># Run the tox environment</span>
</span></span><span class="line"><span class="cl">tox -e lint
</span></span></code></pre></div><p>We can pass extra parameters to tox environments using the <code>{posargs}</code>. So for example, if we had an environment defined as</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="k">[testenv:bumpversion]</span>
</span></span><span class="line"><span class="cl"><span class="na">skip_install</span> <span class="o">=</span> <span class="s">true</span>
</span></span><span class="line"><span class="cl"><span class="na">deps</span> <span class="o">=</span> <span class="s">bumpversion</span>
</span></span><span class="line"><span class="cl"><span class="na">commands</span> <span class="o">=</span> <span class="s">bumpversion --verbose {posargs}</span>
</span></span></code></pre></div><p>We could run it like so <code>tox -e bumpversion -- --allow-dirty patch</code> (note the extra <code>--</code>).</p>
<p>So as you can see Tox allows us to automate tedious Python related tasks such as code formatting, running the lint and running unit tests.
We can test our against using different versions of Python as well such as Python3.6 or Python3.7, to make sure our code is compatible with
both. So if we wanted to run pytest against python3.6 we could do it like so <code>tox -e py36</code> and equally python3.7 as <code>tox -e py37</code>
(given the same configuration file as above). Some common tools Tox is used in conjunction with include;</p>
<ul>
<li><a href="https://github.com/psf/black">Black</a></li>
<li><a href="https://github.com/timothycrosley/isort">Isort</a></li>
<li><a href="https://github.com/timothycrosley/isort">Pytest</a></li>
<li><a href="https://github.com/PyCQA/flake8">Flake8</a></li>
<li><a href="https://github.com/peritus/bumpversion">Bumpversion</a></li>
<li><a href="https://github.com/pypa/twine">Twine</a></li>
</ul>
<h2 id="makefile">Makefile</h2>
<p>Makefiles are often used in C/C++ programs to compile the code/generate binaries etc. Used to automate (often long-winded) tasks.
To use a make file all you need to do is create a file called <code>Makefile</code>. Each &ldquo;job&rdquo; in the makefile is called a <code>target</code>, for
example a makefile may look like so;</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nv">PY</span> <span class="o">=</span> py36
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># prompt_example&gt; make test PY=py36 OPTIONS=&#34;-- -s&#34;
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">test</span>
</span></span><span class="line"><span class="cl"><span class="nf">test</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	@tox -e <span class="k">$(</span>PY<span class="k">)</span> <span class="k">$(</span>OPTIONS<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">lint</span>
</span></span><span class="line"><span class="cl"><span class="nf">lint</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	@tox -e lint
</span></span></code></pre></div><p>So now if we want to run our linter we could simply do <code>make lint</code>, to run our tests we can simply type the command <code>make test</code>.
If we want to specify a Python version we could do <code>make test PY=py37</code> (note how <code>$(PY)</code> is a variable
we can override). This may remind of tools available to other languages such as <code>package.json</code> for JavaScript/NodeJS.
The main advantage of using a Makefile with Tox is that we can define targets in our makefile that aren&rsquo;t specifically
related to Python tools. Such as cleaning our project.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">clean</span>
</span></span><span class="line"><span class="cl"><span class="nf">clean</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	@find . -type f -name <span class="s1">&#39;*.pyc&#39;</span> -delete
</span></span><span class="line"><span class="cl">	@find . -type d -name <span class="s1">&#39;__pycache__&#39;</span> <span class="p">|</span> xargs rm -rf
</span></span><span class="line"><span class="cl">	@find . -type d -name <span class="s1">&#39;*.ropeproject&#39;</span> <span class="p">|</span> xargs rm -rf
</span></span><span class="line"><span class="cl">	@rm -rf build/
</span></span><span class="line"><span class="cl">	@rm -rf dist/
</span></span><span class="line"><span class="cl">	@rm -f src/*.egg*
</span></span><span class="line"><span class="cl">	@rm -f MANIFEST
</span></span><span class="line"><span class="cl">	@rm -rf docs/build/
</span></span><span class="line"><span class="cl">	@rm -f .coverage.*
</span></span></code></pre></div><p>That&rsquo;s is a simple introduction how you can use a <code>Makefile</code> and <code>Tox</code> in conjunction to automate various
tedious tasks.</p>
<h2 id="appendix">Appendix</h2>
<ul>
<li><a href="https://gitlab.com/gitlab-automation-toolkit/gitlab-auto-release/tree/abfdd70e1dae8bacf7dfd999a76711ca052ce23e">Example Project</a></li>
</ul>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
