这单来自一个很典型的 macOS + zsh 场景:用户按 pip 文档把 pip completion --zsh 追加进 ~/.zprofile 后,开启新 shell 会直接报错 command not found: compdef,自动补全也无法使用。
- Issue: pypa/pip#12738
- PR: pypa/pip#13805
🔍 分析 (Analyze)
compdef 由 zsh 的 completion system(compinit)提供;而 ~/.zprofile 会在 login shell 启动时先于 ~/.zshrc 执行。很多用户是在 ~/.zshrc 里初始化 compinit,因此把 pip 的 completion 脚本放进 ~/.zprofile 时,就会在 compinit 尚未运行的阶段触发 compdef,导致启动报错。
这个问题的本质不是 pip completion 逻辑本身,而是“脚本运行时机”和“依赖的 zsh completion 基础设施”之间没有对齐。
📍 定位 (Locate)
- completion 输出:
src/pip/_internal/commands/completion.py - 文档指引:
docs/html/user_guide.rst(Command Completion 章节) - 回归测试:
tests/functional/test_completion.py
🛠️ 执行 (Execute)
- 在 zsh completion 输出里增加保护逻辑:当交互式 shell 下
compdef不可用时,先autoload -Uz compinit && compinit; - 只有在
compdef可用时才执行compdef __pip ...注册(避免继续抛错); - 同步更新文档:把 zsh 的安装指引从
~/.zprofile调整为~/.zshrc,并补一句compinit的前置要求; - 更新对应功能测试的期望片段,并添加 NEWS fragment(bugfix)。
✅ 总结 (Summary)
这一改动的目标是把“按文档配置就报错”的坑填平:不要求用户了解 zsh 启动顺序细节,也尽量避免在不合适的时机硬调用 compdef。对最终用户来说,结果就是新 shell 不再出现 compdef not found,而且补全更稳定。