pip 装完包 Flask 就起不来:我把虚拟环境和依赖冲突理了一遍
上周给单位那套 Flask 监控脚本加个导出 Excel 的功能,顺手 pip install openpyxl。装得很顺利,第二天早上脚本起不来了,报 ImportError: cannot import name 'escape' from 'flask'。
我当时第一反应是 Flask 坏了,于是 pip install --upgrade flask,结果又冒出来 Jinja2 的版本警告。折腾了半个多小时,最后发现问题根本不在 Flask 身上。
先别急着重装,先搞清楚你在用哪个 Python
这台 Windows 机器上装着三四个 Python:系统装的 3.12、WorkBuddy 带的 3.13、还有几个项目各自建的 venv。我平时在命令行里敲的 pip,装到了哪个环境里,其实我自己都不确定。
所以第一步永远是确认:
where python
where pip
python -c "import sys; print(sys.executable)"
python -c "import sys; print(sys.executable)" 这一条最实在,它直接告诉你当前这个解释器是哪个可执行文件,不用猜 PATH 谁排在前面。
还有个坑:PowerShell 里 where 是 Where-Object 的别名,得写 where.exe python,不然命令静默没输出,你会以为没装 Python。
确认完解释器之后,养成一个习惯:永远用 python -m pip install xxx,不要直接 pip install xxx。前者能保证包装到你当前这个 python 底下,后者装到 PATH 里第一个 pip 所属的环境,两者经常不是一回事。
看看冲突到底在哪
我这个报错表面是 Flask 的问题,实际上是某个包把 Jinja2 顶上去了,Flask 版本和新 Jinja2 对不上。
pip check
这条会直接列出不满足的依赖要求,输出很干净。想看得更细就上 pipdeptree:
python -m pip install pipdeptree
python -m pipdeptree --warn fail
--warn fail 只打印冲突部分,不会把整棵依赖树糊你一脸。我看到的是 openpyxl 本身干净,但它带进来的某个传递依赖和既有包版本打架——这就是"装 A 坏 B"最常见的成因。
顺便说一句,装之前可以先试运行,不真装:
python -m pip install --dry-run openpyxl
pip 22.2 以上支持这个参数,它会把要装、要升级的东西都列出来。看到有 "would upgrade flask" 这种字样,就知道要出事了。我后来把这个动作固化成了习惯,装任何生产环境上的包之前先 dry-run 一遍。
venv 不是万能的,但这次确实该用
那套监控脚本之前是直接跑在系统 Python 上的,所有依赖都堆在全局 site-packages 里,谁装个什么都可能踩到别人。
重建一个隔离环境其实就三步:
cd D:\projects\db_monitor
python -m venv .venv
.venv\Scripts\activate
python -m pip install -r requirements.txt
Windows 上要注意两点。一是 PowerShell 默认禁止运行脚本,激活时会报"在此系统上禁止运行脚本",用 Set-ExecutionPolicy -Scope CurrentUser RemoteSigned 改一下就行,改的只是当前用户,不影响机器策略;或者干脆用 cmd 里那个 .venv\Scripts\activate.bat,绕过执行策略。二是激活后提示符前面会出现 (.venv),别嫌它丑,这是唯一能让你确定自己身在哪个环境的信号。
还有个细节:python -m venv .venv 用的是哪个 python,venv 就是哪个版本。想建 3.12 的环境,就得写 C:\...\python3.12.exe -m venv .venv。别指望 venv 自己挑版本,它不会。
requirements.txt 别用 pip freeze 一把梭
我以前的 requirements.txt 是 pip freeze > requirements.txt 生成的,里面躺着四十多个包,一大半是别的项目的。等我要在新机器上还原环境时,那些包全被装上,冲突概率极高。
现在我只写真正直接依赖的那几个,剩下的交给 pip 自己解:
Flask==2.3.3
PyMySQL==1.1.0
openpyxl==3.1.2
如果确实需要锁住传递依赖的版本,用约束文件单独管,和业务依赖分开:
python -m pip install -c constraints.txt -r requirements.txt
这样 requirements.txt 保持干净可读,constraints.txt 负责把版本钉死,两边职责不混在一起。
重装之前,先给自己留个能跑的快照
这次能较快恢复,是因为我前一天恰好做过备份。现在这套流程每次动生产环境前都跑一遍:
python -m pip freeze > requirements.lock.txt
一行命令,十几秒。真把环境搞崩了,重建 venv 之后 pip install -r requirements.lock.txt 就能回到能跑的状态,不用靠记忆去凑版本号。
我现在的顺序基本固定了:先 freeze 留快照,再 dry-run 看影响,确认没问题才真装,装完跑一遍 pip check。多花一分钟,省掉后面半小时的慌乱。
那天最后是把环境整个重建了一遍,只装 requirements 里那三个包,脚本就正常了。escape 那个报错从头到尾都是版本错配的连带反应,跟 Flask 本身一点关系没有。
如果你也遇到"装了 A 之后 B 起不来",别去修 B,先查 A 动了谁。
作者:phantomxjc
- 点赞
- 收藏
- 关注作者
评论(0)