如何从setup_require依赖项覆盖setuptools命令?

时间:2018-11-26 09:49:56

标签: python override setuptools

上下文:

为了能够在建立时在setuptools中将GNU gettext po文件转换为mo文件,我创建了setuptools.command.build_py的子类,该子类在调用基类之前(通过pymsgfmt的副本)对其进行编译:

from setuptools.command.build_py import build_py as _build_py

class build_py(_build_py):
    parent = _build_py
    def run(self):
        self.compile_po_files()  # internal implementation
        self.parent.run(self)

    def get_outputs(self):  # overriden to produce a correct list of installed files
        build_mo = self.get_finalized_command("build_mo")
        return _build_py.get_outputs(self) + self.outputs

然后我只需要在cmdclass的{​​{1}}参数中声明它:

setup

到目前为止,很好,当在setup( ... cmdclass = {"build_py", mypgk.build_py}, ) 脚本中安装并导入我的模块时,setuptools的构建阶段可以正确处理我的po文件。

问题:

目标是允许使用pip简单安装源代码发行版。事情看起来不错,因为pip可以处理任何依赖项,只要它们在setup.pyinstall_requires参数中声明即可。这就是鸡和鸡蛋的问题所在:运行setup_requires时会安装依赖项,但是如果不首先安装setup.py则无法运行依赖项。

当前研究:

我尝试使用魔术mypkgentry_points build_py脚本中声明mypkg覆盖:

setup.py

但是它没有任何作用,尽管我可以这样声明一个有效的新... entry_points = { "distutils.commands": [ "build_py = mypkg:build_py", ], } 命令:

build_mo

长话短说,entry_points = { "distutils.commands": [ "build_mo = mypkg:build_py", ], } 调用我的替代,而python setup.py build_mo调用setuptools版本。

问题:

为什么用python setup.py build_py声明覆盖build_py命令的尝试无效,怎么办?

1 个答案:

答案 0 :(得分:0)

解释问题

我接近解决方案。经过setuptools文档和资料的进一步研究后,我终于意识到它已经使用entry_points机制来用自己的命令覆盖distutils命令。

这意味着当您尝试覆盖setuptools命令时,实际上您建议对同一命令进行第二次覆盖。由于setuptools的处理方式,仅使用找到的第一个替代,而根据我的测试,setuptools就是第一个替代。

我现在可以说,因此,只能以这种方式处理distutils中未被覆盖的来自setuptools的命令。好消息是build没有被覆盖,在正常使用中,总是从build_py调用build

可能的解决方案:

由于build不会覆盖setuptools命令,因此很容易用entry_point替换它。然后,自定义build命令类可以更新cmdclass目录以声明自定义build_py类,因为基类build会加载它。该代码可以是:

from distutils.command.build import build as _build

class build(_build):
    parent = _build
    def run(self):
        self.distribution.cmdclass["build_py"] = build_py
        self.parent.run(self)

在我的测试中,只需简单地使setuptools使用自定义build_py类即可

setup(
    ...
    setup_requires = ["mypkg"],
)