为什么Python项目中没有用于自动化的Makefile?

36 投票
8 回答
13057 浏览
提问于 2025-04-17 03:15

作为一个长期使用Python的程序员,我一直在想,Python文化中有一个重要的方面我可能一直没理解:我们用什么来代替Makefile?

我见过的大多数Ruby项目(不仅仅是Rails)都使用Rake,而在node.js流行后不久,就出现了cake。在许多其他编程语言中(无论是编译型还是非编译型),都有经典的Make文件。

但是在Python中,似乎没有人需要这样的工具。我随便挑了一些GitHub上的Python项目,除了通过setup.py提供的安装功能外,几乎没有任何自动化的东西。

这背后的原因是什么呢?

难道没有什么需要自动化的事情吗?大多数程序员更喜欢手动运行样式检查、测试等吗?

这里有一些例子:

  • dependencies 用来设置一个虚拟环境并安装依赖包
  • check 调用pep8pylint这些命令行工具。
  • test 任务依赖于dependencies,启用虚拟环境,启动selenium服务器进行集成测试,并调用nosetest
  • coffeescript 任务将所有的CoffeeScript编译成压缩的JavaScript
  • runserver 任务依赖于dependenciescoffeescript
  • deploy 任务依赖于checktest,并进行项目部署。
  • docs 任务调用sphinx并传入适当的参数

其中一些任务可能只有一两行代码,但在我看来,它们加起来还是很有用的。因为有了Makefile,我就不需要记住这些内容。

需要说明的是:我并不是在寻找Python中Rake的替代品。我对paver很满意。我只是想了解背后的原因。

8 个回答

12

Setuptools 可以自动化很多事情,而且对于一些没有内置的功能,它也很容易扩展。

  • 要运行单元测试,你可以在调用 setup() 时添加一个 test_suite 参数,然后使用 setup.py test 命令来执行测试。 (文档)
  • 依赖项(即使在 PyPI 上没有提供)也可以通过在 setup() 调用中添加 install_requiresextras_requiredependency_links 参数来处理。 (文档)
  • 要创建一个 .deb 包,你可以使用 stdeb 模块。
  • 对于其他所有事情,你可以 添加自定义的 setup.py 命令

不过我同意 S.Lott 的看法,大多数你希望自动化的任务(也许除了处理依赖项,这个我觉得真的有用)都是你并不会每天都做的事情,所以自动化这些任务并不会带来真正的效率提升。

20

其实,自动化对Python开发者来说也是非常有用的!

Invoke可能是最接近你想要的工具,它可以帮助你自动化一些常见的、重复的Python任务:https://github.com/pyinvoke/invoke

使用invoke,你可以创建一个像这样的tasks.py文件(这个例子是从invoke的文档中借来的)

from invoke import run, task

@task
def clean(docs=False, bytecode=False, extra=''):
    patterns = ['build']
    if docs:
        patterns.append('docs/_build')
    if bytecode:
        patterns.append('**/*.pyc')
    if extra:
        patterns.append(extra)
    for pattern in patterns:
        run("rm -rf %s" % pattern)

@task
def build(docs=False):
    run("python setup.py build")
    if docs:
        run("sphinx-build docs docs/_build")

然后你可以在命令行中运行这些任务,比如:

$ invoke clean
$ invoke build --docs

另一个选择是直接使用Makefile。比如,一个Python项目的Makefile可能看起来像这样:

docs:
    $(MAKE) -C docs clean
    $(MAKE) -C docs html
    open docs/_build/html/index.html

release: clean
    python setup.py sdist upload

sdist: clean
    python setup.py sdist
    ls -l dist
-3

难道没有什么可以自动化的吗?

其实没有。除了两个例子,其他的都是一行命令。

总结一下:这些内容很少有真正有趣或复杂的地方。很少有地方能从“自动化”中受益。

因为有文档,所以我不需要记住这些命令。

大多数程序员喜欢手动运行样式检查、测试等吗?

是的。

生成文档时,文档任务会用适当的参数调用sphinx。

这只是一行代码。自动化帮助不大。sphinx-build -b html source build/html。这是一个用Python写的脚本。

我们很少这样做。每周几次。通常是在“重大”更改后。

运行样式检查(Pylint、Pyflakes和pep8命令工具)。检查会调用pep8和pylint命令行工具。

我们不这样做。我们使用单元测试,而不是pylint。你可以自动化这个三步流程。

但我能理解SCons或make在这里可能对某些人有帮助。

测试

这里可能有自动化的空间。这是两行命令:非Django单元测试(python test/main.py)和Django测试(manage.py test)。可以自动化运行这两行。

我们每天这样做几十次。我们从来不知道需要“自动化”。

依赖关系设置虚拟环境并安装依赖。

我们很少这样做,所以简单的步骤列表就足够了。我们非常仔细地跟踪依赖关系,因此从来没有意外情况。

我们不这样做。

测试任务依赖于依赖关系,启用虚拟环境,启动selenium-server进行集成测试,并调用nosetest。

start server & run nosetest作为一个两步的“自动化”是有意义的。它可以省去你输入两个命令的麻烦。

coffeescript任务将所有coffeescript编译为压缩的javascript。

这对我们来说是非常少见的。我想这是一个很好的自动化例子。自动化这行脚本可能会有帮助。

我能理解SCons或make在这里可能对某些人有帮助。

runserver任务依赖于依赖关系和coffeescript。

不过,依赖关系变化得很少,这样做似乎有点多余。如果你一开始就没有很好地跟踪依赖关系,这可能是个好主意。

部署任务依赖于检查和测试,并部署项目。

这在服务器上是一个svn copython setup.py install,然后是从子版本区到客户/www区域的一堆客户特定的复制。这是一个用Python写的脚本。

这不是一个通用的make或SCons之类的东西。它只有一个执行者(系统管理员)和一个使用场景。我们绝不会把部署和其他开发、质量保证或测试任务混在一起。

撰写回答