Lyth: Better be safe than sorry
Published: 2020-02-17 21:19:16

The most immediate mistake young and unskilled coyotes make, at the very beginning of each episode, is to believe they can match the Road Runner. They start running after them, get ready for the fray too early, and after a while, they run out of gas, stunned.

## First failure

It seems that even hobby projects do require a bit of QA. *Never mind what test cases provide!* I first thought. As an enthusiastic runner I swooped hungrily on my project and started implementing the wonderful <a href="https://ruslanspivak.com/lsbasi-part1/">series</a> on how to implement a basic interpreter with Python.

Then came the bug... The lexer never caught properly the following expression:
```
let:
  a := 1 + 2
```
Was it the analyzer? Did it come from the tokens? or even the scanner? Damn! Why the indent was not retrieved properly? After many clutches and hacks, I had to come to terms with this: The project stopped, and that Road Runner escaped, sticking out defiantly its tongue. Meep! Meep!

What is the most frustrating part in this story is to consider how many times the Coyote fails because it did not test its tools first...

## A Python package tool

Ok, ok so my silly project needs some harness. And now that I am unpacking my recent acquisition comprising a <a href="https://flake8.pycqa.org/en/latest/">linter</a> and <a href="https://docs.pytest.org/en/latest/">a test framework</a>, why not doing things right, and follow the instructions on <a href="https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-test-matrix">ACME's blueprint by Ionel Cristian Mărieș</a>?

![Boom, haha!](http://4.bp.blogspot.com/-k5_6IKGYF7Y/T9aZZCmqVkI/AAAAAAAAAW8/FLiUzsHmmIQ/s1600/beepbeep+(24).jpg)

To get an out of the box python package <a href="https://cookiecutter-pylib.readthedocs.io/en/latest/">cookie cutter</a> comes to the rescue. Package templates are available <a href="https://github.com/audreyr/cookiecutter-pypackage">here.</a>. Please do not ask why, I chose this <a href="https://github.com/ionelmc/cookiecutter-pylibrary">one</a>, because well, it comes from <a href="https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-test-matrix">Ionel's blog</a>.

## Packaging Lyth

The instructions are clear and pretty straightforward. We first need cookiecutter installed on the machine, we provide it the target github template we desire, we answer a couple of questions. I chose the following set of tools:

```
pytest
Travic-CI
Coveralls
flake8
```

Executing `tox` went smoothly. I only had to <a href="https://github.com/new">create</a> a new empty project. By empty, I guess, do not check the README option, no .gitignore as well, and no license.

And then, the steps were quite similar to what was instructed:
```
git init .
git add .
git commit -m "Add initial project skeleton"
git remote add origin https://github.com/$USERNAME/$PROJECTNAME.git
git push -u origin master
```

## Polishing badges

At that point, we get man shiny badges, most of them shaming you, the build fails, there is no coverage at all etc. etc. So, to get this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nbp31beku36igoynh9e8.png)

I had to register everywhere and link my repository to my accounts:
1. <a href="https://travis-ci.org/profile">Travis CI</a>
2. <a href="https://coveralls.io/repos/new">Coveralls</a>
3. <a href="https://readthedocs.org/dashboard/import/">Read the docs</a>
4. <a href="https://pypi.org/">Pypi</a> to publish my work!
5. And even <a href="https://dev.to/">here</a> to write my reports.
6. If you need a doi, and want your work to be tracked, you could even use <a href="https://zenodo.org/">Zenodo</a>. I am too shy for this.

So much fun for today, but is my project a burden on Mother Nature? I mean, any time I `git push` I have now a bunch of small workers contributing to global warming, basically testing, keeping track of code coverage, building documentation, publishing and so on... Sorry polar cubs...

## All set up?

So, definitely, this will not guarantee you will catch the Road Runner, but it will raise your confidence next time you ride a rocket, you will not end up in some cactus... Outch!

![All setup](https://media.tenor.com/images/9b68d1052047354340a751827879f2de/tenor.gif)

## A couple of caveats 

### Unicode issue in .readthedocs.yml

I got an error with .readthedocs.yml, and had to remove the last lines, `path: .`. It did not bother `tox` on my local machine, nor it hurt Read the docs from building the documentation.

### Added .readthedocs.yml to MANIFEST.in

I got issues with `tox -e docs` and thought adding .readthedocs.yml could ease the problem:
```
include tox.ini .travis.yml .appveyor.yml .readthedocs.yml
```

### NoInterpreterFound for docs

`tox -e docs` kept failing, and I found that issue tricky, it seems, that in `tox.ini`, adding the missing `docs` helps it find the right Python interpreter to complete (successfully) its objective:
```
[testenv]
basepython =
    py37: {env:TOXPYTHON:python3.7}
    {bootstrap,clean,check,docs,report,codecov,coveralls}: {env:TOXPYTHON:python3}
```
Do not forget to have `docs` included.

### Improving coverage in template __main__.py

When running a test for pytest, it is practically almost impossible entering in:
```
if __name__ == '__main__':
```
of ` __main__.py` file. Consequently, coverage reports that the corresponding couple of lines are not covered. I added into my `.coveragerc` file `exclude_lines`:
```
[report]
show_missing = true
precision = 2
omit = *migrations*
exclude_lines =
    if __name__ == .__main__.:
```
 And made the promise I will **NEVER EVER** write any code in that section.

### setup.py

I removed the versions of Python I did not want to use. As I use a lot of <a href="https://realpython.com/python-f-strings/">f-strings</a>, Travis CI will report failure with Python < 3.7.
I also removed the unwanted python versions in `tox.ini`.

### Read the docs

It is correctly said in Ionel's cookie cutter template, but it was very important to do these extra steps. Go to read the docs, open your repository, and go to admin:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5z10yp7nx0daj07hsdem.png)

You need to check the box regarding virtualenv via `setup.py install`, specify the `docs/requirements.txt`to make the build run smoothly
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ln5blb4wpfnf5migf0ur.png)
 and excuse my French.

### bumpversion and Windows

Are not good friends... I needed to use <a href="https://pypi.org/project/bump2version/">bump2version</a> instead.

So keep in mind that now changing version of project requires this small `2`, otherwise, bumpversion will scr*** your project on Windows. Oh, and do not forget to **commit first**, otherwise it will complain the repository is **messy**

1. `bump2version patch` to increase version from 1.0.0 to 1.0.1.
2. `bump2version minor` to increase version from 1.0.0 to 1.1.0.
3. `bump2version major` to increase version from 1.0.0 to 2.0.0.

## Publishing

I dump here the set of commands I used to publish as I guess I will have to write a script later to automate this process:

```
rm -rf build
rm -rf src/*.egg-info
tox -e check
tox
python setup.py clean --all sdist bdist_wheel
twine upload --skip-existing dist/*.whl dist/*.gz
```

Tada! That makes this, an empty project that burnt a lot of CO2...
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0koj7egi2qg0gtya0p0t.png)

## Pending issues

I am still unsatisfied with the recipe, but using `bump2version` and pushing to repository may lead to temporary broken badges, because github cannot compare the new version (as it expects it to be a branch) to master.

So the thing I did so far, and that may be dead wrong, is to go to github, create a branch named the new version generated by `bump2version`, that is present in `setup.py` and that is on `Pypi`, and then push to master. There is nothing to compare indeed, but read the docs does not complain about a broken link, and I guess it is the essentials.