一日一技:为 Python 项目编写 Makefile

本文翻译自Writing Makefiles for Python Projects[1]。日技原作者:Bastian Venthur.
作为 Makefiles的项写粉丝,我几乎在每一个业余项目里面都使用它们。目编并且我也主张在工作项目中使用。日技
对开源项目来说,项写Makefiles 让代码贡献者知道怎么构建、目编测试、日技部署项目。项写并且,目编如果你正确使用了 Makefiles,日技他们可以大大简化你的项写CI/CD 流程脚本。因为你只需要简单地调用对应的目编 make 命令就可以了。最重要的日技是,Makefiles 可以简化你的项写开发工作。
对 Python 项目来说,目编我总是使用虚拟环境,因此我使用了两个不同的 Makefiles 策略:
假设 make 命令是在虚拟环境里面执行的 通过 make 命令来封装虚拟环境的命令假设 make 命令是在虚拟环境中执行的
我们来看一个非常简单的 Makefile 文件,这个文件可以让你实现构建、测试和发布 Python 项目:
all: lint test .PHONY: test test: pytest .PHONY: lint lint: flake8 .PHONY: release release: python3 setup.py sdist bdist_wheel upload clean: find . -type f -name *.pyc -delete find . -type d -name __pycache__ -delete这几段代码写的非常直接,服务器托管所有潜在贡献者立刻就知道你项目的入口在哪里了。
假设已经有一个虚拟环境了,那么你需要首先激活它,然后再运行 make 命令:
$ . venv/bin/activate $ make test当然,不方便的地方在于,你的每一个 shell 窗口都必须手动激活虚拟环境。所以当你使用 tmux 激活一个新的终端窗口或者把 vim 放到后台上去运行的时候,就很麻烦。
在 make 命令里面激活虚拟环境看起来是很难做到的,因为每一段代码甚至每一个命令都会在它自己的 shell 里面运行。但是我们稍后看一个办法绕过这个限制,比如说使用.ONESHELL标志,但这无法解决新开新的代码片段运行在新 shell 的问题。
在 make 命令里面封装虚拟环境的调用命令
第二个方法基本上解决了在 make 命令里面激活虚拟环境的问题。这个办法是从makefile.venv[2]里面学到的,我简化了一下:
# system python interpreter. used only to create virtual environment PY = python3 VENV = venv BIN=$(VENV)/bin # make it work on windows too ifeq ($(OS), Windows_NT) BIN=$(VENV)/Scripts PY=python endif all: lint test $(VENV): requirements.txt requirements-dev.txt setup.py $(PY) -m venv $(VENV) $(BIN)/pip install --upgrade -r requirements.txt $(BIN)/pip install --upgrade -r requirements-dev.txt $(BIN)/pip install -e . touch $(VENV) .PHONY: test test: $(VENV) $(BIN)/pytest .PHONY: lint lint: $(VENV) $(BIN)/flake8 .PHONY: release release: $(VENV) $(BIN)/python setup.py sdist bdist_wheel upload clean: rm -rf $(VENV) find . -type f -name *.pyc -delete find . -type d -name __pycache__ -delete仅从功能上看,这个 Makefile 跟刚才的差不多,IT技术网但是代码看起来更复杂了。所以我们现在一行一行来看看它是怎么实现的。
如果虚拟环境已经激活,或者pytest, flake8这些包已经安装到了系统 Python 环境里面,那么我们直接调用他们就可以了。但是现在,在新的 Makefile 文件中,我们显式地使用虚拟环境中的绝对路径来调用他们。为了确保虚拟环境存在,每一段代码都依赖于$(VENV)这一项。这一项确保了当前有一个最新的虚拟环境可用。
这种方案有效,是因为当我们执行. venv/bin/activate的时候,本来虚拟环境就是把它自己的绝对路径放到了环境变量里面。因此每一次调用 Python 或者其他包的时候,都是使用虚拟环境中安装的。
虽然 Makefile 文件变得有点复杂了,但是我们要测试代码的高防服务器时候,还是仅仅需要简单地执行一下命令:
$ make test就可以了,我们不需要再去关心虚拟环境是不是已经安装了之类的问题。如果你不需要支持 Windows,甚至可以从 Makefile 里面移除Windows 相关的部分。这样一来,这个 Makefile 文件即使对于不怎么用的人来说也不难理解。
哪一种更好?
我觉得第二种方案更方便。虽然第一种方法我已经快乐地用了几年了,而第二种方法是最近才学到的。之前我确实没有注意到这种方法。但我注意到几乎所有使用 Makefile的 Python 项目都用的第一种方法,我也想知道为什么。
Kingname 点评
我在Python 项目和Golang 项目里面经常使用Makefile,其中,Python 项目我主要用来删除__pycache__,而 Golang 项目中,由于我使用的是 VSCode 来开发,它的 lint 有点问题,所以代码写完以后,我会使用 Makefile 来执行一段gofmt命令,把所有.go文件都格式化。
但 Makefile 有一个非常智障的地方——它里面的缩进必须使用制表符,不能使用空格。所以要写Makefile 的时候,我还必须用 vim 来写。因为我的 PyCharm 已经调成把所有制表符换成空格的设置了。而如果在 Makefile 的缩进里面混入了空格,它就会报错。
如果大家对 Makefile 有兴趣的话,我给大家写一篇从入门到精通的文章。有兴趣的同学请留言~
参考资料
[1]Writing Makefiles for Python Projects: https://venthur.de/2021-03-31-python-makefiles.html
[2]makefile.venv: https://github.com/sio/Makefile.venv
本文转载自微信公众号「未闻Code」,可以通过以下二维码关注。转载本文请联系未闻Code公众号。

本文地址:http://www.bzuk.cn/news/018c31499667.html
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。