为什么Python项目中没有用于自动化的Makefile?
作为一个长期使用Python的程序员,我一直在想,Python文化中有一个重要的方面我可能一直没理解:我们用什么来代替Makefile?
我见过的大多数Ruby项目(不仅仅是Rails)都使用Rake,而在node.js流行后不久,就出现了cake。在许多其他编程语言中(无论是编译型还是非编译型),都有经典的Make文件。
但是在Python中,似乎没有人需要这样的工具。我随便挑了一些GitHub上的Python项目,除了通过setup.py
提供的安装功能外,几乎没有任何自动化的东西。
这背后的原因是什么呢?
难道没有什么需要自动化的事情吗?大多数程序员更喜欢手动运行样式检查、测试等吗?
这里有一些例子:
dependencies
用来设置一个虚拟环境并安装依赖包check
调用pep8
和pylint
这些命令行工具。test
任务依赖于dependencies
,启用虚拟环境,启动selenium服务器进行集成测试,并调用nosetest
coffeescript
任务将所有的CoffeeScript编译成压缩的JavaScriptrunserver
任务依赖于dependencies
和coffeescript
deploy
任务依赖于check
和test
,并进行项目部署。docs
任务调用sphinx并传入适当的参数
其中一些任务可能只有一两行代码,但在我看来,它们加起来还是很有用的。因为有了Makefile,我就不需要记住这些内容。
需要说明的是:我并不是在寻找Python中Rake的替代品。我对paver很满意。我只是想了解背后的原因。
8 个回答
Setuptools
可以自动化很多事情,而且对于一些没有内置的功能,它也很容易扩展。
- 要运行单元测试,你可以在调用
setup()
时添加一个test_suite
参数,然后使用setup.py test
命令来执行测试。 (文档) - 依赖项(即使在 PyPI 上没有提供)也可以通过在
setup()
调用中添加install_requires
、extras_require
或dependency_links
参数来处理。 (文档) - 要创建一个
.deb
包,你可以使用stdeb
模块。 - 对于其他所有事情,你可以 添加自定义的 setup.py 命令。
不过我同意 S.Lott
的看法,大多数你希望自动化的任务(也许除了处理依赖项,这个我觉得真的有用)都是你并不会每天都做的事情,所以自动化这些任务并不会带来真正的效率提升。
其实,自动化对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
难道没有什么可以自动化的吗?
其实没有。除了两个例子,其他的都是一行命令。
总结一下:这些内容很少有真正有趣或复杂的地方。很少有地方能从“自动化”中受益。
因为有文档,所以我不需要记住这些命令。
大多数程序员喜欢手动运行样式检查、测试等吗?
是的。
生成文档时,文档任务会用适当的参数调用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 co
和python setup.py install
,然后是从子版本区到客户/www
区域的一堆客户特定的复制。这是一个用Python写的脚本。
这不是一个通用的make或SCons之类的东西。它只有一个执行者(系统管理员)和一个使用场景。我们绝不会把部署和其他开发、质量保证或测试任务混在一起。