内容提要
Ruff v0.0.278 发布,用 Rust 编写,速度极快,可替代 Flake8 等工具。更新包括:无效 # noqa 指令现发警告;# flake8: noqa 支持指定代码;isort 设置支持 glob。新增规则:RUF015 用 next(iter()) 替代 list()[0]、RUF016 检查无效索引类型、B034 检查 re.sub 位置参数、PYI030 合并 Literal 联合、PLC0105 和 PLC0131 检查类型变量方差。修复多项 bug。
延伸解读
无效 # noqa 指令的处理变化
此前,无效的 # noqa 指令可能被静默忽略,或被当作全局抑制注释,导致意外忽略整行违规。现在 Ruff 会为每个无效指令发出警告,例如 # noqa: unused-import 会提示需要逗号分隔的代码列表。这有助于开发者及时发现并修正错误的抑制注释,避免遗漏本应检查的问题。
文件级代码抑制的增强
Ruff 原本支持 # ruff: noqa: F401 来抑制文件中的特定违规,但 # flake8: noqa: F401 会被当作抑制所有违规。现在 # flake8: noqa: F401 也能正确抑制指定代码,与 # ruff: noqa: F401 行为一致。这为从 Flake8 迁移的用户提供了更细粒度的控制,减少误抑制。
isort 配置支持 glob 模式
isort 的 known-first-party 等设置现在除了模块名,还接受 glob 模式。例如 known-first-party = "my_module_*" 可将所有以 my_module_ 开头的模块标记为第一方。这简化了大型项目中模块分类的配置,避免逐个列出模块名。
新增规则 RUF015 的注意事项
RUF015 建议用 next(iter(...)) 替代 list(...)[0],以避免创建整个列表。但迁移时需注意行为差异:list(...) 会立即评估整个集合,而 next(iter(...)) 只评估第一个元素,可能延迟副作用;且空集合时前者引发 IndexError,后者引发 StopIteration。该规则可自动修复,但需确认这些变化不影响程序逻辑。
Q&A
Ruff v0.0.278 对无效的 # noqa 指令做了什么改变?
现在会对每个无效的 # noqa 指令发出警告,而不是静默忽略或当作全局抑制。例如,`import os # noqa: unused-import` 会触发警告,提示应使用逗号分隔的代码列表。
Ruff 现在支持用 # flake8: noqa 来抑制特定代码吗?
是的,Ruff 现在支持 `# flake8: noqa: F401` 这样的语法来抑制特定代码,而之前只支持 `# ruff: noqa: F401`。
isort 的 known-first-party 设置现在支持通配符吗?
是的,现在 known-first-party 等设置支持 glob 模式。例如,`known-first-party = "my_module_*"` 会将所有以 my_module_ 开头的模块标记为第一方。
RUF015 规则是什么?它有什么作用?
RUF015 检查可以用 `next(iter(...))` 替代的 `list(...)[0]` 用法。这样可以避免创建整个列表,惰性获取第一个元素,但注意行为变化:延迟副作用,且空集合时抛出 StopIteration 而非 IndexError。该规则可自动修复。
RUF016 规则检查什么?为什么重要?
RUF016 检查对列表、字符串、元组、字节和推导式使用非整数或切片类型进行索引。这会导致运行时 TypeError 和导入时 SyntaxWarning,因此应使用整数或切片。
B034 规则是关于什么的?
B034 检查对 re.sub、re.subn 和 re.split 的调用中,将 count、maxsplit 或 flags 作为位置参数传递的情况。建议改为关键字参数,以避免混淆,因为 re 模块中大多数方法接受 flags 作为第三个位置参数,而这些函数签名不同。
PYI030 规则建议如何合并 Literal 类型?
PYI030 检查联合类型中多个 Literal 类型,建议合并为单个 Literal。例如,将 `Literal[1] | Literal[2]` 改为 `Literal[1, 2]`。
PLC0105 和 PLC0131 规则分别检查什么?
PLC0105 检查类型名称是否与类型参数的变体匹配,建议使用 _co 和 _contra 后缀。PLC0131 检查 TypeVar 和 ParamSpec 定义中同时标记为协变和逆变的情况,建议改为单一变体或使用两个类型参数。