Why You Should Add Makefile Into Your Python Project.
5 Min Read
There’s a quote that goes like, “I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it.” by Bill Gates and I think when he mentioned lazy people he also included me in the same pool. You could ask yourself, Why am I saying that about myself. The reason is, over time I have found myself doing the same thing over and over again and I’m sure that you also have been caught in that repetitive loop before you might not be aware of it.
When creating and working on a new Python or related project, I would find myself repeating the same things over and over. For example:
- Creating a Python virtual environment, install all the packages I would need into it and cleaning up Python byte codes and other artefacts.
virtualenv .venv && source .venv/bin/activate && pip install .
- Run code linters and formatters as I develop or before pushing to GitHub.
black -l 90 && isort -rc . && flake8 .
- Running unittests and generating documentation (if any).
pytest -sv . && sphinx-apidoc . -o ./docs -f tests
All the example I’ve listed above assumes you know what shell command to execute and when most times this can be cumbersome or tedious to juniors.
Enter GNU-Make, in this post I will show you how you can leverage the use of
Makefile for automation, ensuring all the goodies are placed in one place and never need to memorise all the shell commands.
When building any programming project leveraging the use of
Makefile’s for tedious work.
Below is an example of a generic
Makefile I have been using. I usually remove parts I do not need and then place it in the root of my project:
make without any targets generates a detailed usage doc. I will not go through the
Makefile as it is well documented and self-explanatory.
$ make python3 -c "$PRINT_HELP_PYSCRIPT" < Makefile Please use `make <target>` where <target> is one of build-image Build docker image from local Dockerfile. build-cached-image Build cached docker image from local Dockerfile. bootstrap Installs development packages, hooks and generate docs for development dist Builds source and wheel package dev Install the package in development mode including all dependencies dev-venv Install the package in development mode including all dependencies inside a virtualenv (container). install Check if package exist, if not install the package venv Create virtualenv environment on local directory. run-in-docker Run example in a docker container clean Remove all build, test, coverage and Python artefacts clean-build Remove build artefacts clean-docs Remove docs/_build artefacts, except PDF and singlehtml clean-pyc Remove Python file artefacts clean-test Remove test and coverage artefacts clean-docker Remove docker image lint Check style with `flake8` and `mypy` checkmake Check Makefile style with `checkmake` formatter Format style with `black` and sort imports with `isort` install-hooks Install `pre-commit-hooks` on local directory [see: https://pre-commit.com] pre-commit Run `pre-commit` on all files coverage Check code coverage quickly with pytest coveralls Upload coverage report to coveralls.io test Run tests quickly with pytest view-coverage View code coverage changelog Generate changelog for current repo complete-docs Generate a complete Sphinx HTML documentation, including API docs. docs Generate a single Sphinx HTML documentation, with limited API docs. pdf-doc Generate a Sphinx PDF documentation, with limited including API docs. (Optional)
In one of my projects here I have an example.
When executed the command above will:
- Build a docker image based on the user and current working directory. eg:
- Download the models that OpenVINO uses for inference.
- Adds current hostname/username to the list allowed to make connections to the X/graphical server and lastly,
- Run the application inside the pre-built docker image.
Further your learning:
If you found this post helpful or unsure about something, leave a comment or reach out @mphomphego
This post was inspired by these posts below: