Using Makefiles in Python projects

Cameron Simpson cs at cskk.id.au
Thu Nov 7 17:41:31 EST 2019


On 07Nov2019 22:20, Vitaly Potyarkin <sio.wtf at gmail.com> wrote:
>What do you think of using Makefiles for automating common chores in
>Python projects? Like linting, type checking and testing?

I do use one for some things. (Not linting, which I'll describe lower 
down.)

I do like to use it for what make's strength is: running actions based 
on updated files, but there are a few "action" targets too.

Here's a slightly edited and trimmed excerpt from a Makefile (well, 
Mykefile, but the intent and syntax are very similar) from a current 
project:

    venv_dir = $./venv
    venv_reqs = requirements.txt
    venv_pip = $(venv_dir)/bin/pip

    py_static_bundle = $(py_app)/static/app.js

    fleet_dev = [ "$$HOST" = fleet -a "$$USER" = cameron ]

    _help:
            @echo '_build: make $(py_static_bundle)'
            @echo '_deploy_tip: formally deploy the current tip to the dev host dev tree:'
            @echo '_sync_dev: rsync the current working files into the dev tip tree'

    _build:
            make $(py_static_bundle)

    _venv:
            :make $(venv_dir)

    $(venv_dir):    $(venv_reqs)
            python3 -m venv $(venv_dir)
            $(venv_pip) install -U pip
            $(venv_pip) install -U -r $(venv_reqs)

    $(py_static_bundle): $(app_js)
            env-dev browserify -t [ babelify --presets [ react ] ] $? >$@

    _sync_dev:
            $(fleet_dev) || { echo "not cameron at fleet, refusing to rsync" >&2; exit 1; }
            :make $(py_static_bundle)
            $(sync_src(target_dev_host:releases/tip))

Things to note:

"Virtual targets" are actions rather than result files, and start with 
an underscore.

The default target is _help, which recites a description of the other 
targets.

The _venv target makes the venv directory if missing, and that runs 
python3 -m venv and then pip to do the required packages.

There's a traditional make rule i.e. an action based on a dependent 
file, gosh! for the static bundle (javascript compiled into a single 
file).

You'll see that _sync_dev has a leading sanity check: it won't run 
unless I'm me on my personal machine; avoids accidents. This is 
important because it isn't running the formal deploy script, which 
builds a clean versioned tree at the far end, instead it just rsyncs my 
local code into a "live" dev tree at the far end. Obviously that is a 
very personal hack.

>I've come up with a reusable Makefile for automating virtual 
>environment
>management in Python projects. I think it can be useful for simplifying
>the onboarding of new developers (both new to project and new to Python)
>and for documenting project's development practices.

These are laudable goals. I like the expose the dev practices in 
particular.

>Here it is:
>- Repo: https://github.com/sio/Makefile.venv
>- Demo screencast: https://asciinema.org/a/279646
>
>What do you think? Is this useful or I'm just unaware of some tool that
>abstracts venv chores away better?

There may be other tools.

Linting can be personal. In my current team we have varying lint habits 
among the devs. OTOH a common "required lint before release" could be 
useful, covering off the project lint standards if they exist.

I lint by hand, with 2 main levels of automation:

1: I have a personal "lint" script with runs my preferred linters with 
my preferred options, so I can just say "lint filenames..." and have it 
do the right thing. It is also multilanguage: python linters, shell 
linters, etc.

2: I have a few VCS related shell functions. One is named "lint". With 
arguments is invokes the above lint script directly. _Without_ arguments 
it lints the "modified" (== changed and not committed) files. So I can 
just say "lint" and it lints my changes, not all the files.

Cheers,
Cameron Simpson <cs at cskk.id.au>


More information about the Python-list mailing list