首页
/ Ruff 破坏性变更全解:从 0.0.x 到 0.16.0 的升级避坑指南

Ruff 破坏性变更全解:从 0.0.x 到 0.16.0 的升级避坑指南

2026-09-05 10:43:25作者:牧宁李

BREAKING_CHANGES.md 是 Ruff 仓库中专门记录各版本不兼容行为变更的权威清单。本文完整梳理其中从 0.0.178 到 0.16.0 的全部破坏性变更——默认规则集、默认 Python 版本、抑制注释语法、输出格式、CLI 子命令、JSON 输出结构等核心主题,并结合当前仓库源码(如 python_version.rs 中的默认版本实现、settings/mod.rs 中解析器与规则引擎的版本分离策略)说明每项变更背后的设计意图。读完本文,你可以判断一次 Ruff 升级是否会改变自己项目的行为,并知道如何用 target-versionper-file-ignoresextend-exclude 等配置项平滑过渡。

破坏性变更的核心主题:Python 版本默认值

理解 Ruff 的破坏性变更,首先要抓住一条贯穿始终的主线:默认 Python 版本的历史演进

  • 0.0.283/0.0.284 起,默认版本从 3.10 改为当时最低支持的 3.8(3.7 虽仍受支持但已 EOL,不作默认);
  • 0.8.0 起,默认版本从 3.8 改为 3.9
  • 0.14.0 起,默认版本从 3.9 改为 3.10;同时未配置版本时,语法检查默认使用最新支持版本(当时为 3.14,0.12.0 时这一角色由 3.13 担任),而 lint 规则仍按最低版本处理。

当前仓库的源码印证了 0.14.0 之后的双轨策略。python_version.rsPythonVersionDefault 实现固定返回 PY310

impl Default for PythonVersion {
    fn default() -> Self {
        Self::PY310
    }
}

而在 settings/mod.rs 中,TargetVersion 包装器将“未配置版本”的两种回退路径分开:parser_version() 在未设置时回退到 PythonVersion::latest(当前为 3.14,见 python_version.rslatest() 常量),用于解析和语义错误检测以“最小化版本相关诊断”;linter_version() 则回退到 PythonVersion::default()(3.10),用于版本相关的 lint 规则。这正是 0.12.0/0.14.0 中“语法错误按最新版、lint 规则按最低版”策略的实现。

适用建议:无论默认值如何变化,显式设置 target-version(或 project.requires-python)是唯一可靠的做法。从源码结构看,python_version.rs 的 JSON Schema 生成(同文件 L205 起的 schemars 模块)会把所有受支持版本枚举进 ruff.schema.json,编辑器补全即来源于此。

0.16.0:默认规则集大幅扩容与输出能力增强

这是当前仓库中记录的最重量级一次破坏性变更,共六项:

  1. 默认规则集从 59 条扩容到 413 条。这主要是一次扩展,但同时移除了 18 条较有争议的 pycodestyle(E)与 pyflakes(F)规则:E401E402E701E702E703E711E712E713E714E721E731E741E742E743F403F405F406F722。如果你此前依赖“默认 = 保守”的假设,升级到 0.16.0 后首次运行 ruff check 会看到大量新增诊断。

  2. Markdown 文件中的 Python 代码块默认参与格式化ruff format 现在会处理 .md 文件里的 Python 代码块,且默认开启。

  3. ruff: ignore 抑制注释。现在支持两种位置的 ruff: ignore 注释,功能定位与 noqa 类似:行尾注释(如 import math # ruff: ignore[F401])或紧邻诊断的前一行注释:

    import math  # ruff: ignore[F401]
    
    # ruff: ignore[F401]
    import os
    

    两者都能抑制 unused-importF401)诊断。仓库中该注释的语法解析实现在 suppression.rs,其文档注释明确区分了“独立行注释”与“行尾注释”两类形态。

  4. checkformat --check 输出中展示修复 diff。0.16.0 起,ruff format --check 会直接打印将被改写的内容:

    ❯ ruff format --check .
    unformatted: File would be reformatted
     --> try.md:1:1
      |
    1 | ```python
      - import   math
    2 + import math
    3 | ```
      |
    
    1 file would be reformatted
    
  5. format --check 支持与 linter 相同的输出格式,包括在 CI 中渲染注解的 githubgitlab 格式:

    ❯ ruff format --check --output-format github .
    ::error title=ruff (unformatted),file=try.md,line=2,col=8,endLine=2,endColumn=10::try.md:2:8: unformatted: File would be reformatted
    

    完整格式列表见 CLI help 或 output-format 配置文档。

  6. JSON 输出中部分字段可为 nullfilenamelocationend_locationfix.edits[].locationfix.edits[].end_location 这些字段现在可能是 null,而不再回退为空字符串或“第 1 行第 1 列”。如果你用脚本消费 JSON 输出,需要兼容空值。

0.15.0 与 0.14.0:2026 风格指南、块级抑制与平台变更

0.15.0 包含五项变更:

  • 2026 formatter 风格指南ruff format 现在按 2026 版风格指南排版,具体差异见 CHANGELOG 的 formatter 部分;

  • linter 支持块级抑制注释,配合 ruff: enable 成对使用:

    # ruff: disable[N803]
    def foo(
        legacyArg1,
        legacyArg2,
        legacyArg3,
        legacyArg4,
    ): ...
    # ruff: enable[N803]
    
  • Alpine Docker 镜像基于 Alpine 3.23(原 3.21);Debian 镜像ruff:debianruff:debian-slim)迁移到 Debian 13 “Trixie”(原 Debian 12 “Bookworm”);

  • ppc64(64 位大端 PowerPC)预编译二进制不再随发布提供,如需仍可手动构建;

  • 默认 Python 版本与 extend 的解析顺序:Ruff 现在先解析所有 extend 的配置链,再回退到默认 Python 版本——这意味着被扩展配置文件中声明的 target-version 会正确生效。

0.14.0 如前文所述,是默认 Python 版本升到 3.10、语法错误检查改用最新支持版本(3.14)的节点;其源码依据见 settings/mod.rsparser_version()linter_version() 的分离实现。

0.13.0:自动补 from __future__ import annotations 与规则移除

  • TC001/TC002/TC003/RUF013/UP037 的修复现在会自动添加 from __future__ import annotations(当 lint.future-annotations 开启时)。这使得这些规则可以把更多 import 移入 TYPE_CHECKING 块(TC00x)、在 Python 3.10 之前使用 PEP 604 联合语法(RUF013)、以及解除更多注解引号(UP037)。对依赖“修复不改写 import 头”的自动化流水线,这是一个行为变化。
  • first-party 模块识别改用完整模块路径:Ruff 现在会验证磁盘上完整路径存在,才把 import 归类为 first-party。这降低了本地目录与第三方包同名时的误报(FAQ 中“Ruff 如何区分 first-party / third-party”一节有详细说明)。
  • 已废弃规则必须用精确规则码选择:不再能通过组名或前缀激活废弃规则。由于本版本同时移除了仅剩的两条废弃规则(PD901 pandas-df-variable-nameUP038 non-pep604-isinstance),对现网配置无感,但为未来废弃立下了规则。
  • 移除 macOS 配置目录回退:不再查找 ~/Library/Application Support/ruff/ruff.toml。自 v0.5 起该路径就已被标记废弃,统一走 XDG 规范(通常为 ~/.config/ruff/ruff.toml)。

0.12.0 与 0.11.0:语法错误检测增强与发布事故补救

0.12.0

  • 更多版本相关语法错误:如 Python 3.10 之前使用 match 语句,以及 CPython 编译器会报告的“最后一个 case 分支前出现不可证伪 match 模式”等错误;
  • 未配置版本时,这类语法错误检查默认使用最新支持版本(当时为 3.13)以避免误报,lint 规则默认值不变(3.9);
  • f-string 格式化更新:多行 f-string 带格式化说明符时不再在说明符后换行——Python 3.13.4 的语法变更使这种换行成为语法错误;
  • rust-toolchain.toml 不再包含在源码发行包中:它原本用于开发/发版时指定高于 MSRV 的 Rust 版本,但留在 sdist 里会迫使下游打包者拉取相同工具链,即使其本地工具链满足 MSRV;
  • 移除 S320suspicious-xmle-tree-usage)规则。

0.11.0 是对 0.10.0 的补救发布:由于发布流程失误,requires-python 推断变更未随 0.10.0 上线,0.11.0 补齐了它,并稳定了 PGH004 的预览行为。核心变更是未指定 target-version 时 Python 版本的推断方式(PR #16319):

  • 此前:只有含 [tool.ruff] 段的 pyproject.tomlrequires-python 才会被读取;不含该段的 pyproject.toml 会被忽略,Ruff 回退到默认版本(当时 3.9),与用户预期不符;
  • 新行为:
    1. 找到不含 target-versionruff.toml 时,检查同目录 pyproject.tomlrequires-python(即使没有 [tool.ruff] 段);
    2. 使用用户级配置时,最近父目录 pyproject.tomlrequires-python 优先;
    3. 被检查文件目录内没有任何配置文件时,向父目录查找最近的 pyproject.toml 并使用其 requires-python

0.10.0、0.9.0 与 0.8.0:TYPE_CHECKING、noqa 语义与安装路径

0.10.0

  • TYPE_CHECKING 识别更宽泛:此前只认 typing.TYPE_CHECKING 符号,现在任意名为 TYPE_CHECKING 的局部变量都算;同时移除对 if 0: / if False: 这类旧式类型检查块的识别(PR #16669)。# noqa: TC00x 等注释若依赖旧块语法,需要迁移到本地 TYPE_CHECKING 变量;
  • noqa 解析更健壮(PR #16483):文件级与行内抑制注释语法统一并对若干错误更宽容。多数情况下会“多读”注释,但个别此前能被读取的注释现在会向用户报错;
  • with 语句括号修正(PR #14005):formatter 不再为“单个上下文管理器 + 行尾注释”的 with 语句添加多余括号,可能导致少量既有文件重排;
  • ruff:alpine 默认标签升到 3.21ruff:alpine3.20 停止更新(PR #16456);
  • RUF035unsafe-markup-use)改码为 S704(PR #15957)——按安全类规则统一编号。

0.9.0 是一次风格指南大版本:formatter 按 2025 风格指南排版,代码可能因此被重新格式化。详细差异见 CHANGELOG.md

0.8.0

  • 默认 Python 版本 3.8 → 3.9
  • pydoclint 诊断位置变化pydoclint 规则的诊断现在指向问题 docstring 的首行。若你在预览期启用过这些规则并用 noqa 压制,可能需要移动注释位置;
  • 独立安装脚本改用 XDG 路径:不再用 $CARGO_HOME / ~/.cargo/bin,安装目标按顺序取 $XDG_BIN_HOME$XDG_DATA_HOME/../bin~/.local/bin。用 uv 或 pip 安装的用户不受影响;
  • 行宽计算换用新版 unicode-width crate:极罕见情况下,含 Unicode 字符的行可能被重排或被 E501 新判为超长。

0.7.0 与 0.6.0:规则改码与 Notebook 默认开启

0.7.0

  • pytest 规则 PT001PT023 默认省略无参装饰器的括号(此变更在 0.6.0 中因失误只部分落地,0.7.0 补全);
  • useless-try-except 规则从 TRY302 改码为 TRY203,与上游 tryceratops linter 编号保持一致;
  • lint.allow-unused-imports 配置项被移除,改用 lint.pyflakes.allow-unused-imports

0.6.0 是 Notebook 用户的关键节点:

  • isort 规则默认识别 src 布局下的 import;

  • PT001/PT023 无参括号省略(见上);

  • 默认 lint 并 format Jupyter Notebook 文件。按需用配置收敛:

    [tool.ruff.lint.per-file-ignores]
    "*.ipynb" = ["E501"] # disable line-too-long in notebooks
    

    只想 lint 不想 format:

    [tool.ruff.format]
    exclude = ["*.ipynb"]
    

    反过来只 format 不 lint:

    [tool.ruff.lint]
    exclude = ["*.ipynb"]
    

    完全禁用 Notebook 支持:

    [tool.ruff]
    extend-exclude = ["*.ipynb"]
    

0.5.0 则包含:macOS 遵循 XDG 规范发现用户级配置(与其他 Unix 平台一致);ALL 选择器排除废弃规则;发布压缩包多一层目录嵌套(tar 时用 --strip-components=1);发布产物文件名不再含版本号,从而支持 /latest 直链安装。

0.3.0 及更早:默认排除列表与 CLI/JSON 结构的定型

0.3.0 有三条值得注意的变更:

  1. formatter 切换到 Ruff 2024.2 风格指南,稳定化差异见 CHANGELOG.md

  2. stub 文件(.pyi)import 后固定一个空行:此前为 1~2 个空行(或 isort.lines-after-imports 配置值),现统一为 1 个,与 formatter 行为一致;

  3. build 目录不再默认排除。默认排除列表(不含 build)如下:

    • .bzr.direnv.eggs.git.git-rewrite.hg.ipynb_checkpoints.mypy_cache.nox.pants.d.pyenv.pytest_cache.pytype.ruff_cache.svn.tox.venv.vscode__pypackages___buildbuck-outdistnode_modulessite-packagesvenv

    原因:build 是较常见的目录名,默认排除反而造成困惑。现在只有当 .gitignore 排除它或你自行写入 extend-exclude 时才会被跳过;

  4. ruff ruleruff linter 不再接受 --format 别名,请改用 --output-format

0.1.9site-packages 加入默认排除(此前依赖 .venv 间接排除,但 VS Code 在非虚拟环境中运行时可能失效),列表即上表。

0.1.0 有三项结构性变更:

  • 废弃的 format 设置移除format 设置、--format CLI 选项、RUFF_FORMAT 环境变量不再用于输出格式(自 v0.0.291 起已弃用,format 语义已转给代码格式化)。输出格式请用 output-format 设置 / RUFF_OUTPUT_FORMAT 环境变量 / --output-format 选项;
  • unsafe 修复默认不再应用:Ruff 把修复分为 safe/unsafe,unsafe 修复此前会展示并应用,现在默认隐藏且不应用,需 --unsafe-fixes 标志或 unsafe-fixes 配置显式开启。这是 CI 中“升级后修复数量骤降”的最常见原因;
  • 移除与 formatter 冲突的规则:默认 pycodestyle 规则从整个 E 前缀收窄为 E4E7E9 三个前缀,E501(line-too-long)、E101(mixed-spaces-and-tabs)等离开默认集。显式 select = ["E"] 的用户不受影响。

更早版本中的关键条目(均为 CLI 契约层面的收缩):

  • 0.0.288:移除 emoji 标识符(如 📦 = 1)支持,现在与 CPython 一致地报语法错误;GitLab 输出改用不依赖位置的指纹,避免“前置代码一改就误报一修一新”(升级 PR 中所有存量违规会各报一次“已修复 + 新增”,属预期);

  • 0.0.283/0.0.284:默认目标版本 3.10 → 3.8(0.0.283 宣布、0.0.284 生效);

  • 0.0.277.ipynb_checkpoints.pyenv.pytest_cache.vscode 加入默认排除,与 Black 等工具对齐;

  • 0.0.276 / 0.0.268keep-runtime-typing 先移除(等价于忽略 UP006/UP007),后以更严格语义恢复——仅对 Python 3.7/3.8 生效,防止 Ruff 生成 Pydantic/FastAPI 等运行期解析注解的库不支持的 list[int] 标注;

  • 0.0.267update-check 彻底移除,配置或 CLI 中再出现该选项会直接报错;

  • 0.0.265--fix-only 退出码语义与 --fix 对齐——默认返回 0,仅在显式 --exit-non-zero-on-fix 且确有修复时非零;

  • 0.0.260修复(fix)表示为编辑列表。JSON 输出的 fix 字段从单个 edit 变为 edits 数组,支持一次违规跨多处编辑:

    {
        "message": "Remove unused import: `sys`",
        "edits": [
            {
                "content": "",
                "location": {"row": 1, "column": 0},
                "end_location": {"row": 2, "column": 0}
            }
        ]
    }
    
  • 0.0.246 / 0.0.245:移除 E704(pycodestyle 与 Flake8 默认也忽略它);移除未文档化的公开 Rust check API,为未来稳定 API 留余地;

  • 0.0.238select/extend-select/ignore/extend-ignore 语义重定义(PR #2312)——以“最高优先级来源”(CLI > 当前 pyproject.toml > 继承的 pyproject.toml)的 select 为基线,再叠加 extend-select/ignore/extend-ignore。典型破坏点:配置了 ignore = ["F401"] 时,ruff --select F 从“F 全部但排除 F401”变为“F 全部(含 F401)”,因为 CLI --select 会重置解析;同版本移除 UP016remove-six-compat);

  • 0.0.237--explain--clean--generate-shell-completion 转为子命令 ruff rule / ruff clean / ruff generate-shell-completion。注意:子命令遇到不支持的参数会直接失败(不再静默忽略);ruff rule 等词同时是有效文件/目录名时语义改变;脚本调用位置参数前建议加 --

  • 0.0.226 / 0.0.225PLC2201 废弃并推荐 SIM300@functools.lru_cache(maxsize=None)@functools.cache 的重写从 UP011 拆出为独立规则 UP033(相关 noqa 注释需改码);

  • 0.0.222--max-complexity 从 CLI 移除,改在配置中设置:

    [tool.ruff.mccabe]
    max-complexity = 10
    
  • 0.0.181:被 .ignore.gitignore.git/info/exclude 及全局 gitignore 排除的文件默认不检查(由 ignore crate 驱动,叠加在内置 exclude 之上);关闭方式:respect-gitignore = false。注意以 . 开头的隐藏文件默认忽略;

  • 0.0.178:配置解析层级化——每个 Python 文件按路径找到第一个 pyproject.toml 并以其 [tool.ruff] 段为准,这是后续所有“配置发现”行为(包括 0.11.0 的 requires-python 推断)的基础。

升级实践:如何安全地跨过这些版本

综合以上各节的破坏性变更类型,升级 Ruff 时建议按以下顺序验证:

  1. 显式固定 Python 版本target-versionrequires-python 写清楚,避免 3.8 → 3.9 → 3.10 的默认值漂移影响 UP/TC 类规则判定;
  2. 审视输出消费方:JSON 输出从单 edit 变 edit 列表(0.0.260)、字段可为 null(0.16.0)、GitLab 指纹变化(0.0.288)——消费这些输出的脚本与 CI 集成应同步审查;
  3. 对比修复行为unsafe-fixes 默认关闭(0.1.0)意味着自动化流水线需要显式开启;0.13.0 起 TC/RUF013/UP037 的修复可能连带插入 from __future__ import annotations
  4. 核对规则码TRY302→TRY203RUF035→S704UP011→UP033(部分)等改码,以及 PD901UP038S320E704UP016 的移除,会影响 select/ignore/noqa 中写死的规则码;
  5. 注意范围变化:0.6.0 起 Notebook 默认纳入、0.16.0 起 Markdown 代码块默认格式化、build/site-packages 等默认排除列表多次调整——先用 ruff check --show-files / ruff format --check 对比新旧版本的检查范围与结果,再决定是否用 extend-excludeper-file-ignores、分节 exclude 收敛行为。

BREAKING_CHANGES.md 本身按版本倒序组织(新 → 旧),配合 CHANGELOG.md 的逐版本细节,构成了升级决策的完整证据链:本文引用的默认版本实现(python_version.rs)、解析/规则双版本策略(settings/mod.rs)与 ruff: ignore 注释解析(suppression.rs)都可以在当前仓库中直接查证。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384