如何使用distutils或setuptools API安装distutils包
我正在写一个脚本,目的是在远程服务器上安装一个叫做distutils的包。
在PyPi上,有两个方法可以做到这一点,分别是 collective.recipe.distutils 0.1 和 zerokspot.recipe.distutils 0.1.1。
后者是前者的改进版,使用起来稍微方便一点,但它们都有一个共同的问题,我接下来会说明。
当执行bootstrap.py时,它会下载zc.buildout这个包,并把它放到buildout的蛋目录里。这让./bin/buildout可以访问zc.buildout的代码,但此时/usr/local/python并不知道zc.buildout的存在。
Buildout尝试通过在一个子进程中运行'python setup.py install'来安装这个包。这会导致一个ImportError,因为/usr/local/python并没有安装zc.buildout。
所以,我有几个解决方案。
在远程服务器上使用easy_install安装zc.buildout。我对这个选项一点都不喜欢,因为它为一个不太重要的模块做了特殊处理。
修改zerokspot.recipe.distutils,在'import zc.buildout'周围加一个try块,这样即使zc.buildout没有安装也能安装。这是一个可以接受的解决方案,但有点像是临时拼凑的。
用代码替代子进程,使用distutils API或setuptools API来安装这个包。在我看来,这是最好的解决方案。
我的问题是,如何实现第三个方案呢?
谢谢,
Taras
PS:我通过创建一个不依赖于zc.buildout的新包解决了这个问题。我的包叫做 taras.recipe.distutils,可以在pypi上找到。
3 个回答
你确定你不想直接生成一个 bdist 吗?
zerokspot.recipe.distutils 这个东西本身就有问题,因为它在 setup.py 里加了对 zc.buildout 的依赖,具体情况如下:
setup.py
从zerokspot.recipe.distutils
里引入了get_version
- 整个
zerokspot.recipe.distutils
都是在它的__init__.py
里定义的,包括get_version
zerokspot.recipe.distutils
的__init__.py
又引入了zc.buildout
我不明白作者为什么要定义 get_version
; 按照最佳实践,应该在 setup.py
里简单写个版本号,让 setuptools 来处理开发版本(通过 setup.cfg
),而 distutils 则用来提取版本信息。
一般来说,在 setup.py
里引入整个包并不是个好主意,因为这会要求在安装时所有的包依赖都必须存在。显然,这个包的作者把 zc.buildout 安装成了全局包,没注意到这个问题。
你最好的办法是去 GitHub 上复制这个包,去掉 get_version
的依赖,然后把这个修改提给原作者,同时自己使用你复制的版本。
你可以在你的Python程序中使用subprocess模块来调用命令行程序:
import subprocess
subprocess.call('python setup.py install')
不过,你对这个安装程序运行的环境有多少控制权呢?如果这是一个你要分发的包,不管别人提出什么解决方案,你可能都会遇到问题。比如,如何处理需要管理员权限的情况(例如,sudo python setup.py install)?
你可以考虑看看Paver,因为它提供的API在某种程度上是对setuptools的扩展。