pip 需求文件格式(requirements.txt)完整指南:语法、选项与源码解析
【免费下载链接】pipThe Python package installer项目地址: https://gitcode.com/gh_mirrors/pi/pip
导读:需求文件(requirements file)是 pip 安装依赖的核心载体,pip install通过它批量读取要安装的项目清单。本文基于 pip 官方文档 requirements-file-format.md 展开,结合 req_file.py 解析器源码与对应测试,系统讲解需求文件的六种行形式、编码与注释规则、支持的全局/单需求选项、-r/-c文件引用以及环境变量展开,帮助读者写出可维护、可复现、可安全校验的 requirements 文件。
一、什么是需求文件
需求文件是 pip 在执行pip install时使用的一份"待安装项目清单"。使用该格式的文件通常命名为requirements.txt——但命名不是强制要求,任何采用该格式的文件都可以传给 pip。
在 pip_install.rst 中,-r(--requirement)参数即用于从文件中读取需求;需求文件格式与 pip 内部细节(例如命令行选项)紧密相关:
- 基础语法相对稳定且可移植;
- 但完整语法仅面向 pip 消费,其他工具在复用时应谨慎评估兼容性。
这一点在官方文档中以 note 形式特别声明,也是编写需求文件时需要记住的前提:以本格式为准、以 pip 的实际解析行为为准。
二、完整示例与逐行解读
官方文档给出了一个覆盖全部核心语法的最小示例,逐行拆解如下:
# 以 # 开头的行是注释,会被忽略 pytest pytest-cov beautifulsoup4 # 这里支持的语法与 requirement specifier 相同 docopt == 0.6.1 requests [security] >= 2.8.1, == 2.8.* ; python_version < "2.7" urllib3 @ https://github.com/urllib3/urllib3/archive/refs/tags/1.26.8.zip # 可以引用其他需求文件或约束文件 -r other-requirements.txt -c constraints.txt # 可以引用本地发行版文件路径 ./downloads/numpy-1.9.2-cp34-none-win32.whl # 可以引用 URL http://wxpython.org/Phoenix/snapshot-builds/wxPython_Phoenix-3.0.3.dev1820+49a8884-cp34-none-win_amd64.whl各部分的含义:
| 行内容 | 含义 |
|---|---|
pytest | 纯项目名,安装最新可用版本 |
docopt == 0.6.1 | 版本约束(精确指定版本) |
requests [security] >= 2.8.1, == 2.8.* ; python_version < "2.7" | extras + 版本约束 + 环境标记(environment marker) |
urllib3 @ https://...zip | 直接 URL 引用形式(name @ url) |
-r other-requirements.txt | 嵌套引用另一个需求文件 |
-c constraints.txt | 引用一个约束文件 |
./downloads/...whl | 本地 wheel 包路径 |
http://...whl | 远程 wheel 包 URL |
注意示例中有两处细节值得强调:
-c与-r的区别:-r引入的文件中每个项目都会被安装;-c引入的约束文件只限制版本、不触发安装(详见下文第五节)。- shell 引用的差异:在需求文件里不要给 specifier 加引号(与命令行不同)。唯一的例外是 2015 年 5 月的 pip 7.0/7.0.1,那两个版本要求含环境标记的 specifier 必须加引号,此后的版本均已取消该要求。
关于 requirement specifier 的完整语法(name-based 与 URL-based 两种形式、extras、版本说明符、环境标记等),可参考同目录下的 requirement-specifiers.md。
三、文件结构:六种受支持的行形式
需求文件的每一行都表示一个要安装的项,或一条传给pip install的参数。官方文档列出的受支持形式包括:
[[--option]...]—— 仅由命令行选项构成的行(例如--pre、--no-index)<requirement specifier>—— 需求说明符(项目名 + 可选版本约束等)<archive url/path>—— 归档包(wheel / sdist)的 URL 或本地路径[-e] <local project path>—— 本地项目路径,可加-e以可编辑模式安装[-e] <vcs project url>—— 版本控制仓库(Git、Mercurial、Subversion、Bazaar)的 URL,可加-e
这些形式对应源码解析器src/pip/_internal/req/req_file.py中的行处理逻辑:每一行先被拆分为"参数部分(args)"与"选项部分(options)"。break_args_options(req_file.py)按第一个以-或--开头的 token 为界拆分——它只对选项部分做 shlex 分词,参数部分原样保留,因为参数中可能包含会被 shlex 破坏的环境标记。
四、编码规则
需求文件的默认编码是UTF-8,除非通过 PEP 263 风格的注释指定其他编码:
# -*- coding: <encoding name> -*-从源码看,编码识别做了三层处理(req_file.py):
- BOM 探测:按优先级依次匹配 UTF-8、UTF-32、UTF-32-BE/LE、UTF-16、UTF-16-BE/LE 的 BOM(req_file.py)。源码注释特别提示:
BOM_UTF16_LE是BOM_UTF32_LE的前缀,因此 UTF-32 必须排在 UTF-16 之前判断。 - PEP 263 声明:检查文件前两行中以
#开头的行里是否存在coding[:=]\s*([-\w.]+)形式的编码声明。 - 兜底 UTF-8:以上均未命中时按 UTF-8 解码;若解码失败,会回退到区域设置(locale)编码,并打印一条警告日志,提示使用者应显式添加 PEP 263 编码注释。
五、行延续(Line Continuation)
以未转义的\结尾的行会被视为行延续,其后的换行符被忽略,前后两行拼接为一行:
--config-settings build_option=--with-x \ --config-settings other=value pkgname从实现看,join_lines(req_file.py)在拼接时以第一行的行号作为拼接结果的行号,并且只处理不以\结尾的普通行;注释行(以#开头)不会触发延续拼接。
六、注释规则
- 以
#开头的行整体视为注释并被忽略; - 行内空白符后出现的
#,会将#及其后的内容视为注释; - 注释的剔除发生在行延续处理之后(源码
preprocess顺序为join_lines→ignore_comments→expand_env_variables,见 req_file.py)。
这带来一个值得注意的行为:如果#出现在行首之后、但前面没有空白符(例如拼接后的行中间),COMMENT_RE = r"(^|\s+)#.*$"(req_file.py)要求#前必须是行首或空白符才被当作注释起点。单元测试 tests/unit/test_req_file.py 中的test_strip_comment("req # comment")即验证了这一"空白符 + #"的剥离行为。
七、支持的选项
需求文件只支持一部分pip install选项,并非所有命令行选项都可写入。选项分为两类。
7.1 全局选项(Global Options)
以下选项作用于整个pip install运行过程,且必须单独占一行。官方文档通过pip-requirements-file-options-ref-list指令动态列出,结合源码 req_file.py 中SUPPORTED_OPTIONS的定义,实际支持集合为:
| 选项 | 作用 |
|---|---|
--index-url | 指定包索引源 |
--extra-index-url | 附加包索引源(可多次) |
--no-index | 忽略索引源,仅用本地/链接源 |
--constraints/-c | 引用约束文件 |
--requirements/-r | 引用其他需求文件 |
--editable/-e | 可编辑安装本地/VCS 项目 |
--find-links | 额外查找链接位置(可多次) |
--no-binary | 禁止使用二进制发行版 |
--only-binary | 只允许二进制发行版 |
--prefer-binary | 优先选用旧版 wheel |
--require-hashes | 启用哈希校验模式 |
--no-require-hashes | 关闭哈希校验 |
--pre | 允许安装预发布版本 |
--all-releases | 允许所有发行版(含预发布) |
--only-final | 仅允许正式版本 |
--trusted-host | 标记受信任主机 |
--use-new-feature | 启用新特性(预览) |
官方示例——同时指定--pre、--no-index和两个--find-links:
--pre --no-index --find-links /my/local/archives --find-links http://some.archives.com/archives从源码handle_option_line(req_file.py)可见这些选项的底层影响路径:
--no-index/--index-url/--extra-index-url/--find-links会被合并重建SearchScope,直接改写PackageFinder的搜索范围;--find-links若给定的是相对路径且相对于需求文件目录存在,会先转换为相对需求文件目录的绝对路径;--pre会被转换为--all-releases :all:语义写入ReleaseControl;--prefer-binary调用finder.set_prefer_binary();--trusted-host会把主机加入 session 的受信任列表,并记录来源为"某文件第几行"。
7.2 每需求选项(Per-requirement Options)
自 pip 7.0 起支持。
作用于单个需求行的选项只有两个(req_file.py):
--config-settings(即 PEP 517 构建配置设置):可附加在单个需求行上,为该需求的构建指定配置;--hash:配合哈希校验模式使用,为该需求指定期望的哈希值。
两者都可针对普通需求行使用;--config-settings还可用于-e可编辑行(SUPPORTED_OPTIONS_EDITABLE_REQ仅含config_settings)。
源码层面,SUPPORTED_OPTIONS_REQ对应的 dest 值(hash、config_settings)会被提取到该行的ParsedRequirement.options中(req_file.py),随单个需求生效;而全局选项作用于整次安装。handle_line(req_file.py)明确指出:含需求的行上,只有SUPPORTED_OPTIONS_REQ生效,其他选项被忽略;不含需求的行上反之。
哈希校验模式(Hash-Checking Mode)的完整说明见 user_guide.rst 对应章节,典型用法是让 pip 根据文件中的哈希值逐一校验下载包,校验失败即报错,保障供应链安全。
八、引用其他需求文件与约束文件
需求文件可以嵌套引用其他文件:
-r more_requirements.txt也可以引用约束文件(constraints file):
-c some_constraints.txt约束文件是需求文件的一个子集:语法与需求文件相同,但只控制某个包被安装时的版本,不决定它是否被安装——把某个包写进约束文件不会触发它的安装。同时约束文件有几类语法不允许:必须包含项目名、不能是可编辑安装、不能指定 extras。命令行用法为python -m pip install -c constraints.txt(详见 user_guide.rst 的 "Constraints Files" 小节)。
源码对嵌套引用的处理(req_file.py)值得注意:
- 相对路径解析:当外层文件是普通路径时,嵌套文件路径会基于外层文件所在目录做
os.path.join后再abspath规范化;当外层文件本身是http(s)://URL 时,则用urllib.parse.urljoin拼接,使相对 URL 也能正确解析。 - 递归引用检测:解析器维护一个已解析文件栈,若发现某个文件被递归引用(文件引用自身或形成引用环),会抛出
RequirementsFileParseError,提示"<path> recursively references itself in <file>"。 - 文件来源追踪:每个需求行的
comes_from都会记录为"-r 文件名 (行号)"或"-c 文件名 (行号)",这在pip freeze、卸载和安装报告中追溯依赖来源时非常有用。
九、使用环境变量
自 pip 10.0 起支持。
需求文件支持环境变量展开,但只认 POSIX 格式的${大写变量名}:
${API_TOKEN}pip 在运行时会去宿主机环境中查找同名变量并替换。约束条件:
- 变量名必须为大写字母、数字和下划线(
[A-Z0-9_]+),遵循 POSIX 标准(IEEE Std 1003.1, 2013 Edition); - 不支持
$VARIABLE或%VARIABLE%等其他展开语法; - 若变量未定义(
os.getenv返回空),则保持原样不展开(req_file.py)。
源码中对应的正则ENV_VAR_RE = r"(?P<var>\$\{(?P<name>[A-Z0-9_]+)\})"(req_file.py),展开发生在注释剔除之后。
这样做的两个设计动机(源码注释中明确说明):
- 避免字符串中出现的
$被误展开; - 保证不同平台(Windows / Unix)间需求文件行为一致。
实际用途:将 Token、密钥等敏感信息放在环境变量中,需求文件里只写变量名,运行时由 pip 查值。这与常见的 12-factor 配置模式(把配置注入环境)保持一致,例如:
# 私有索引需要认证的场景 --index-url https://${PRIVATE_INDEX_USER}:${PRIVATE_INDEX_TOKEN}@pypi.example.com/simple注意:环境变量展开同样适用于 URL 片段,因此可以安全地把凭证从文件里剥离出去,避免把密钥提交进版本库。
十、从源码看解析全流程
将文档中的语法规则对应到源码执行顺序,一个需求文件的完整处理链路是:
- 读取文件:
get_file_content(req_file.py)支持普通路径、file://URL 与http(s)://URL(后者通过PipSession拉取);随后按第五节所述进行 BOM / PEP 263 / UTF-8 解码。 - 预处理(
preprocess,req_file.py):join_lines(行延续拼接)→ignore_comments(剔除注释、过滤空行)→expand_env_variables(环境变量展开)。 - 逐行解析:每行先经
break_args_options拆分为参数与选项,再用build_parser构建的、仅含SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ的 optparse 解析器解析选项(req_file.py);解析失败会包装为OptionParsingError再转成RequirementsFileParseError,并附上出错的原始行文本。 - 递归处理:遇到
-r/-c行则递归解析嵌套文件并做循环检测。 - 生成需求:
handle_line区分需求行(产出ParsedRequirement)与纯选项行(更新PackageFinder/ session 状态)。
对应地,tests/unit/test_req_file.py 中的test_comments_and_joins_case1/2/3、test_ignore_comment、test_strip_comment等用例直接验证了注释与拼接的交互规则,可以作为阅读解析行为的入口。
十一、实践建议与常见坑
结合上述语法与源码行为,编写需求文件时建议留意以下几点:
- 区分
-r与-c:需求文件中的包会被安装;约束文件只锁版本。多层引用时保持两者语义清晰,避免用-c引入的文件意外漏装依赖。 - 避免引用环:
-r互相引用会触发RequirementsFileParseError;用相对路径引用时注意目录层级,善用"相对需求文件目录"的解析规则。 - 选项行单独成行:全局选项必须独占一行,且每行只放一个选项(源码实现支持多选项但文档约定为单选项),便于阅读与调试。
- 哈希校验与敏感信息:对不可变版本建议启用
--require-hashes+ 每行--hash提升供应链安全性;认证凭证一律走${ENV_VAR}而非明文。 - 编码声明:文件含非 UTF-8 内容时,务必在首行或次行加 PEP 263 编码注释,否则会回退到区域设置编码并产生警告日志。
- 不要加 shell 引号:需求文件内的 specifier 不加引号,只有命令行中因 shell 解释才需要引号包裹
>、<或环境标记。
需求文件格式是 pip 生态中被引用最广泛的接口之一,理解其语法边界(哪些选项可用、哪些不可用)与解析行为,能帮助你写出既稳定又可审计的依赖管理配置。
【免费下载链接】pipThe Python package installer项目地址: https://gitcode.com/gh_mirrors/pi/pip
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考