自定义distutils命令

27 投票
4 回答
17284 浏览
提问于 2025-04-15 15:52

我有一个叫“example”的库,我想把它安装到我的全局包目录里。不过,我希望能安装两个版本,一个用于生产环境,另一个用于测试(因为我有一个网页应用和其他一些东西是这样管理版本的)。

有没有办法可以指定,比如说“python setup.py stage”,这样不仅可以把不同的版本安装到包目录里,还能把模块的名字从“example”改成“example_stage”或者类似的名字呢?

如果distutils做不到这个,还有其他工具可以实现吗?

4 个回答

5

如果你想使用多个版本的东西,可以试试 virtualenvvirtualenvwrapper,这两个工具会很有帮助。

56

这可以通过在setup.py文件中继承distutils.core.Command来轻松实现。

举个例子:

from distutils.core import setup, Command
import os, sys

class CleanCommand(Command):
    description = "custom clean command that forcefully removes dist/build directories"
    user_options = []
    def initialize_options(self):
        self.cwd = None
    def finalize_options(self):
        self.cwd = os.getcwd()
    def run(self):
        assert os.getcwd() == self.cwd, 'Must be in package root: %s' % self.cwd
        os.system('rm -rf ./build ./dist')  

要启用这个命令,你必须在setup()中引用它:

setup(
     # stuff omitted for conciseness.
     cmdclass={
        'clean': CleanCommand
}

注意,你也可以通过这种方式覆盖内置命令,比如我对'clean'做的修改。(我不喜欢内置版本留下的'dist'和'build'目录。)

% python setup.py --help-commands | grep clean
  clean            custom clean command that forcefully removes dist/build dirs.

这里有一些常用的约定:

  • 你可以通过user_options来指定任何命令行参数。
  • 你可以用initialize_options()方法声明你会用到的变量,这个方法在初始化后被调用,用来设置你自定义的命名空间。
  • finalize_options()方法在run()之前被调用。
  • 命令的主要内容会在run()中执行,所以确保在那之前做好其他准备工作。

最好的例子就是查看默认命令的源代码,比如在PYTHON_DIR/distutils/command目录下的install.pybuild.py

14

当然,你可以通过新的命令来扩展distutils。在你的distutils配置文件中,添加以下内容:

 [global]
 command-packages=foo.bar

这个配置可以放在distutils.cfg文件中,或者放在你家目录下的..pydistutils.cfg(在Windows上不要加点),或者放在当前目录的setup.cfg文件中。

接下来,你需要在Python的site-packages目录下创建一个名为foo.bar的包。

然后在这个包里,你需要添加实现你想要的新命令的类,比如stage,这个类要继承自distutils.cmd。虽然文档不太详细,但有很多例子,因为所有现有的distutils命令都是这样构建的。

撰写回答