Ruff RUF201 规则详解:在 ruff.toml 选择器中使用人类可读规则名(rule-codes-in-selectors)
Ruff RUF201 规则详解:在 ruff.toml 选择器中使用人类可读规则名(rule-codes-in-selectors)【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff本文围绕 Ruff 的RUF201(rule-codes-in-selectors)规则展开,完整解析这条“面向配置文件本身”的 Lint 规则:它如何检查ruff.toml与pyproject.toml中select、ignore、per-file-ignores等选择器是否误用了F401这类规则代码,如何给出安全自动修复把代码替换为unused-import这类人类可读名称,以及它在什么条件下生效(Preview 模式)。读完后你能在项目中正确启用该规则、理解其扫描范围与边界行为,并能对照 Ruff 源码验证其底层实现。规则定位:检查配置文件中的人类可读规则名RUF201属于 Ruff 自有的Ruff规则集(代码前缀RUF),分类为Pedantic,自0.15.22起以 Preview 状态提供(见 crates/ruff_linter/src/rules/ruff/rules/rule_codes_in_selectors.rs 中的violation_metadata(preview_since 0.15.22, category Category::Pedantic);RUF201于 changelogs/0.15.x.md 的 Preview features 一节随 PR #26772 引入)。它的职责与其他规则不同——不是检查 Python 源码,而是检查Ruff 的配置文件本身:What it does: Checks for any configuration files that use rule codes as selectors.Why is this bad?: Human-readable rule names are easier to understand than rule codes. Using names also avoids requiring readers to look up the meaning of each code.(What it does:检查配置文件中把规则代码当作选择器使用的情况;Why is this bad:人类可读的规则名比代码更易理解,无需读者逐个查表。)— 规则文档注释(rule_codes_in_selectors.rs)官方文档注释给出的最小示例:[tool.ruff.lint] select [F401]应改写为:[tool.ruff.lint] select [unused-import]规则注册表中,RUF201 的映射为(Ruff, 201) rules::ruff::rules::RuleCodesInSelectors(见 crates/ruff_linter/src/codes.rs);并且它在 crates/ruff_linter/src/registry.rs 中被标记为LintSource::Toml——这决定了它只会在 Lint TOML 配置文件时被触发,而不会出现在普通 Python 文件上。启用条件:必须开启 PreviewRUF201是 Preview 规则。规则入口函数的第一件事就是检查开关:// crates/ruff_linter/src/rules/ruff/rules/rule_codes_in_selectors.rs (L67-L74) pub(crate) fn rule_codes_in_selectors( context: LintContext, document: DeTable_, source_type: TomlSourceType, ) { if !is_human_readable_names_enabled(context.settings().preview) { return; } ...而 crates/ruff_linter/src/preview.rs 中的判定非常简单:pub const fn is_human_readable_names_enabled(preview: PreviewMode) - bool { preview.is_enabled() }也就是说,从源码结构看,只要preview开启,is_human_readable_names_enabled即返回 true,规则即可工作(注释中注明这是“人类可读规则名”特性的统一开关,后续稳定化时才有机会收紧)。对应到配置文件,就是文档测试中使用的标准启用方式:[lint] preview true select [rule-codes-in-selectors]注意这里select里直接写的是规则名rule-codes-in-selectors而不是RUF201——在 Preview 模式下,Ruff 的解析器本身就接受人类可读规则名作为选择器(解析逻辑见 crates/ruff_linter/src/rule_selector.rs,其中Rule::from_name(selector)分支在is_human_readable_names_enabled为真时才放行)。触发链路:从 lint_toml 到规则函数TOML 配置文件的 Lint 入口在 crates/ruff_linter/src/toml.rs:pub fn lint_toml( path: Path, contents: str, settings: LinterSettings, source_type: TomlSourceType, ) - VecDiagnostic { let context LintContext::new(path, contents, settings); let document DeTable::parse(contents); if context.is_rule_enabled(Rule::RuleCodesInSelectors) let Ok(document) document { rule_codes_in_selectors(context, document.get_ref(), source_type); } ... }可以看到整个调用链:DeTable::parse把配置解析成带位置信息的 TOML 文档 → 规则启用检查(is_rule_enabled)→rule_codes_in_selectors遍历选择器字段 → 通过context.report_diagnostic上报诊断。若配置了--fix,同文件的lint_fix_toml会迭代应用修复直到收敛(最多MAX_ITERATIONS轮)。配置文件定位:ruff.toml 与 pyproject.toml规则函数按文件类型(TomlSourceType)定位 Ruff 配置根:// rule_codes_in_selectors.rs (L76-L93) let ruff match source_type { TomlSourceType::Pyproject document .get(tool) .and_then(|tool| tool.get_ref().get(ruff)) .and_then(|ruff| ruff.get_ref().as_table()), TomlSourceType::Ruff Some(document), _ None, };ruff.toml:整个文档就是 Ruff 配置,文档根即配置根;pyproject.toml:只检查[tool.ruff]表;其余 TOML 文件:直接跳过。定位到配置根后,规则会对顶层(已废弃的顶层设置)与[lint]表两处都调用check_selectors,后者通过in_lint_table布尔值影响诊断消息前缀(见下文)。检查范围:哪些选择器字段会被扫描源码用两个常量清单定义扫描目标(rule_codes_in_selectors.rs):数组型选择器(ARRAY_SELECTORS)——值本身是字符串数组:字段用途select选定的规则集合extend-select扩展选定规则fixable/extend-fixable可自动修复的规则ignore/extend-ignore忽略的规则unfixable/extend-unfixable禁止自动修复的规则extend-safe-fixes/extend-unsafe-fixes追加的安全/不安全修复开关表型选择器(TABLE_SELECTORS)——值是按 glob 路径分组的表:字段示例per-file-ignores/extend-per-file-ignoresper-file-ignores { foo.py [E501] }check_selectors的遍历逻辑:对数组型字段,若值是DeValue::Array则逐项检查;对表型字段,先确认值是DeValue::Table,再对每个路径条目确认其值是数组后逐项检查。一个值得注意的工程约定写在 crates/ruff_linter/src/rule_selector.rs 的文档注释里:If you add a new field that uses this type, be sure to updaterule-codes-in-selectors(RUF201) to validate the additional selector field.即:未来新增使用UnresolvedRuleSelector类型的配置字段时,必须同步扩展 RUF201 的扫描清单——这从源码层面保证了该规则与配置 schema 的演进保持同步。实战演示:文档测试中的五组场景仓库自带的 mdtest 文档 crates/ruff_linter/resources/mdtest/ruff/rule-codes-in-selectors.md 本身就是一份“可运行的规格说明”:它由 mdtest 测试框架(crates/mdtest/src 中的断言与解析器)执行,文中# snapshot: rule-codes-in-selectors标记的行会触发快照断言,# error: [rule-codes-in-selectors]注释标记行会断言对应行必须产出诊断。以下按文档原始小节完整还原其行为。场景一:各种引号风格均能命中ruff.toml:[lint] select [ F401, # snapshot: rule-codes-in-selectors F402, # snapshot: rule-codes-in-selectors F403, # snapshot: rule-codes-in-selectors F404, # snapshot: rule-codes-in-selectors ]四条字符串(单引号、双引号、三引号两种形式)全部被标记,诊断输出形如(首条示例):error[RUF201]: Rule code used instead of name in lint.select -- src/ruff.toml:3:6 | 3 | F401, # snapshot: rule-codes-in-selectors | ^^^^ help: Replace rule code with unused-import | 2 | select [ - F401, # snapshot: rule-codes-in-selectors 3 unused-import, # snapshot: rule-codes-in-selectors 4 | F402, # snapshot: rule-codes-in-selectors |四个代码到规则名的映射(来自该文档的快照输出):代码人类可读名F401unused-importF402import-shadowed-by-loop-varF403undefined-local-with-import-starF404late-future-import注意高亮位置^^^^精确落在引号内部的代码上,而非整段字符串。这由RuleCode::from_spanned完成:先取 TOML span 覆盖的范围,再从两侧裁掉等长的引号(rule_codes_in_selectors.rs):// 注释原文:提取的代码范围对应代码本身而非周围的引号 let content string.trim_start_matches([, \]); let quote_len string.text_len() - content.text_len(); let start range.start() quote_len; let end range.end() - quote_len;场景二:无效代码不误报,合法代码照常分析文档明确指出:无效规则代码不会被标记,包括像F401(带嵌套引号)这类畸形值,但同一选择器数组里的合法代码仍然会被分析:ruff.toml:[lint] # snapshot: rule-codes-in-selectors select [F401, F402]只有第二个元素F402被标记:error[RUF201]: Rule code used instead of name in lint.select -- src/ruff.toml:3:22 | 3 | select [F401, F402] | ^^^^ help: Replace rule code with import-shadowed-by-loop-var对应实现上,RuleCode::from_spanned要求Rule::from_code(code)解析成功才返回Some(失败的项直接continue),并先经过get_redirect_target处理重定向代码——因此重定向前的旧代码也能被解析并映射到规范规则名。场景三:畸形选择器形状被安全跳过为防止极端情况(这些形状本应被配置反序列化拦截,但规则做了防御):ruff.toml:[lint] select { nested [F401] } per-file-ignores [F401]该场景不产生任何诊断。源码中check_selectors对select只做if let DeValue::Array(...)匹配、对per-file-ignores只做if let DeValue::Table(...)匹配,形状不符即跳过——这是“宁可不报也不 panic”的健壮性设计。场景四:前缀与规则名保持原样[lint] select [F, unused-import]单字母/单段前缀(如F表示全部 Pyflakes 规则)和已经是人类可读名的选择器都不标记。源码中这与Rule::from_code的行为一致:仅当字符串能解析为“某个具体规则”的代码时才处理,前缀(F)和规则名(unused-import)都不满足。场景五:全覆盖——顶层废弃设置与[lint]表都扫描这是文档中最能说明扫描面的用例,顶层(已废弃)与[lint]表中的全部 12 个选择器字段逐一验证:select [F401] # error: [rule-codes-in-selectors] extend-select [F841] # error: [rule-codes-in-selectors] fixable [E501] # error: [rule-codes-in-selectors] extend-fixable [UP035] # error: [rule-codes-in-selectors] ignore [F401] # error: [rule-codes-in-selectors] extend-ignore [F841] # error: [rule-codes-in-selectors] per-file-ignores { foo.py [E501] } # error: [rule-codes-in-selectors] extend-per-file-ignores { bar.py [UP035] } # error: [rule-codes-in-selectors] unfixable [F401] # error: [rule-codes-in-selectors] extend-unfixable [F841] # error: [rule-codes-in-selectors] extend-safe-fixes [E501] # error: [rule-codes-in-selectors] extend-unsafe-fixes [UP035] # error: [rule-codes-in-selectors] [lint] select [F401] # error: [rule-codes-in-selectors] extend-select [F841] # error: [rule-codes-in-selectors] fixable [E501] # error: [rule-codes-in-selectors] extend-fixable [UP035] # error: [rule-codes-in-selectors] ignore [F401] # error: [rule-codes-in-selectors] extend-ignore [F841] # error: [rule-codes-in-selectors] per-file-ignores { foo.py [E501] } # error: [rule-codes-in-selectors] extend-per-file-ignores { bar.py [UP035] } # error: [rule-codes-in-selectors] unfixable [F401] # error: [rule-codes-in-selectors] extend-unfixable [F841] # error: [rule-codes-in-selectors] extend-safe-fixes [E501] # error: [rule-codes-in-selectors] extend-unsafe-fixes [UP035] # error: [rule-codes-in-selectors]每行都必须产出诊断。这也解释了诊断消息中的in_lint_table分支(rule_codes_in_selectors.rs):在[lint]表内时报Rule code used instead of name in lint.select,在顶层废弃设置处则报in select。场景六:pyproject.toml 的 [tool.ruff][tool.ruff] ignore [F401] # error: [rule-codes-in-selectors] [tool.ruff.lint] select [F402] # error: [rule-codes-in-selectors]pyproject.toml中同样同时覆盖顶层[tool.ruff]与[tool.ruff.lint]两层,与ruff.toml的行为一致。场景七:尊重用户的 unfixable 设置文档最后验证 RUF201 这类 TOML 专用规则也遵守unfixable配置:[lint] preview true select [rule-codes-in-selectors] unfixable [rule-codes-in-selectors]# ruff.toml # snapshot: rule-codes-in-selectors lint.select [F401]此时诊断照常产出,但不再附带修复(快照中只剩消息,没有修复行):error[RUF201]: Rule code used instead of name in lint.select -- src/ruff.toml:2:17 | 2 | lint.select [F401] | ^^^^ help: Replace rule code with unused-import文档说明该行为同样覆盖extend-unsafe-fixes、per-file-ignores等所有经由LintContext统一处理的修复开关。修复本体是一个安全编辑(Fix::safe_edit(Edit::range_replacement(name, range)),rule_codes_in_selectors.rs),只替换引号内的代码部分,保留原有引号风格与行尾注释。从命令行验证:一次可复现的运行集成测试 crates/ruff/tests/cli/lint.rs 展示了端到端的 CLI 用法:对包含lint.select [F401]的ruff.toml执行:ruff check --no-cache --isolated --preview --select RUF201预期输出(摘自该测试的内联快照):rule-codes-in-selectors: [*] Rule code used instead of name in lint.select -- ruff.toml:1:17 | 1 | lint.select [F401] | ^^^^ help: Replace rule code with unused-import | - lint.select [F401] 1 lint.select [unused-import]要点:必须带--preview,否则规则不启用(见上文 Preview 门槛);--isolated保证不受其他配置干扰,--no-cache保证每次真实执行;诊断标记[*]表示附带可自动修复(未声明unfixable时)。配合--fix,Ruff 会迭代应用修复直到诊断稳定(lint_fix_toml的循环实现,见 crates/ruff_linter/src/toml.rs)。小结:RUF201 的行为边界一览维度行为依据生效前提Preview 模式(preview true或--preview)preview.rs适用文件ruff.toml与pyproject.toml的[tool.ruff]rule_codes_in_selectors.rs扫描字段10 个数组型 2 个表型选择器,顶层与[lint]两处rule_codes_in_selectors.rs不标记无效代码、嵌套引号值、前缀(如F)、已是规则名的选择器rule-codes-in-selectors.md 场景二/四安全跳过形状错误的值(select为表、per-file-ignores为数组)check_selectors的if let收窄高亮范围精确到引号内的代码,不含引号RuleCode::from_spanned修复安全修复,替换为规则名;受unfixable等LintContext设置约束rule_codes_in_selectors.rs演进约定新增选择器字段时必须同步更新本规则rule_selector.rs作为“人类可读规则名”这一 Preview 特性在配置侧的组成部分,RUF201 让ruff.toml/pyproject.toml本身也能被 Lint:在开启 Preview 的项目里,select [unused-import]这类写法从此有工具层面的保障,而F401这类代码一旦出现在选择器中,会获得带精确位置和安全修复的即时反馈。【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →