如何从 setup_require 依赖项覆盖 setuptools 命令?
How can I override a setuptools command from a setup_require dependancy?
上下文:
为了能够在构建时在 setuptools 中将 GNU gettext po 文件转换为 mo 文件,我创建了 setuptools.command.build_py
的子 class 来编译它们(通过 pymsgfmt 的副本) 在调用其基数 class:
之前
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
那我只需要在setup
的cmdclass
参数中声明即可:
setup(
...
cmdclass = {"build_py", mypgk.build_py},
)
到目前为止一切顺利,当我的模块在 setup.py
脚本中安装和导入时,setuptools 的构建阶段正确处理了我的 po 文件。
问题:
目标是允许使用 pip 简单安装源分发。事情看起来不错,因为 pip 会处理任何依赖项,前提是它们在 install_requires
或 setup_requires
参数中声明。这就是先有鸡还是先有蛋的问题:当 setup.py
被 运行 时依赖项被安装,但是如果没有 mypkg
就不能 运行 。
当前研究:
我已经尝试使用魔术 entry_points
在 mypkg
setup.py
脚本中声明 build_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
调用我的覆盖,而 python setup.py build_py
调用 setuptools 版本。
问题:
为什么我用 entry_points
声明覆盖 build_py
命令的尝试不起作用,我该怎么做?
解释问题
我已经接近解决方案了。在对 setuptools
文档和来源进行更多研究后,我终于意识到它已经使用 entry_points
机制来用它自己的命令覆盖 distutils
命令。
这意味着当您尝试覆盖 setuptools
命令时,实际上您建议对同一命令进行第二次覆盖。由于 setuptools
处理它的方式,只使用找到的第一个覆盖,并且根据我的测试,setuptools
一个是第一个。
我现在可以说,正因如此,只有来自 distutils
且未在 setuptools
中被覆盖的命令才能以这种方式处理。好消息是 build
没有被覆盖,在正常使用中,build_py
总是从 build
.
调用
可能的解决方案:
由于 build
命令未被 setuptools
覆盖,因此很容易将其替换为 entry_point
。然后自定义 build
命令 class 可以更新 cmdclass
目录以声明自定义 build_py
class 因为基础 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
class 和一个简单的
就足够了
setup(
...
setup_requires = ["mypkg"],
)
上下文:
为了能够在构建时在 setuptools 中将 GNU gettext po 文件转换为 mo 文件,我创建了 setuptools.command.build_py
的子 class 来编译它们(通过 pymsgfmt 的副本) 在调用其基数 class:
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
那我只需要在setup
的cmdclass
参数中声明即可:
setup(
...
cmdclass = {"build_py", mypgk.build_py},
)
到目前为止一切顺利,当我的模块在 setup.py
脚本中安装和导入时,setuptools 的构建阶段正确处理了我的 po 文件。
问题:
目标是允许使用 pip 简单安装源分发。事情看起来不错,因为 pip 会处理任何依赖项,前提是它们在 install_requires
或 setup_requires
参数中声明。这就是先有鸡还是先有蛋的问题:当 setup.py
被 运行 时依赖项被安装,但是如果没有 mypkg
就不能 运行 。
当前研究:
我已经尝试使用魔术 entry_points
在 mypkg
setup.py
脚本中声明 build_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
调用我的覆盖,而 python setup.py build_py
调用 setuptools 版本。
问题:
为什么我用 entry_points
声明覆盖 build_py
命令的尝试不起作用,我该怎么做?
解释问题
我已经接近解决方案了。在对 setuptools
文档和来源进行更多研究后,我终于意识到它已经使用 entry_points
机制来用它自己的命令覆盖 distutils
命令。
这意味着当您尝试覆盖 setuptools
命令时,实际上您建议对同一命令进行第二次覆盖。由于 setuptools
处理它的方式,只使用找到的第一个覆盖,并且根据我的测试,setuptools
一个是第一个。
我现在可以说,正因如此,只有来自 distutils
且未在 setuptools
中被覆盖的命令才能以这种方式处理。好消息是 build
没有被覆盖,在正常使用中,build_py
总是从 build
.
可能的解决方案:
由于 build
命令未被 setuptools
覆盖,因此很容易将其替换为 entry_point
。然后自定义 build
命令 class 可以更新 cmdclass
目录以声明自定义 build_py
class 因为基础 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
class 和一个简单的
setup(
...
setup_requires = ["mypkg"],
)