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

36
作为一名长期使用Python的程序员,我想知道一个中心问题:我们在Python文化中没有类似Makefile的东西,这是否有所遗漏?
我看过很多Ruby项目(不仅仅是Rails),它们大多数都使用Rake;在Node.js变得流行后,出现了Cake。在许多其他编译和非编译语言中,都有传统的Make文件。
但在Python中,似乎没有人需要这样的基础设施。我随机选择了GitHub上的Python项目,除了由setup.py提供的安装之外,它们没有任何自动化。
这是为什么呢?是因为没有什么需要自动化的吗?大多数程序员都喜欢手动运行风格检查、测试等吗?
以下是一些例子:
- dependencies设置虚拟环境并安装依赖项。 - check调用pep8和pylint命令行工具。 - test任务依赖于dependencies,启用虚拟环境,为集成测试启动selenium-server,并调用nosetest。 - coffeescript任务将所有coffeescript编译为压缩的javascript。 - runserver任务依赖于dependencies和coffeescript。 - deploy任务依赖于check和test,并部署项目。 - docs任务使用适当的参数调用sphinx。
其中一些只有一两行代码,但在我的看法中,它们会累加起来。由于Makefile的存在,我不必记住它们。
需要澄清的是:我不是在寻找Python中的Rake等价物。我很满意paver。我正在寻找原因。

4
在Python项目中,你会自动化哪些部分? - Dietrich Epp
2
@S.Lott:抱歉,我以为stylecheck是一个常见的术语。我指的是像Pylint、Pyflakes和pep8-cmdtool这样的东西。 - keppla
2
如果你想要制作makefile,那就直接写呗?有什么阻止你的呢? - Jochen Ritzel
2
@S.Lott:抱歉,我以为从上下文中可以清楚地理解为“只有一些”。 - keppla
1
@kappa:还有 Ant、你的 IDE 的自动化功能、bash 脚本等等。我猜没有人觉得有必要重新发明轮子。 - Jochen Ritzel
显示剩余8条评论
8个回答

18

实际上,自动化对Python开发人员也很有用!

Invoke可能是最接近你想要的工具,用于自动化常见重复的Python任务:https://github.com/pyinvoke/invoke

使用invoke,您可以创建像文档中这个tasks.py文件一样的文件:

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可能如下所示:

Another option is to simply use a Makefile. For example, a Python project's Makefile could look like this:

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

问题是为什么他们不去做,而不是“提供说辞来说服项目维护者应该这样做”。 - Kaz
1
你的 Makefile 只有虚假目标(没有声明它们为 .PHONY),这意味着 make 实际上会查找名为 releasedocssdist 的文件是否存在。你的 Makefile 只是一个脚本动作的存储库;它不执行已编译代码库的增量重建(这是 make 的设计目的)。对于不了解 make 的普通 Python 程序员来说,这一切都毫无意义。 - Kaz
在Python中使用Makefile自动化事务是一种常见的方式吗? - St.Antario

12

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

  • 要运行单元测试,可以在setup()函数调用中添加一个test_suite参数后,使用setup.py test命令来运行。 (文档)
  • 即使不在PyPI上可用,也可以通过在setup()函数调用中添加install_requires/extras_require/dependency_links参数来处理依赖性。 (文档)
  • 要创建一个.deb包,可以使用stdeb模块。
  • 对于其他一切,您可以添加自定义的setup.py命令

但是我同意S.Lott的观点,大多数您想要自动化的任务(除了处理依赖项之外,这是我真正有用的唯一任务)都是您不会每天运行的任务,因此没有真正的生产力提升。


5

Python有许多自动化选项。我认为没有反对自动化的文化,只是没有一种主导的方法。通用的工具是distutils

与您描述的最接近的是buildout。这在Zope/Plone世界中被广泛使用。

我自己使用以下组合:Distribute, pipFabric。我主要使用Django进行开发,它有manage.py来进行自动化命令。

Python 3.3也正在积极开发中。


1
我不想暗示反对自动化的文化。"有什么不能自动化的吗?"的意思是"一切都已经自动化了,而我不明白",而不是"只有我这个聪明人才自动化"? - keppla

2
make 工具是一种优化工具,可减少构建软件镜像所需的时间。当先前构建的所有中间材料仍然可用,并且仅对输入(例如源代码)进行了小的更改时,可以获得时间减少。在这种情况下,make 能够执行“增量构建”:仅重新构建受输入更改影响的中间部分。

当进行完整构建时,所有 make 实际上只执行一组脚本步骤。这些相同的步骤可以直接放入一个扁平脚本中。实际上,make-n 选项将打印这些步骤,从而使这种操作成为可能。

Makefile 不是“自动化”,而是“针对优化增量重建的自动化”。任何使用任何脚本工具编写的内容都是自动化。

那么,为什么 Python 项目会避免使用像 make 这样的工具呢?可能是因为 Python 项目不会因为渴望优化而遇到长时间的构建时间。此外,将 .py 编译为 .pyc 文件与将 .c 编译为 .o 文件没有相同的依赖关系。

C 源文件可以包含数百个依赖文件;这些文件中任何一个字符的更改都可能意味着必须重新编译源文件。正确编写的 Makefile 将检测到是否需要重新编译。

如果没有增量构建系统的大型 C 或 C++ 项目将意味着开发人员必须等待几个小时才能进行测试。快速的增量构建是必不可少的。

在 Python 的情况下,可能唯一需要担心的是当一个 .py 文件比其对应的 .pyc 文件更新时,这可以通过简单的脚本处理:循环遍历所有文件,并重新编译任何新于其字节码的文件。此外,编译本身是可选的!

因此,Python 项目通常不使用 make 的原因是它们对执行增量重建优化的需求较低,并且它们使用其他自动化工具;这些工具对 Python 程序员更加熟悉,例如 Python 本身。


2
任何一个不错的测试工具都有一种可以在单个命令中运行整个套件的方式,没有什么阻止你使用rake、make或其他任何工具。当现有方法完全可行时,发明新方法的理由很少——为什么要重新发明某些东西,只是因为你没有发明它?(NIH)。

1
我知道没有什么能阻止我,正如问题所说,我目前正在使用Paver。我很想知道为什么只有少数Python程序员认为需要Make,而在其他社区中许多人似乎都认为需要。 - keppla
那些会的人使用make,或者他们感觉需要的任何其他工具。 - Arafangion

1

可以在这里找到提出此问题的原始PEP。Distutils已成为分发和安装Python模块的标准方法。

为什么呢?因为Python是一种非常适合用来安装Python模块的优秀语言。


1
但是安装并不是我想要自动化的唯一事情,请参见我上面的评论。 - keppla
啊,这种情况下我无法回答你;它超出了我的知识范围。希望有人能提供一些好的理由。 - Lewis Norton

0

-3
有什么不能自动化的吗?
其实没有。除了两个例子外,其他都是一行命令。
简而言之,这些内容很少有真正有趣或复杂的地方。很少有东西需要“自动化”。
由于文档,我不必记住如何执行这些命令。
大多数程序员喜欢手动运行样式检查、测试等吗?
是的。
生成文档,docs任务使用适当的参数调用sphinx。
这只是一行代码。自动化并没有太大帮助。sphinx-build -b html source build/html。那是一个脚本。用Python编写。
我们很少这样做。每周几次。在“重大”更改后。
运行样式检查(Pylint、Pyflakes和pep8-cmdtool)。
我们不这样做。我们使用单元测试代替pylint。你可以自动化这个三步骤的过程。

但我能看出SCons或make如何帮助某人。

测试

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

我们每天都这样做几十次。我们从没意识到我们需要"自动化"。

依赖项设置一个虚拟环境并安装依赖项

这种情况很少发生,我们只需要一个简单的步骤列表就足够了。我们非常仔细地跟踪我们的依赖关系,所以永远不会有任何意外。

我们不这样做。

测试任务依赖于依赖项,启用虚拟环境,为集成测试启动selenium-server,并调用nosetest

启动服务器和运行nosetest作为两个步骤的"自动化"是有道理的。它可以避免您输入运行这两个步骤的两个shell命令。

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

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

我可以看到 SCons 或 make 在这里能够帮助某人。

runserver 任务依赖于 dependencies 和 coffeescript。

除此之外,依赖关系很少发生变化,因此似乎有点过度。如果一开始就没有很好地跟踪依赖关系,那么这可能是一个好主意。

deploy 任务依赖于 check 和 test,并部署项目。

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

它不是一般的 make 或 SCons 类型。它只有一个操作者(系统管理员)和一个用例。我们永远不会将部署与其他开发、QA 或测试任务混合在一起。


所以,与其像Make、Rake、Paver这样为自动化编写单个文件,您更喜欢拥有多个脚本? - keppla
@keppla:是的。我需要时就运行它们。我不知道哪部分需要“自动化”。您能提供一些需要“自动化”的步骤序列或脚本示例吗?我一个接一个地完成它们,从未同时进行两个步骤。从来没有。我不明白你所说的“自动化”。你能提供一些你认为需要“自动化”的示例脚本或步骤序列吗? - S.Lott
我不明白pythonev与不跟踪依赖项有什么关系。我使用它来避免在我的开发系统中产生垃圾,并且因为不同的项目可能具有不同的要求,有时会发生冲突。 - keppla
@keepla: “不要垃圾邮件我的开发系统”?“不同的项目可能有不同的要求”?虽然这些都是真的,但我们似乎没有经常构建环境来证明“自动化”的必要性。它们大多数时间只是静静地存在,已经完全构建好了。不清楚为什么你需要频繁重建它们,以至于自动化能帮助你。 - S.Lott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接