Ruff 0.5.x 版本演进全解:规则重映射、输出格式变更与语言服务器稳定化
本篇技术指南基于 Ruff 仓库中的 0.5.x 版本变更记录,系统梳理 Ruff 0.5.0 至 0.5.7 的完整演进脉络:从 0.5.0 引入的破坏性变更(XDG 配置发现、ALL 选择器行为、规则代码重映射)、29 条预览规则的稳定化、废弃配置与 CLI 选项的移除,到 0.5.3 语言服务器(native server)的稳定发布和 0.5.6 预览模式下 Notebook 默认启用。读完本文,你将掌握升级到 0.5.x 需要做的全部配置迁移,以及每个次要版本中规则行为、解析器、服务端与性能层面的具体改动,并能结合仓库源码验证关键机制的实现位置。
0.5.0:一次面向长期稳定性的重大版本
0.5.0 是 0.5.x 系列中唯一包含破坏性变更的版本。官方将其定位为一个"里程碑式"的发布:一方面清理了此前积累的废弃配置与命令,另一方面通过规则重映射(remapping)让 flake8-async 与 flake8-trio 两个插件体系合流,并对大量预览期规则进行了稳定化。
破坏性变更
0.5.0 的破坏性变更共有五项,升级时需要逐一确认:
- macOS 用户级配置遵循 XDG 规范:与其他 Unix 平台一致,macOS 上用户级配置的发现路径改为遵循 XDG 规范。这意味着原先依赖 macOS 专属路径(如
~/Library/Application Support)存放用户配置的使用方式不再适用。 ALL选择器排除已废弃规则:此前select = ["ALL"]会包含所有规则,0.5.0 起该选择器不再选中处于 deprecated 状态的规则。如果你在配置中使用ALL,升级后部分规则会"静默消失",需要显式确认。- 发布压缩包多了一层目录嵌套:下载的发行归档内部多了一个目录层级,解压时需要用
--strip-components=1去除,否则二进制会落在多一层子目录中。 - 发布产物文件名不再包含版本号:这一改动允许用户通过 GitHub 的
/latest相对 URL 直接安装最新版,简化了安装脚本。 - 部分
flake8-bandit规则的诊断范围(diagnostic range)被调整:与 shell 相关的 bandit 规则高亮位置发生了变化(对应 PR #10667),依赖精确诊断范围做二次处理的工具需要回归验证。
规则废弃:syntax-error(E999)
0.5.0 起,规则 syntax-error(代码 E999)被标记为废弃。原因是语法错误从此总是会被显示——解析器报错直接成为诊断输出的一部分,不再需要通过选择 E999 来"打开"这一能力。这一改动在 0.5.1 中还得到了配套完善:token 级别的规则可以在存在语法错误的源码上继续运行(PR #11950),且当源码存在语法错误时会自动禁用 autofix(PR #12134),避免在不完整 AST 上产生错误修复。
规则重映射:TRIO 并入 ASYNC,ASYNC10x 拆分为 ASYNC2xx
这是 0.5.0 对现有用户影响最大的一组改动。flake8-trio 的规则被整体并入 flake8-async,同时原来含义混杂的 ASYNC100~ASYNC102 被拆分为更精确的 ASYNC2xx/ASYNC25x 系列。完整映射表如下:
| 规则 | 原代码 | 新代码 |
|---|---|---|
blocking-http-call-in-async-function |
ASYNC100 |
ASYNC210 |
open-sleep-or-subprocess-in-async-function |
ASYNC101 |
拆分为 ASYNC220、ASYNC221、ASYNC230、ASYNC251 |
blocking-os-call-in-async-function |
ASYNC102 |
合并进 ASYNC220 和 ASYNC221 |
trio-timeout-without-await |
TRIO100 |
ASYNC100 |
trio-sync-call |
TRIO105 |
ASYNC105 |
trio-async-function-with-timeout |
TRIO109 |
ASYNC109 |
trio-unneeded-sleep |
TRIO110 |
ASYNC110 |
trio-zero-sleep-call |
TRIO115 |
ASYNC115 |
repeated-isinstance-calls |
PLR1701 |
SIM101 |
从源码结构看,这些重定向并非仅在文档层面存在:仓库中维护了一张集中式的重定向表 rule_redirects.rs,其中明确标注了 TRIO → ASYNC1 的前缀级重定向(TRIO100→ASYNC100、TRIO105→ASYNC105、TRIO109→ASYNC109、TRIO110→ASYNC110、TRIO115→ASYNC115)以及 PLR1701 → SIM101 的条目(源码注释中标记为 "Removed in v0.5")。这张表通过 get_redirect_target 在解析 select/ignore 中的旧代码时生效——只要你在配置里写的是旧代码,Ruff 会自动按新代码处理,但变更记录同时提醒:重映射可能导致原本被禁用的规则变为启用状态(例如原 ignore = ["ASYNC100"] 现在对应 ASYNC210,而新拆出的 ASYNC220/ASYNC221/ASYNC230/ASYNC251 不再被该条目覆盖)。
拆分后的新规则在源码中一一对应:blocking_http_call.rs 产出 ASYNC210、blocking_process_invocation.rs 产出 ASYNC220/ASYNC221、blocking_open_call.rs 产出 ASYNC230、blocking_sleep.rs 产出 ASYNC251(见 crates/ruff_linter/src/rules/flake8_async/)。
规则稳定化:29 条规则脱离预览
0.5.0 将以下规则从 preview 转为稳定(稳定化后其行为不再随 preview 开关变化,可放心用于生产配置):
- Ruff 自有规则:
mutable-fromkeys-value(RUF024)、default-factory-kwarg(RUF026) - flake8-bandit:
django-extra(S610) - Perflint:
manual-dict-comprehension(PERF403) - Refurb:
print-empty-string(FURB105)、readlines-in-for(FURB129)、if-expr-min-max(FURB136)、bit-count(FURB161)、redundant-log-base(FURB163)、regex-flag-alias(FURB167)、isinstance-type-none(FURB168)、type-none-comparison(FURB169)、implicit-cwd(FURB177)、hashlib-digest-hex(FURB181)、list-reverse-copy(FURB187) - Pylint:
bad-open-mode(PLW1501)、empty-comment(PLR2044)、global-at-module-level(PLW0604)、misplaced-bare-raise(PLE0744)、non-ascii-import-name(PLC2403)、non-ascii-name(PLC2401)、nonlocal-and-global(PLE0115)、potential-index-error(PLE0643)、redeclared-assigned-name(PLW0128)、redefined-argument-from-local(PLR1704)、repeated-keyword-argument(PLE1132)、super-without-brackets(PLW0245)、unnecessary-list-index-lookup(PLR1736)、useless-exception-statement(PLW0133)、useless-with-lock(PLW2101)
同时,五条既有规则的行为调整也在 0.5.0 完成稳定化:
is-literal(F632):现在对 list、set、dict 字面量做is/is not身份检查也会告警needless-bool(SIM103):现在能检测隐式else分支的if表达式module-import-not-at-top-of-file(E402):现在允许在导入语句之间修改os.environtype-comparison(E721):现在允许type(x) is int这类惯用写法yoda-condition(SIM300):现在覆盖更宽范围的表达式
废弃配置与命令的移除
0.5.0 按既定流程移除了所有标记为 deprecated 的配置项、CLI 选项与命令形态,替代关系如下:
已移除的废弃配置项
| 移除项 | 替代方案 |
|---|---|
output-format = "text" |
output-format = "concise" 或 output-format = "full" |
tab-size |
indent-width |
已移除的废弃 CLI 选项
| 移除项 | 替代方案 |
|---|---|
--show-source |
--output-format=full |
--no-show-source |
--output-format=concise |
已移除的废弃 CLI 命令形态
| 移除项 | 替代方案 |
|---|---|
ruff <path> |
ruff check <path> |
ruff --clean |
ruff clean |
ruff --generate-shell-completion |
ruff generate-shell-completion |
配置查找与解析的实现集中在 crates/ruff_workspace/src/pyproject.rs 与 crates/ruff_workspace/src/options.rs,其中说明了 pyproject.toml、ruff.toml、.ruff.toml 三种配置文件形态及其在解析范围(respect-gitignore 相关的 respected_extensions 默认列表)中的处理——0.5.0 起这三种形态的匹配行为是稳定契约的一部分。
CLI 与输出格式:full 成为默认值
0.5.0 对 CLI 输出做了三处调整:
--statistics统计改用规则名而非诊断消息作为聚合维度(PR #11697),统计结果对不同代码风格更加稳定;- 默认输出格式从简洁模式切换为
full(PR #12010),即诊断默认附带源码代码框(code frame),不再需要--show-source; - 语法错误不再重复打印到控制台日志(PR #11902),避免诊断与日志双份刷屏。
这一默认值在源码中有直接体现:OutputFormat 枚举将 Full 标记为 #[default],并列出全部 13 种取值(concise、full、json、json_lines、junit、grouped、github、gitlab、pylint、rdjson、azure、sarif 等),同时提供 is_human_readable 判定来决定是否输出页头/页脚(见 settings/types.rs)。如果 CI 中依赖旧的简洁输出做文本比对,升级后应显式加 --output-format=concise。
0.5.0 的其他改动
预览功能:新增 assert-with-print-message 规则(PR #11981),检测在 assert 中使用 print 附带消息的反模式。
规则修正:
- Ruff 自有:修复
gettext通过别名导入时RUF027的误报(PR #12025) - NumPy:更新
NPY201中trapz、in1d的弃用判定(PR #11948) - flake8-bandit:调整 shell 相关规则的诊断范围(PR #10667)
解析器修复(6 项,均影响错误恢复与诊断范围精度):
- 空类型参数列表(如
def f[]() -> None)现在正确报语法错误(PR #12030) - 未终止字符串不再吞掉换行符(PR #12067),且错误范围不再包含换行(PR #12017)
- 行续接错误的定位使用正确的范围(PR #12016)
- 行续接前的 2 字符行尾(如 CRLF)被正确处理(PR #12035)
- 重新词法分析(re-lexing)时考虑行续接字符(PR #12008)
其他:用于度量 line-length 的 Unicode 表升级(PR #11194);移除 nursery 选择器的弃用报错(PR #10172)。
0.5.1:语法错误处理与缓存正确性
0.5.1 是紧随 0.5.0 的修复版本,重点围绕"存在语法错误时的行为"与缓存正确性。
预览功能:
- flake8-bugbear 新增
mutable-contextvar-default(B039)(PR #12113) - pycodestyle 新增装饰器后空白规则(
E204)(PR #12140) - pytest 插件交换了
PT001与PT0023的默认状态(PR #12106)
规则修正:
- 存在语法错误的源码上启用 token 级规则(PR #11950)
- flake8-bandit 的
S113现在能识别httpx(PR #12174) NPY201覆盖异常类弃用项(PR #12065)PLE0241(duplicate-bases)新增 autofix(PR #12105)
服务端:
- 源码动作(source code actions)不再触发语法错误通知(PR #12148)
- Notebook 同步时考虑新单元格内容(PR #12203)
- 修复替换编辑范围计算(PR #12171)
Bug 修复(关键项):
- 源码含语法错误时禁用 autofix(PR #12134)
- 修复含分隔符路径的缓存键碰撞(PR #12159)——这是 0.5.0 缓存键实现的缺陷修复,影响 Windows 与 POSIX 混用路径的场景
requires-python推断对==约束更健壮(PR #12091)- 宽度计算改用逐字符(char-wise)宽度而非
str宽度(PR #12135) - pycodestyle:关键词后跟逗号或分号时不再误报
E275(PR #12136、PR #12095) - pylint:
PLR1704跳过哑变量(dummy variables)(PR #12190)
性能:parse_identifier 去分配化(PR #12103);Identifier AST 节点改用 CompactString 存储(PR #12101)——AST 节点内存布局优化的首批实践。
0.5.2:async 规则覆盖面扩展与 Windows 缓存容错
预览功能:ASYNC100、ASYNC109、ASYNC110、ASYNC115、ASYNC116 五条规则统一扩展为覆盖 anyio 与 asyncio 命名空间(PR #12221、#12236、#12261、#12262、#12266);formatter 在带前导注释的推导式中,对括号表达式使用 space 分隔符(PR #12282)。
规则修正:RET501 将 property 从显式返回检查中豁免(PR #12243);NPY201 增加 np.NAN → np.nan 诊断(PR #12292);FURB187(list-reverse-copy)的 autofix 改为 unsafe 标记(PR #12303)。
服务端:native server 开始考虑 include 与 extend-include 设置(PR #12252),并在设置重载时纳入嵌套配置(PR #12253)——这直接服务于 options.rs 中定义的文件包含/排除契约。
CLI:修复(fix)范围为空时省略代码框(PR #12304);对 D203(与 formatter 的空白行策略冲突)给出 formatter 不兼容警告(PR #12238)。
Bug 修复(关键项):
- Windows 上缓存写入失败不再致命(PR #12302)
not运算被视为布尔测试(影响若干以布尔上下文为判定条件的规则)(PR #12301)- flake8-bandit:HTTP 安全的 f-string 不再误报
S310(PR #12305),S310支持显式字符串拼接的 URL 检测(PR #12315),无timeout参数的 httpx 调用不再误报S113(PR #12213) - pycodestyle:移除
E721的"非显而易见"豁免(PR #12300) - pyflakes:
with块被视为单条目分支参与重定义分析(PR #12311) - refurb:
open()的newline参数转发修复限制在 Python ≥ 3.10(PR #12244)
其他:文档与帮助文本更新以反映 --output-format full 默认值(PR #12248);Python 文件发现使用更多线程(PR #12258)。
0.5.3:Ruff 语言服务器稳定发布
0.5.3 的标志性事件是 Ruff 语言服务器(native server)的正式稳定,配套的编辑器文档同步重构,包括编辑器安装指南与服务端设置参考(文档迁移至独立文档仓库,PR #12341;服务端文档 PR #12344;编辑器集成版本策略更新 PR #12375)。仓库内 crates/ruff_server/ 即该服务器的实现,其中 README.md 与 CONTRIBUTING.md 说明了其开发方式。
预览功能:formatter 在函数/类定义后、suite 与备选分支之间插入空行(PR #12294);pyupgrade 新增 unnecessary-default-type-args(UP043)(PR #12371)。
规则修正:
B909(loop-iterator-mutation)检测enumerate迭代中的迭代器变更,并移除对discard/remove/pop的豁免(PR #12366、#12365)PLR1714允许混合运算下的重复等值比较(PR #12369)PLR0913统计参数个数时忽略self/cls(PR #12367)PLW1514的 autofix 默认使用 UTF-8 编码(PR #12370)
服务端:
- 原生服务器并行构建设置索引(PR #12299)
- 索引项目时使用回退设置(PR #12362)
server子命令开始接受--preview标志以分别控制 linter 与 formatter 的预览模式(PR #12208)
Bug 修复:C419 允许 sum/max 推导式的额外参数(PR #12364);PLR1714 修复 autofix 丢弃多余布尔运算(PR #12368);PLR1704 在判定绑定类型时考虑语句前的表达式(PR #12346)。
其他:Wasm API 发布到 npm(PR #12317),对应仓库中的 crates/ruff_wasm/。
0.5.4 与 0.5.5:命名修正与 FastAPI/pydoclint 预览
0.5.4 体量较小,核心是命名与修复质量:
RUF007更名为zip-instead-of-pairwise(PR #12399),名称更贴合规则意图- flake8-builtins 不再对
@override方法报遮蔽诊断(PR #12415) - flake8-comprehensions 的 autofix 为多参生成器插入括号(PR #12422)
- pydocstyle 处理 docstring 内部转义(
D301,PR #12192) - 文档修正:Neovim 安装链接、设置参考中
output-format默认值(PR #12409、#12410)
0.5.5 引入了两组新的预览规则,并修复 formatter 注释定位问题:
- FastAPI 插件首发:
fastapi-redundant-response-model(FAST001)与fastapi-non-annotated-dependency(FAST002)(PR #11579) - pydoclint 新增
docstring-missing-exception(DOC501)与docstring-extraneous-exception(DOC502)(PR #11471) - NumPy:修复
np.alltrue/np.sometrue的 2.0 规则(PR #12473);except块内忽略NPY201以兼容旧版 NumPy(PR #12490) - pep8-naming:
ignore-names不再作用于self/cls函数名(N804/N805,PR #12497) - formatter:修复带类型参数函数的前导注释错位(PR #12447)
- Bug 修复:
cmp_fix的Ord实现修正(PR #12471);多参调用中未加括号的生成器表达式报语法错误(PR #12445);DOC501的 panic 修复(PR #12435);B013允许含星号表达式的单元素元组(PR #12484) - 文档新增 Emacs/Eglot、Zed 编辑器安装指南,以及
nvim-lspconfig破坏性变更说明(PR #12426、#12501、#12507)
0.5.6 与 0.5.7:Notebook 预览启用与 pydoclint 完善
0.5.6 的核心变化:预览模式下默认启用 Notebook 的 lint 与 format。这是对 0.5.x 服务端 Notebook 支持工作的收束。如需退出该行为,在配置中将 *.ipynb 加入 extend-exclude 即可:
[tool.ruff]
extend-exclude = ["*.ipynb"]
同版本还包括:
- 预览规则:flake8-builtins 实现 import/lambda/module 遮蔽检测(PR #12546);pydoclint 新增
docstring-missing-returns(DOC201)与docstring-extraneous-returns(DOC202)(PR #12485) RET501将缓存型 property 及类似 property 的装饰器豁免出显式返回检查(PR #12563)- 服务端:panic hook 增强容错(PR #12610);Zed 与 VS Code 使用
$/logTrace输出服务端追踪日志(PR #12564);为单元格重排请求记录已删除单元格(PR #12575) - flake8-implicit-str-concat:禁止隐式拼接时始终允许显式多行拼接(PR #12532)
- Bug 修复重点:isort 不再把必需导入标记为未使用(PR #12537)、保留
import-from行尾内联注释(PR #12498);pycodestyleE305补换行、错缩进注释不附带(PR #12606、#12604);pyflakes 预览模式下__init__.py中一方子模块F401自动修复缺陷(PR #12569);pyupgrade 避免对slots=Truedataclass 建议无参 super(PR #12530);移除未使用导入时的 NFKC 规范化 Bug(PR #12571) - 其他:更多标准库装饰器被认定为 property 风格(PR #12583)、元类在各规则中的处理改进(PR #12579)、"函数是否 property"的判定在各规则间保持一致(PR #12581)
0.5.7 继续完善 pydoclint 家族与修复质量:
- 预览:
C409考虑列表/集合推导(PR #12657);PYI044新增 autofix(PR #12676);RET505autofix 处理混合缩进避免语法错误(PR #12740);pydoclint 新增docstring-missing-yields(DOC402)与docstring-extraneous-yields(DOC403)(PR #12538),并处理了 stub 函数豁免、"Returns" 开头的 docstring 豁免、re-raise 视为显式抛出等 5 处语义细节(PR #12651、#12675、#12642、#12639);新增RUF031(incorrectly-parenthesized-tuple-in-subscript)(PR #12480);RUF023在__slots__非集合且绑定被别处使用时将修复标记为 unsafe(PR #12692) - 规则修正:
FURB177(implicit-cwd)与RUF007(zip-instead-of-pairwise)均新增 autofix(PR #12708、#12663);TRY002将BaseException纳入raise-vanilla-class(PR #12620) - CLI:修复嵌套
pyproject.toml的缓存失效问题(PR #12727) - Bug 修复重点:
ASYNC100多async with项误报(PR #12643);S608列表拼接构造 SQL 的误报(PR #12720);B909将return视为等价于break(PR #12646);C419的sum接受集合推导(PR #12691);SIM114合并 if 分支时按优先级加括号(PR #12737);DOC501在未指定约定时尝试两种 Raises 段落风格(PR #12649)
升级实践小结
基于 0.5.x 的完整变更记录,升级时需要检查的事项可以归纳为:
- 检查
select/ignore中的旧代码:TRIO*系列与ASYNC100/ASYNC101/ASYNC102/PLR1701会命中 rule_redirects.rs 中的重定向表自动换算,但拆分/合并类映射(ASYNC101→ 四条新规则、ASYNC102→ 并入ASYNC220/ASYNC221)可能改变实际启用的规则集合,建议用ruff check --statistics对比升级前后结果; - 检查
ALL选择器:0.5.0 起ALL不再包含废弃规则,如依赖E999需显式改为依赖语法错误直出; - 替换被移除的配置与命令:按上表将
output-format=text、tab-size、--show-source及三种旧命令形态迁移到新写法,CI 输出文本比对需显式指定--output-format; - 确认 Notebook 策略:若启用
--preview,0.5.6 起 Notebook 默认参与 lint/format,不需要时用extend-exclude = ["*.ipynb"]排除; - 验证诊断范围依赖:使用 flake8-bandit shell 相关规则(
S603/S604等)并依赖精确高亮位置的下游工具,需对 0.5.0 的诊断范围调整做回归。
0.5.x 系列整体展示了 Ruff 的演进方法论:破坏性变更集中于 0.5.0 一次性兑现(并有重定向表兜底旧代码),0.5.1–0.5.7 则以"行为细化 + 修复质量 + 服务端能力"为主线小步推进。后续的 0.6.x 变更记录 在此基础之上继续,可作为对照参考。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00