我有一个我正在使用Travis-CI的requirements.txt文件。在requirements.txt和setup.py中复制需求似乎很愚蠢,所以我希望在setuptools.setup中传递一个文件句柄给install_requires kwarg。

这可能吗?如果是,我该怎么做呢?

这是我的requirements.txt文件:

guessit>=0.5.2
tvdb_api>=1.8.2
hachoir-metadata>=1.3.3
hachoir-core>=1.3.3
hachoir-parser>=1.3.4

当前回答

交叉张贴我从这个SO问题的答案,另一个简单的,pip版本证明解决方案。

try:  # for pip >= 10
    from pip._internal.req import parse_requirements
    from pip._internal.download import PipSession
except ImportError:  # for pip <= 9.0.3
    from pip.req import parse_requirements
    from pip.download import PipSession

requirements = parse_requirements(os.path.join(os.path.dirname(__file__), 'requirements.txt'), session=PipSession())

if __name__ == '__main__':
    setup(
        ...
        install_requires=[str(requirement.req) for requirement in requirements],
        ...
    )

然后把所有的需求放在项目根目录下的requirements.txt下。

其他回答

使用parse_requirements是有问题的,因为pip API没有公开的文档和支持。在pip 1.6中,该函数实际上是移动的,因此对它的现有使用可能会中断。

消除setup.py和requirements.txt之间重复的一个更可靠的方法是在setup.py中指定你的依赖项,然后输入-e。到requirements.txt文件中。关于为什么这是一种更好的方式,来自pip开发人员的一些信息可以在这里找到:https://caremad.io/blog/setup-vs-requirement/

小心parse_requirements行为!

请注意,pip.req。Parse_requirements将把下划线改为破折号。这件事让我生气了几天,后来我才发现。示例演示:

from pip.req import parse_requirements  # tested with v.1.4.1

reqs = '''
example_with_underscores
example-with-dashes
'''

with open('requirements.txt', 'w') as f:
    f.write(reqs)

req_deps = parse_requirements('requirements.txt')
result = [str(ir.req) for ir in req_deps if ir.req is not None]
print result

生产

['example-with-underscores', 'example-with-dashes']

交叉张贴我从这个SO问题的答案,另一个简单的,pip版本证明解决方案。

try:  # for pip >= 10
    from pip._internal.req import parse_requirements
    from pip._internal.download import PipSession
except ImportError:  # for pip <= 9.0.3
    from pip.req import parse_requirements
    from pip.download import PipSession

requirements = parse_requirements(os.path.join(os.path.dirname(__file__), 'requirements.txt'), session=PipSession())

if __name__ == '__main__':
    setup(
        ...
        install_requires=[str(requirement.req) for requirement in requirements],
        ...
    )

然后把所有的需求放在项目根目录下的requirements.txt下。

上面的大多数其他答案都不能与当前版本的pip API一起使用。下面是使用pip当前版本(撰写本文时为6.0.8,在7.1.2中也有效)的正确*方法。您可以使用pip -V检查您的版本。

from pip.req import parse_requirements
from pip.download import PipSession

install_reqs = parse_requirements(<requirements_path>, session=PipSession())

reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
    ....
)

正确,因为这是当前pip使用parse_requirements的方式。这仍然可能不是最好的方法,因为正如上面的帖子所说,pip并没有真正维护API。

你可以把它翻转过来,在setup.py中列出依赖项,并只有一个字符——一个点。-在requirements.txt中。


或者,即使不建议,仍然可以使用以下hack(用pip 9.0.1测试)解析requirements.txt文件(如果它没有通过URL引用任何外部需求):

install_reqs = parse_requirements('requirements.txt', session='hack')

但是这并不能过滤环境标记。


在pip的旧版本中,特别是6.0以上的版本中,可以使用一个公共API来实现这一点。需求文件可以包含注释(#),也可以包含一些其他文件(——requirement或-r)。因此,如果你真的想解析一个requirements.txt文件,你可以使用pip解析器:

from pip.req import parse_requirements

# parse_requirements() returns generator of pip.req.InstallRequirement objects
install_reqs = parse_requirements(<requirements_path>)

# reqs is a list of requirement
# e.g. ['django==1.5.1', 'mezzanine==1.4.6']
reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
)