如何使用distutils或setuptools API安装distutils包

2 投票
3 回答
1802 浏览
提问于 2025-04-15 14:18

我正在写一个脚本,目的是在远程服务器上安装一个叫做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。

所以,我有几个解决方案。

  1. 在远程服务器上使用easy_install安装zc.buildout。我对这个选项一点都不喜欢,因为它为一个不太重要的模块做了特殊处理。

  2. 修改zerokspot.recipe.distutils,在'import zc.buildout'周围加一个try块,这样即使zc.buildout没有安装也能安装。这是一个可以接受的解决方案,但有点像是临时拼凑的。

  3. 用代码替代子进程,使用distutils API或setuptools API来安装这个包。在我看来,这是最好的解决方案。

我的问题是,如何实现第三个方案呢?

谢谢,
Taras

PS:我通过创建一个不依赖于zc.buildout的新包解决了这个问题。我的包叫做 taras.recipe.distutils,可以在pypi上找到。

3 个回答

0

你确定你不想直接生成一个 bdist 吗?

1

zerokspot.recipe.distutils 这个东西本身就有问题,因为它在 setup.py 里加了对 zc.buildout 的依赖,具体情况如下:

  1. setup.pyzerokspot.recipe.distutils 里引入了 get_version
  2. 整个 zerokspot.recipe.distutils 都是在它的 __init__.py 里定义的,包括 get_version
  3. zerokspot.recipe.distutils__init__.py 又引入了 zc.buildout

我不明白作者为什么要定义 get_version; 按照最佳实践,应该在 setup.py 里简单写个版本号,让 setuptools 来处理开发版本(通过 setup.cfg),而 distutils 则用来提取版本信息。

一般来说,在 setup.py 里引入整个包并不是个好主意,因为这会要求在安装时所有的包依赖都必须存在。显然,这个包的作者把 zc.buildout 安装成了全局包,没注意到这个问题。

你最好的办法是去 GitHub 上复制这个包,去掉 get_version 的依赖,然后把这个修改提给原作者,同时自己使用你复制的版本。

1

你可以在你的Python程序中使用subprocess模块来调用命令行程序:

import subprocess
subprocess.call('python setup.py install')

不过,你对这个安装程序运行的环境有多少控制权呢?如果这是一个你要分发的包,不管别人提出什么解决方案,你可能都会遇到问题。比如,如何处理需要管理员权限的情况(例如,sudo python setup.py install)?

你可以考虑看看Paver,因为它提供的API在某种程度上是对setuptools的扩展。

撰写回答