我有一个我正在使用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
另一个parse_requirements黑客也将环境标记解析为extras_require:
from collections import defaultdict
from pip.req import parse_requirements
requirements = []
extras = defaultdict(list)
for r in parse_requirements('requirements.txt', session='hack'):
if r.markers:
extras[':' + str(r.markers)].append(str(r.req))
else:
requirements.append(str(r.req))
setup(
...,
install_requires=requirements,
extras_require=extras
)
它应该同时支持sdist和binary dist。
正如其他人所说,parse_requirements有几个缺点,所以这不是您在公共项目中应该做的,但对于内部/个人项目可能足够了。
另一个可能的解决方案……
def gather_requirements(top_path=None):
"""Captures requirements from repo.
Expected file format is: requirements[-_]<optional-extras>.txt
For example:
pip install -e .[foo]
Would require:
requirements-foo.txt
or
requirements_foo.txt
"""
from pip.download import PipSession
from pip.req import parse_requirements
import re
session = PipSession()
top_path = top_path or os.path.realpath(os.getcwd())
extras = {}
for filepath in tree(top_path):
filename = os.path.basename(filepath)
basename, ext = os.path.splitext(filename)
if ext == '.txt' and basename.startswith('requirements'):
if filename == 'requirements.txt':
extra_name = 'requirements'
else:
_, extra_name = re.split(r'[-_]', basename, 1)
if extra_name:
reqs = [str(ir.req) for ir in parse_requirements(filepath, session=session)]
extras.setdefault(extra_name, []).extend(reqs)
all_reqs = set()
for key, values in extras.items():
all_reqs.update(values)
extras['all'] = list(all_reqs)
return extras
然后使用…
reqs = gather_requirements()
install_reqs = reqs.pop('requirements', [])
test_reqs = reqs.pop('test', [])
...
setup(
...
'install_requires': install_reqs,
'test_requires': test_reqs,
'extras_require': reqs,
...
)
你可以把它翻转过来,在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
)