Ruff 0.2 系列版本演进全解析:配置命名空间迁移、规则重映射与 Preview 特性转正
【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff
Ruff 0.2.x 是该项目早期演进中最具结构性的一批版本:0.2.0 完成了配置项向lint命名空间的迁移、5 条规则代码的重映射以及大量 Preview 规则的转正;0.2.1 为ruff format引入按行范围格式化(--range);0.2.2 则带来 f-string 初步格式化、CLI 任意配置覆盖(--config "key=value")与词法/解析层的显著提速。读完本文,你将掌握从 0.1.x 平滑升级到 0.2.x 所需的完整迁移清单,并能通过仓库源码验证每一项变更的实际落点。
0.2.0:配置架构重构与规则体系大调整
0.2.0 是 0.2.x 中变更幅度最大的版本,包含破坏性变更、大规模弃用、规则重映射和 Preview 转正四类内容,下面逐一展开。
破坏性变更:NURSERY 选择器下线
NURSERY选择器不再可用。- 在 Preview 未启用的情况下,不再允许通过精确规则代码选择(select)nursery(孵化中)规则。
这一点可以在当前源码中得到印证。在 规则选择器解析逻辑 中,NURSERY仅作为PREVIEW的别名被保留解析,且按类别、按名称选择规则均要求开启 Preview 模式:
} else if matches!(selector, "PREVIEW" | "NURSERY") { // ... "Selecting rules by category requires preview mode" "Selecting rules by name requires preview mode"而选择器实际生效时的过滤逻辑(rules()方法)根据PreviewOptions决定是否纳入 preview 规则,并支持explicit-preview-rules要求显式代码选择,这与 0.2.0 中“未开启 preview 不得按精确代码选择 nursery 规则”的声明一致。
弃用项清单
被弃用的规则(迁移到其他命名空间或由其他规则取代):
missing-type-self(ANN101)missing-type-cls(ANN102)
被弃用的命令行选项(应改用输出格式控制):
| 弃用选项 | 替代方式 |
|---|---|
--show-source | --output-format full |
--no-show-source | --output-format concise |
--output-format text | 改用full或concise |
迁移到lint命名空间的配置项(旧顶层名称被弃用)。这是 0.2.0 最主要的迁移工作:原先平铺在顶层的 lint 相关配置全部收敛进[lint]表,旧名称仍可解析但会触发弃用提示。完整迁移对照如下(左侧为旧名,右侧为新名):
| 旧配置项 | 新配置项 |
|---|---|
ruff.allowed-confusables | ruff.lint.allowed-confusables |
ruff.dummy-variable-rgx | ruff.lint.dummy-variable-rgx |
ruff.explicit-preview-rules | ruff.lint.explicit-preview-rules |
ruff.extend-fixable | ruff.lint.extend-fixable |
ruff.extend-ignore | ruff.lint.extend-ignore |
ruff.extend-per-file-ignores | ruff.lint.extend-per-file-ignores |
ruff.extend-safe-fixes | ruff.lint.extend-safe-fixes |
ruff.extend-select | ruff.lint.extend-select |
ruff.extend-unfixable | ruff.lint.extend-unfixable |
ruff.extend-unsafe-fixes | ruff.lint.extend-unsafe-fixes |
ruff.external | ruff.lint.external |
ruff.fixable | ruff.lint.fixable |
ruff.flake8-annotations | ruff.lint.flake8-annotations |
ruff.flake8-bandit | ruff.lint.flake8-bandit |
ruff.flake8-bugbear | ruff.lint.flake8-bugbear |
ruff.flake8-builtins | ruff.lint.flake8-builtins |
ruff.flake8-comprehensions | ruff.lint.flake8-comprehensions |
ruff.flake8-copyright | ruff.lint.flake8-copyright |
ruff.flake8-errmsg | ruff.lint.flake8-errmsg |
ruff.flake8-gettext | ruff.lint.flake8-gettext |
ruff.flake8-implicit-str-concat | ruff.lint.flake8-implicit-str-concat |
ruff.flake8-import-conventions | ruff.lint.flake8-import-conventions |
ruff.flake8-pytest-style | ruff.lint.flake8-pytest-style |
ruff.flake8-quotes | ruff.lint.flake8-quotes |
ruff.flake8-self | ruff.lint.flake8-self |
ruff.flake8-tidy-imports | ruff.lint.flake8-tidy-imports |
ruff.flake8-type-checking | ruff.lint.flake8-type-checking |
ruff.flake8-unused-arguments | ruff.lint.flake8-unused-arguments |
ruff.ignore | ruff.lint.ignore |
ruff.ignore-init-module-imports | ruff.lint.ignore-init-module-imports |
ruff.isort | ruff.lint.isort |
ruff.logger-objects | ruff.lint.logger-objects |
ruff.mccabe | ruff.lint.mccabe |
ruff.pep8-naming | ruff.lint.pep8-naming |
ruff.per-file-ignores | ruff.lint.per-file-ignores |
ruff.pycodestyle | ruff.lint.pycodestyle |
ruff.pydocstyle | ruff.lint.pydocstyle |
ruff.pyflakes | ruff.lint.pyflakes |
ruff.pylint | ruff.lint.pylint |
ruff.pyupgrade | ruff.lint.pyupgrade |
ruff.select | ruff.lint.select |
ruff.task-tags | ruff.lint.task-tags |
ruff.typing-modules | ruff.lint.typing-modules |
ruff.unfixable | ruff.lint.unfixable |
这一设计的动因在 workspace 选项定义 中可见:lint小节下的选项优先于被弃用的顶层设置,即“Options specified in the lint section take precedence over the deprecated top-level settings”。对用户而言,迁移策略就是把pyproject.toml/ruff.toml中上述顶层键整体挪进[lint]表,例如:
# 旧写法(弃用) select = ["E", "F", "I"] ignore = ["E501"] # 新写法 [lint] select = ["E", "F", "I"] ignore = ["E501"]规则代码重映射
5 条规则被重映射到新代码。若你的配置或noqa注释仍使用旧代码,规则将实际上被“禁用”(旧代码指向新代码,而旧代码对应的规则本体不复存在),这也是 changelog 特别提示“见 Remapped rules 一节,否则可能导致规则被禁用”的原因:
| 规则 | 旧代码 | 新代码 |
|---|---|---|
raise-without-from-inside-except | TRY200 | B904 |
suspicious-eval-usage | PGH001 | S307 |
logging-warn | PGH002 | G010 |
static-key-dict-comprehension | RUF011 | B035 |
runtime-string-union | TCH006 | TCH010 |
重映射的实现位于 rule_redirects.rs:一张静态HashMap把所有历史代码映射到现行代码。其中本版本的 5 条重映射对应表中的条目:
("RUF011", "B035"), ("TRY200", "B904"), ("PGH001", "S307"), ("PGH002", "G010"), // TCH 前缀后来整体更名为 TC ("TCH006", "TC010"), ("TCH010", "TC010"),从源码结构看,TCH006的重映射目标经过了两步演进:0.2.0 时重映射到TCH010,之后整个TCH前缀与上游插件统一更名为TC,于是现在的重映射表直接将其指向TC010。该文件末尾还内置了overshadowing_redirects测试,确保任何现行规则代码都不会被重映射条目意外遮蔽——这是重映射机制的安全网。
Preview 规则转正(Stabilizations)
以下规则在 0.2.0 中稳定,脱离 Preview 直接生效:
trio-timeout-without-await(TRIO100)、trio-sync-call(TRIO105)、trio-async-function-with-timeout(TRIO109)、trio-unneeded-sleep(TRIO110)、trio-zero-sleep-call(TRIO115)unnecessary-escaped-quote(Q004)enumerate-for-loop(SIM113)、zip-dict-keys-and-values(SIM911)timeout-error-alias(UP041)flask-debug-true(S201)、tarfile-unsafe-members(S202)、ssl-insecure-version(S502)、ssl-with-bad-defaults(S503)、ssl-with-no-version(S504)、weak-cryptographic-key(S505)、ssh-no-host-key-verification(S507)、django-raw-sql(S611)、mako-templates(S702)generator-return-from-iter-method(PYI058)、runtime-string-union(TCH006)numpy2-deprecation(NPY201)quadratic-list-summation(RUF017)、assignment-in-assert(RUF018)、unnecessary-key-check(RUF019)、never-union(RUF020)direct-logger-instantiation(LOG001)、invalid-get-logger-argument(LOG002)、exception-without-exc-info(LOG007)、undocumented-warn(LOG009)
修复(Fix)转正——以下规则的自动修复不再需要 Preview:
triple-single-quotes(D300)、non-pep604-annotation(UP007)dict-get-with-none-default(SIM910)、in-dict-keys(SIM118)、if-with-same-arms(SIM114)collapsible-else-if(PLR5501)、useless-else-on-loop(PLW0120)unnecessary-literal-union(PYI030)unnecessary-spread(PIE800)error-instead-of-exception(TRY400)redefined-while-unused(F811)、duplicate-value(B033)multiple-imports-on-one-line(E401)non-pep585-annotation(UP006)
修复安全级别提升:unaliased-collections-abc-set-import(PYI025)的修复从 unsafe 提升为 safe,即默认--fix即会应用,无需--unsafe-fixes。
行为层面的稳定化:
module-import-not-at-top-of-file(E402)允许在 import 语句之间插入sys.path修改;reimplemented-container-builtin(PIE807)把可替换为dict的 lambda 也纳入检测;unnecessary-placeholder(PIE790)扩展到无用的省略号(...);if-else-block-instead-of-dict-get(SIM401)扩展到if-else表达式。
0.2.0 的 Preview 新特性与 Bug 修复
Preview 特性:
- [refurb] 新增
metaclass_abcmeta(FURB180) - 新增
blank_line_after_nested_stub_class格式化预览样式 - 移除 Preview 规则
and-or-ternary(PLR1706)
Bug 修复:
- [flake8-async] 分析异步函数时计入
pathlib.Path - [flake8-return] 修复
RET505的缩进语法错误 - else 移除(autofix)时检测多语句行
RUF022、RUF023:序列末尾绝不追加两个尾逗号RUF023:只排序__slots__,不再排序__match_args__- [flake8-simplify] 修复
SIM114autofix 的语法错误 - [pylint]
magic-value-comparison(PLR2004)展示原样常量 - 多行字符串内部移除尾随空白被重新标记为 unsafe
invalid-envvar-default支持双臂均为字符串的IfExp- [pylint] 将
__mro_entries__加入已知 dunder 方法(PLW3201)
文档改进:被移除的规则现在保留在文档中;被弃用的规则现在在文档中被明确标注。
0.2.1:引入范围格式化(Range Formatting)
0.2.1 的核心能力是范围格式化:可以对源文件中的特定行进行格式化,即ruff format --range选项(起始行到结束行)。这对编辑器集成场景(仅格式化当前编辑区域)意义重大。
Preview 特性:
- [refurb] 新增
missing-f-string-syntax(RUF027) - 格式化模块级 docstring
Formatter:
ruff format新增--range选项- 修复 docstring 末尾空行被误删的问题
Bug 修复:
- 判定基础缩进时跳过空行
unnecessary-dunder-call不再针对__get__与__set__- 省略号移除时尊重泛型
Protocol - 回滚一项 CI 相关变更(Apple Silicon runner)
性能优化(本版本是性能工程密集的一版):
- 标准 dedent 调整跳过 LibCST 解析
- 移除
C408的 CST 修复器 - 引入自有 ignored-names 抽象,降低对上游库的依赖
- 移除
C400、C401、C410、C418的 CST 修复器 - 使用
AhoCorasick加速引号匹配 - 移除
C405、C409的 CST 修复器 - 注释检测加入快速路径
zero-sleep-call反转检查顺序以提前短路- 基于导入信息短路 typing 匹配
- dunder 方法规则直接在方法上运行
- 语义模型中跟踪顶层模块导入
- 小写/大写标识符检查小幅提速
- 移除
C403的 LibCST 修复器
从这些条目可以推断:0.2.x 阶段项目正在系统性地把早期借用 LibCST 的修复逻辑替换为基于自家 AST/CST 的轻量实现,从而压缩解析与修复开销。
文档修正:max-pos-args示例更正为max-positional-args;修正weak_cryptographic_key规则中的示例代码;修正 changelog 中对已弃用ANN规则的引用;修正max-positional-args默认值。
0.2.2:f-string 格式化、CLI 配置覆盖与词法层提速
0.2.2 的官方亮点有三条:f-string 格式化的初步支持(--preview下)、通过扩展的--config参数在 CLI 覆盖任意配置项(如--config "lint.isort.combine-as-imports=false")、以及词法器(lexer)、解析器与 lint 规则的显著性能提升。
Preview 特性:
- 实现最小化 f-string 格式化
- [pycodestyle] 新增空行规则(
E301、E302、E303、E304、E305、E306) - [refurb] 新增
readlines_in_for(FURB129)
规则行为变更:
- [ruff] 多行序列的闭合括号必须独立成行(
RUF022、RUF023) - [numpy] 补充缺失的弃用违规检测(
NPY002) - [flake8-bandit] 检测装饰器中的
mark_safe用法 - [ruff]
asyncio-dangling-task(RUF006)扩展覆盖new_event_loop - [flake8-pyi] 忽略类作用域中“未使用”的私有类型字典
Formatter:
indent-style=tabs时 docstring 格式化保留 tab 缩进- notebook 禁用顶层 docstring 格式化
quote-style的preserve模式转正稳定
CLI:
- 允许在命令行覆盖任意配置选项。当前 全局参数定义 中,
--config的文档注释明确说明它既可以是配置文件路径,也可以是形如KEY = VALUE的 TOML 键值对(例如--config "lint.line-length = 100"或--config "format.quote-style = 'single'"),且这种逐项覆盖的优先级高于所有配置文件(包括同样通过--config指定的文件)。这与 0.2.2 “任意配置项 CLI 覆盖”的声明完全对应。
Bug 修复:
show-settings过滤器不再受目录影响- 重写类型别名时尊重重名
- typing 分析器尊重元组赋值
- 缓存持久化改用原子写入
DebugText使用无括号范围- [flake8-simplify] 消除
SIM113对async for循环的误报 - [flake8-trio]
timeout-without-await尊重async with - [perflint]
PERF101捕获更广泛的变异操作 - [pycodestyle] 修复
E30X在带尾随空白的空行上 panic - [pydocstyle] 允许
parameters作为小节标题(D405);修复模块级 docstring 的空行规则 - [pylint]
PLR2004接受 0.0 和 1.0 为常见魔数;不再对不可哈希类型建议 set 重写 - [ruff] 方法调用内部字符串字面量消除
RUF027漏报与 panic;缺失 f-string 检测忽略 builtin
性能:
- 字符串词法分析改用
memchr - tab 缩进检测改用
memchr - 以
Box<str>替代String缩小Result<Tok, LexicalError>体积 Expr结构体从 80 字节压缩到 64 字节- 尾逗号规则性能优化
- 解析器移除不必要的字符串克隆
升级实操清单:从 0.1.x 迁移到 0.2.x
结合 changelog 内容,迁移检查项可以归纳为四步:
- 配置迁移:把上表列出的 43 个顶层 lint 选项整体移入
[lint]表;被弃用的旧名称在过渡期仍可用,但应尽早消除警告。 - 规则代码更新:全局搜索并替换
TRY200→B904、PGH001→S307、PGH002→G010、RUF011→B035、TCH006→TCH010(含noqa注释与select/ignore列表);删除ANN101、ANN102的选择。 - 选择器清理:移除配置中的
NURSERY选择器;如果原本依赖精确代码选择 nursery 规则,改为开启 preview 或显式选择。 - CLI 选项替换:
--show-source/--no-show-source/--output-format text分别替换为--output-format full/concise的显式取值。
验证方面,仓库提供了 0.2.x 完整变更记录 作为权威对照;若升级后 lint 结果出现规则“凭空消失”,优先检查第 2 步的重映射代码是否遗漏。
版本脉络小结
0.2.x 三个版本呈现清晰的分工:0.2.0 做“减法与归位”(弃用旧接口、收敛配置命名空间、规则重映射、Preview 大规模转正),0.2.1 做“能力增量”(范围格式化)兼做性能工程,0.2.2 做“编辑器友好化”(f-string 格式化起步、--range落地后的 CLI 配置覆盖)并持续压榨词法/解析性能。这套节奏——破坏性变更集中发布、弃用期保留兼容别名、Preview 通道先行试验——贯穿了 ruff 后续的演进(可对照 changelogs/0.3.x.md 及之后的版本记录),理解 0.2.x 是掌握该项目版本策略的关键一环。
【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考