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

开发 后端
对开源项目来说,Makefiles 让代码贡献者知道怎么构建、测试、部署项目。并且,如果你正确使用了 Makefiles,他们可以大大简化你的CI/CD 流程脚本。因为你只需要简单地调用对应的 make 命令就可以了。最重要的是,Makefiles 可以简化你的开发工作。

[[392659]]

本文翻译自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 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

这几段代码写的非常直接,所有潜在贡献者立刻就知道你项目的入口在哪里了。

假设已经有一个虚拟环境了,那么你需要首先激活它,然后再运行 make 命令:

$ . venv/bin/activate 
$ make test 
  • 1.
  • 2.

当然,不方便的地方在于,你的每一个 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 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.

仅从功能上看,这个 Makefile 跟刚才的差不多,但是代码看起来更复杂了。所以我们现在一行一行来看看它是怎么实现的。

如果虚拟环境已经激活,或者pytest, flake8这些包已经安装到了系统 Python 环境里面,那么我们直接调用他们就可以了。但是现在,在新的 Makefile 文件中,我们显式地使用虚拟环境中的绝对路径来调用他们。为了确保虚拟环境存在,每一段代码都依赖于$(VENV)这一项。这一项确保了当前有一个最新的虚拟环境可用。

这种方案有效,是因为当我们执行. venv/bin/activate的时候,本来虚拟环境就是把它自己的绝对路径放到了环境变量里面。因此每一次调用 Python 或者其他包的时候,都是使用虚拟环境中安装的。

虽然 Makefile 文件变得有点复杂了,但是我们要测试代码的时候,还是仅仅需要简单地执行一下命令:

$ make test 
  • 1.

就可以了,我们不需要再去关心虚拟环境是不是已经安装了之类的问题。如果你不需要支持 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公众号。

 

责任编辑:武晓燕 来源: 未闻Code
相关推荐

2021-04-19 23:29:44

MakefilemacOSLinux

2021-04-05 14:47:55

Python多线程事件监控

2024-11-13 09:18:09

2021-09-13 20:38:47

Python链式调用

2021-03-12 21:19:15

Python链式调用

2024-07-30 08:11:16

2024-07-30 08:16:18

Python代码工具

2021-07-27 21:32:57

Python 延迟调用

2021-10-15 21:08:31

PandasExcel对象

2021-04-27 22:15:02

Selenium浏览器爬虫

2021-09-14 21:29:01

项目环境变量

2020-05-19 13:55:38

Python加密密码

2024-02-20 22:13:48

Python项目Java

2023-10-28 12:14:35

爬虫JavaScriptObject

2022-06-28 09:31:44

LinuxmacOS系统

2022-03-12 20:38:14

网页Python测试

2023-10-29 09:16:49

代码安全命令

2022-05-02 16:27:01

JavaScriptHTMLPython

2021-10-03 20:08:29

HTTP2Scrapy

2024-07-19 18:23:17

点赞
收藏

51CTO技术栈公众号