在setup.py或pip需求文件中,如何控制安装包依赖的顺序?
我有一个Python包,它的setup.py文件里通过常规方式声明了依赖关系,也就是在install_requires=[...]里面列出了需要的包。其中有一个包叫scikits.timeseries,它的setup.py文件要求numpy必须先安装。因此,我想找个方法先安装numpy。对于这种情况,或者一般来说,能控制依赖安装的顺序吗?怎么做呢?
目前,setup.py在拉取依赖时(在install_requires参数中列出的那些)似乎顺序是随机的。而且,在setup.py的setup(...)中,我尝试使用了这个参数:
extras_require={'scikits.timeseries': ['numpy']}
...但是没有成功,依赖安装的顺序没有改变。
我还尝试设置了一个pip的需求文件,但在这里,pip安装依赖的顺序也没有按照需求文件中的行顺序来,所以也没成功。
还有一种可能性是在setup.py的开头加一个系统调用,先安装numpy再调用setup(...),但我希望能有更好的方法。提前感谢任何帮助。
4 个回答
这里有一个实际上可以用的解决方案。虽然这个方法不是特别“好用”,但在“绝境中...”也只能这样了。
基本上,你需要:
- 重写setuptools的“安装命令”类(还有一些相关的类)
- 通过命令行语句从脚本中执行pip,这样你可以控制执行的顺序
这样做的缺点是:
- 必须先安装pip。你不能在没有pip的环境中直接执行
setup.py
。 - 最开始安装“前置条件”时的控制台输出出不来,原因有点奇怪。(也许我会在后面更新这里,解决这个问题...)
代码:
from setuptools import setup
# Override standard setuptools commands.
# Enforce the order of dependency installation.
#-------------------------------------------------
PREREQS = [ "ORDERED-INSTALL-PACKAGE" ]
from setuptools.command.install import install
from setuptools.command.develop import develop
from setuptools.command.egg_info import egg_info
def requires( packages ):
from os import system
from sys import executable as PYTHON_PATH
from pkg_resources import require
require( "pip" )
CMD_TMPLT = '"' + PYTHON_PATH + '" -m pip install %s'
for pkg in packages: system( CMD_TMPLT % (pkg,) )
class OrderedInstall( install ):
def run( self ):
requires( PREREQS )
install.run( self )
class OrderedDevelop( develop ):
def run( self ):
requires( PREREQS )
develop.run( self )
class OrderedEggInfo( egg_info ):
def run( self ):
requires( PREREQS )
egg_info.run( self )
CMD_CLASSES = {
"install" : OrderedInstall
, "develop" : OrderedDevelop
, "egg_info": OrderedEggInfo
}
#-------------------------------------------------
setup (
...
install_requires = [ "UNORDERED-INSTALL-PACKAGE" ],
cmdclass = CMD_CLASSES
)
使用 setup_requires
参数,比如在安装 scipy
之前先安装 numpy
,你可以把它放进 setup_requires
中,并添加 __builtins__.__NUMPY_SETUP__ = False
这个钩子,这样就能确保 numpy
正确安装:
setup(
name='test',
version='0.1',
setup_requires=['numpy'],
install_requires=['scipy']
)
def run(self):
__builtins__.__NUMPY_SETUP__ = False
import numpy
如果 scikits.timeseries
这个库需要用到 numpy
,那么它应该在说明中明确指出这一点。这样的话,使用 pip
安装的时候就会自动处理这些依赖关系(我记得 setuptools
也能做到这一点,不过我很久没用过它了)。如果你是 scikits.timeseries
的开发者,那就应该去修正它的依赖声明。