pyupgrade 升级后 import 路径变化导致代码报错,因其默认启用 pep 585 转换(如 list[int]),但 python 3.9 以下不支持;需用 --py-version 指定最低版本并人工对齐 pyproject.toml 中的 python_requires。

pyupgrade 升级后 import 路径变了,但代码跑不起来
pyupgrade 默认会把 from typing import Optional, List 拆成 PEP 585 风格(如 list[int]、optional[str]),但 Python 3.9 以下版本不认这种写法,直接报 SyntaxError: invalid syntax 或运行时报 NameError: name 'list' is not defined。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 先确认项目最低支持的 Python 版本:如果还在用 3.8 或更早,必须禁用 PEP 585 转换,加参数
--py-version 38(或对应版本) - pyupgrade 不会自动检查
python_requires或pyproject.toml中的版本约束,得人工对齐 - 它默认启用所有规则,包括
typing.NamedTuple→namedtuple简写,但后者在带字段类型注解时会丢掉类型信息,IDE 和 mypy 可能报错
pyupgrade --in-place 修改了文件,但 CI 流水线突然挂了
常见现象是 pre-commit hook 里用了 pyupgrade,本地跑完没报错,但 CI 上跑 mypy 或 pylint 失败。根本原因是 pyupgrade 改动了类型提示语法,但类型检查器没同步更新配置或版本。
实操建议:
立即学习“Python免费学习笔记(深入)”;
-
--in-place是高危操作,务必配合 git diff 看改动,尤其关注Union→|、Dict→dict这类变更是否被当前 mypy 版本支持(mypy dict[str, int] 作为类型) - 如果项目用的是 mypy + plugins(比如
mypy-boto3),某些插件只认旧式typing.Dict,升级后会漏检 - 建议在 pre-commit 中固定 pyupgrade 版本,例如
rev: v3.14.0,避免某次自动升级引入破坏性变更
想只升级 f-string,不碰类型提示
pyupgrade 默认一揽子升级,但团队可能只想统一字符串格式,保留 typing 兼容性。它没有“只开某几项”的开关,只能靠排除规则实现。
升级报告:增加动态新闻功能后台添加,删除,编辑,支持UBB代码,支持上传片及文件。 增加我要入团功能散客可以自由选择加入贵社最近要出发的团队。 增加线路置顶功能置顶后的线路永远显示在最前面。 增加同行报价功能管理员在后台添加同行用户,同行用户登录后可查看贵社线路对同行的报价。同行报价在添加线路中一并添加。(感谢网友拽哥提出修改意见) 增加更多线路显示的分页功能方便大型旅行社由于线路过多而引起的部分
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
--skip-magic-trailing-comma这类跳过选项不管用——它们只控制格式细节,不关功能开关 - 真正有效的是
--exit-non-zero-on-changed配合脚本过滤,但更简单的是用--aggressive的反向思路:默认不开 aggressive,再手动加需要的规则 - 目前唯一可靠方式是传参屏蔽特定重写:例如加
--no-runtime-typing禁用运行时 typing 模块替换,加--no-rewrite-imports(注意:该参数实际不存在,pyupgrade 不提供细粒度 import 控制)→ 所以实际得靠--py-version锁死行为,或改用pycodestyle+autopep8组合做局部处理
pyupgrade 把 from __future__ import annotations 加进来了,但 Django 项目报错
pyupgrade 在 Python 3.7+ 文件里会自动插入 from __future__ import annotations,这对大多数项目是好事,但 Django 3.x 早期版本(如 3.0–3.1)的 ORM 在启用了该 future 后,ForeignKey 的字符串引用(如 "auth.User")会被误解析为未求值注解,导致 AttributeError: 'str' object has no attribute '__args__'。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 不是所有 Python 3.7+ 项目都适合开 annotations,Django 用户要查清文档:3.2+ 才完全支持,3.1 需打补丁,3.0 基本别碰
- pyupgrade 没有判断 Django 版本的逻辑,也不会读取
INSTALLED_APPS,所以这个坑得人肉规避 - 临时方案是在对应文件头加注释
# pyupgrade: off,或者整个项目禁用该规则:--no-annotations(注意拼写,不是--no-annotation)
事情说清了就结束。最麻烦的从来不是 pyupgrade 本身,而是它假设所有代码都活在标准 Python 环境里——而现实里总有 Django、Pydantic、mypy 插件、自定义 AST 工具在暗处等着接招。









