`module-import-not-at-top-of-file` (`E402`)

发布时间:2026/9/8 19:47:48
`module-import-not-at-top-of-file` (`E402`) module-import-not-at-top-of-file(E402)【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruffBasic exampleslint.select [E402]This is an example of code flagged by the rule:a 1 import os # snapshot: module-import-not-at-top-of-fileerror[E402]: Module level import not at top of file -- src/mdtest_snippet.py:2:1 | 2 | import os # snapshot: module-import-not-at-top-of-file | ^^^^^^^^^ |Additional cases can just use# errorsince the diagnostics should look the same:b 2 import something_else # error: [module-import-not-at-top-of-file]More complicated configurationIf any of your tests require special configuration options, you can define additional TOML code blocks. These blocks accept all of the configuration options that Ruff itself does:target-version py310 [lint] select [E] [lint.pycodestyle] max-line-length 100TOML 配置块接受 Ruff 本身支持的全部配置项因此可以按文件覆盖 target-version、select、以及 lint.pycodestyle 这类插件级配置。Mdtest 作为 ruff_mdtest crate 的一部分在普通 cargo test 中运行。 ## 五、实战二为诊断附加 auto-fix 当一条 lint violation 存在天然的源码修改建议时需要把 Fix 挂到诊断上。当前实现位于 DiagnosticGuard[ast/mod.rs](https://link.gitcode.com/i/a031592434697df0024eb406a867b79a)核心方法是 - set_fix(mut self, fix: Fix)直接挂接修复。注意其内部会先检查 settings.fix_safety 与该规则当前是否允许修复rules.should_fix(self.rule)再调用 resolve_applicability 计算最终的 Applicability——这正是文档所说需要决定修复是 safe 还是 unsafe的底层落点 - try_set_fix / try_set_optional_fix接受闭包形式的修复构造失败时仅记录 debug 日志而不中断诊断上报。 贡献时需要回答两个问题**何时**提供修复以及它是 **safe 还是 unsafe**。判断依据是官方fix safety文档若修复在某些情况下不安全必须在规则文档中新增 ## Fix safety 小节说明理由。 生成修复文本Edit有三种主要方式各有取舍 1. **AST-based edits**构造目标 AST 节点再用 checker.generator() 上的方法生成文本。优点是几乎不会引入语法错误、格式可预期缺点是按手工构建 AST 较繁琐且对注释的控制粒度较粗。文本生成能力来自 [crates/ruff_python_codegen](https://link.gitcode.com/i/70a9f8cc9a1d0d6246cf8c6f4e6da8c7) 2. **CST-based edits**借助 LibCST 先把源码解析成具体语法树CST再修改。相比 AST 方式它保留更多原始格式同时保持不产生语法错误的优点但引入额外开销。workspace 中 libcst 1.8.4[Cargo.toml](https://link.gitcode.com/i/b98c6275fde1b6dfbb9d9343fbb4d7a9)即此用途的依赖CST 侧代码在 crates/ruff_linter/src/cst/ 3. **Text-based edits**直接以字符串构造替换文本。控制力最强、通常性能最好但最难保证在非常规源码上不产生语法错误——若采用这种方式务必**比平时添加更多的测试 fixture**。 通用修复助手集中在 [fix/edits.rs](https://link.gitcode.com/i/fd40e3717f36f3ed2a1c37b84193516d) 与 [fix/codemods.rs](https://link.gitcode.com/i/d9a2c1e34332aa548b5bcbfbee3d328a)写新修复前应先查阅这两个文件避免重复造轮子。 ## 六、实战三新增配置项的三层数据流 Ruff 的用户可见配置分散在几处文档明确了三层的职责划分 1. **命令行选项**Args 结构体位于 [crates/ruff/src/args.rs](https://link.gitcode.com/i/ea3f192dfe758fb5723d00d37e11c1ad) 2. **pyproject.toml 选项** - Options 结构体[crates/ruff_workspace/src/options.rs](https://link.gitcode.com/i/5c3a2aa33b0de87a8a86dddf6a36c5bb)——用于**解析** pyproject.toml 的 schema - Configuration 结构体crates/ruff_workspace/src/configuration.rs——内部中间表示 - Settings 结构体crates/ruff_workspace/src/settings.rs内含 LinterSettings 字段——最终驱动 Ruff 运行的内部表示。 文档给出的最快定位手法grep dummy_variable_rgx。在当前仓库中该选项定义于 [options.rs](https://link.gitcode.com/i/5c3a2aa33b0de87a8a86dddf6a36c5bb#L710-L721)其 #[option] 宏同时承载了默认值、取值类型与示例文档 rust /// A regular expression used to identify dummy variables, or those which /// should be ignored when enforcing (e.g.) unused-variable rules. The /// default expression matches _, __, and _var, but not _var_. #[option( default r#^(_|(_[a-zA-Z0-9_]*[a-zA-Z0-9]?))$#, value_type str, example r# // 只忽略名为 _ 的变量 dummy-variable-rgx ^_$ # )] pub dummy_variable_rgx: OptionString, 即默认正则匹配 _、__、_var 等哑变量命名但不匹配 _var_。这个 #[option] 派生宏来自 ruff_macros也正是 cargo dev generate-options 与 cargo dev generate-json-schema 生成配置文档表格和 ruff.schema.json 的信息来源。 两个补充要点 - 插件专属配置单独成模块如 crates/ruff_linter/src/flake8_unused_arguments/settings.rs 的 Settings 与 crates/ruff_workspace/src/options.rs 中的 Flake8UnusedArgumentsOptions 配对 - 修改完成后同样以 cargo dev generate-all 重新生成文档与生成代码。 ### cargo dev 工具集 .cargo/config.toml 中定义了两个 alias[.cargo/config.toml](https://link.gitcode.com/i/b665b3d12a95dfeffce611e39f758c5c) toml [alias] dev run --package ruff_dev --bin ruff_dev benchmark bench -p ruff_benchmark --bench linter --bench formatter -- cargo dev 各子命令及作用对应实现均在 crates/ruff_dev/src/ 下如 [main.rs](https://link.gitcode.com/i/5e156d397990d8d5db44e4796f252940)、[print_ast.rs](https://link.gitcode.com/i/df6bb39fb396c2c2effbd01e9f35da3d) 等文件一一对应 - cargo dev print-ast file用 Ruff 的 Python parser 打印 Python 文件 AST。对 if True: pass # comment可见语法树、每个节点的起止字节偏移以及 : token、注释与空白如何不再被表示 text [ If( StmtIf { range: 0..13, test: Constant( ExprConstant { range: 3..7, value: Bool( true, ), kind: None, }, ), body: [ Pass( StmtPass { range: 9..13, }, ), ], orelse: [], }, ), ] - cargo dev print-tokens file打印 AST 所基于的 token 流同一输入 text 0 If 2 3 True 7 7 Colon 8 9 Pass 13 14 Comment( # comment, ) 23 23 Newline 24 - cargo dev print-cst file打印 LibCST 的 CST。与 AST 不同CST 中**包括空白在内的一切**都被表示出来例如 leading_whitespace、trailing_whitespace内含 comment: Some(Comment(# comment)) 与换行等字段完整保留。CST 输出更长此处略其价值在于支撑 CST-based auto-fix 对原始格式的保真。 - cargo dev generate-all更新 ruff.schema.json、docs/configuration.md 与 docs/rules。也可以设置 RUFF_UPDATE_SCHEMA1让 cargo test 过程中顺带更新 ruff.schema.json - cargo dev generate-cli-help / generate-docs / generate-json-schema分别只更新 docs/configuration.md、docs/rules、ruff.schema.json - cargo dev generate-options生成所有 pyproject.toml 选项的 Markdown 表格供官方设置页使用 - cargo dev generate-rules-table生成全部规则的 Markdown 表格供官方规则页使用 - cargo dev round-trip python file or jupyter notebook读入、解析、再序列化回写用于检验表示层多无损——保证 auto-fix 不会重写文件的无关部分 - cargo dev format_devformatter 开发工具详见 [crates/ruff_python_formatter](https://link.gitcode.com/i/ce8a9ce4d6c826029afe81747ebcde06)。 ## 七、MkDocs 文档预览与生态 CI ### 本地预览文档站 修改 docs/ 下的文档后可本地起站验证 1. 安装 Rust 工具链 2. 生成 MkDocs 站点由模板 mkdocs.template.yml 产出 mkdocs.yml shell uv run scripts/generate_mkdocs.py 3. 启动开发服务器 shell uv run --only-groupdocs mkdocs serve -f mkdocs.yml 随后在本地 http://127.0.0.1:8000/ruff/ 查看文档。 ### 生态 CI改动对真实项目的行为 diff GitHub Actions 会在你的 PR 上把改动应用到一批真实开源项目报告 linter 与 formatter 的行为差异本地可用 [python/ruff-ecosystem](https://link.gitcode.com/i/e1e116e0fd0eb4654069e816f82dfdfa) 包复现源码位于 python/ruff-ecosystem/ruff_ecosystem/含 check.py、format.py、projects.py 等模块 shell uvx --from ./python/ruff-ecosystem ruff-ecosystem check ruff ./target/debug/ruff uvx --from ./python/ruff-ecosystem ruff-ecosystem format ruff ./target/debug/ruff PR 合并前主动浏览这些 diff 并把结论写进 PR 描述能显著加快评审发现异常行为时它们也是现成的新测试用例来源。 ## 八、PR 规范、发布流程与 Rust 升级 ### PR 描述的两段式 - **Summary**给维护者的信息——相关 issue 链接、问题与修复方案摘要对方案有疑问、或考虑过替代方案都值得写进来。AI 可以帮助生成代码与总结但最终稿必须经过你自己仔细审阅与编辑优秀的 issue/PR 可检索 great writeup 标签参考 - **Test plan**通常比 summary 短规则类 bug 可以一句Added new snapshot tests for RUF123LSP 或 CLI 类改动则建议附上截图或录屏。 其他 PR 状态约定改动过程中请把 PR 移回 draft重新标记 ready for review 会 ping 原审阅人或显式重新请求评审对已处理的评审评论可点resolved或点赞确认。 ### 发布流程Release Process Ruff 采用高频、adhoc 的发布模式通过 GitHub Actions 自动生成各架构 wheel 并发布到 PyPI。遵循 semver但作为 1.0 之前的软件**补丁版本也可能包含不向后兼容的变更**。流程要点每步单独提交以便评审 1. 工具准备安装 uv 与 npm 2. 运行 ./scripts/release.sh[scripts/release.sh](https://link.gitcode.com/i/a32077a139d5637b880fa12666e1422f)它会用 rooster 生成临时虚拟环境、在 CHANGELOG.md 中生成 changelog 条目、更新 pyproject.toml 与 Cargo.toml 中的版本、更新 README.md 与文档中的版本引用、展示本次贡献者列表 3. 编辑 changelog 使其面向用户补标签、去掉内部细节prek 会自动转义方括号。minor 版本还要把既有 CHANGELOG.md 内容迁移到 changelogs/0.MINOR.x.md如准备发布 0.12.0 时把 0.11 系列迁入 changelogs/0.11.x.md并反转条目使最老版本在前——可用 uv 仓库的 reverse-changelog.py 自动完成 4. 在 [BREAKING_CHANGES.md](https://link.gitcode.com/i/1851359b50f058e3bb96895ff63df405) 中高亮破坏性变更 5. 运行 cargo check 刷新锁文件 6. 打开并合并changelog 版本更新的 PR 7. 手动触发 release workflow填入不带 v 前缀的新版本号并请求另一位团队成员做部署审批。workflow 依次构建全部产物失败时可直接修复后重跑注意要重跑**所有**失败 job 而非单个→ 等待审批 → 上传 PyPI → 从 pyproject.toml 提取版本创建并推送 Git tag刻意放在 wheel 上传之后因为 tag 无法删除或修改→ 把产物挂到 draft GitHub Release → 触发下游仓库失败可后续手动补偿 8. 验证 GitHub Release 的 changelog 与 CHANGELOG.md 一致 9. 如 git diff old-version-tag new-version-tag -- ruff.schema.json 非空需运行 uv run scripts/update_schemastore.py --proto https|ssh 更新 schemastore并按输出链接创建 PR 10. 按 ruff-vscode 仓库的发布说明同步 VS Code 扩展。 ### 升级 Rust 工具链 1. 修改 [rust-toolchain.toml](https://link.gitcode.com/i/b4b5ec36a652482c1b064d9807e17abf) 中 channel 为新版本 2. 修改根 [Cargo.toml](https://link.gitcode.com/i/ea274ab50c1f4056d688d747fb257494) 中 rust-version 为 latest - 2例如最新是 1.86 则写 1.84 3. cargo clippy --fix --allow-dirty --allow-staged 修复新版本的 clippy 告警 4. 提交并合并 PR 5. 在 conda-forge 的 ruff recipe 中同步升级 Rust 版本。 ## 九、基准测试、性能剖析与子系统内幕 ### 基准测试的三种姿势 CONTRIBUTING.md 给出三类性能工作 1. 主性能基准在 CPython 代码库上与生态工具对比 2. 微基准microbenchmarks对单文件运行 linter/formatter会在 PR 上自动执行 3. 剖析profiling对微基准或整个项目做火焰图分析。 注意跑基准时确保 CPU 处于空闲关闭浏览器等后台应用若有performance电源模式建议切换尤其是短生命周期进程。 **CPython 基准**先克隆 CPython 3.10 到测试资源目录 shell git clone --branch 3.10 cpython-repo crates/ruff_linter/resources/test/cpython 对比缓存开/关、以及子集规则如 --select W505,E501的 hyperfine 命令示例示意输出带缓存的 check 比 --no-cache 快约 6 倍说明 ruff_cache 的收益 shell cargo build --release --bin ruff uv run --only-dev hyperfine --warmup 10 \ ./target/release/ruff check ./crates/ruff_linter/resources/test/cpython/ --no-cache -e \ ./target/release/ruff check ./crates/ruff_linter/resources/test/cpython/ -e 与 pyflakes / autoflake / pycodestyle / flake8 的对比命令形如 shell uv run --only-dev hyperfine --ignore-failure --warmup 5 \ ./target/release/ruff check ./crates/ruff_linter/resources/test/cpython/ --no-cache \ pyflakes crates/ruff_linter/resources/test/cpython \ pycodestyle crates/ruff_linter/resources/test/cpython \ flake8 crates/ruff_linter/resources/test/cpython 文档中还给出了 Pylint 与 Pyupgrade 的对照跑法前者需先剔除 CPython 中一批会致其失败/超时的测试文件再以 time pylint -j 0 -E $(git ls-files *.py) 全并行仅报 error后者用 hyperfine --prepare git reset --hard HEAD 配合 find . -name *.py | xargs -P 0 pyupgrade --py311-plus。全部对比基准使用 [scripts/benchmarks/pyproject.toml](https://link.gitcode.com/i/db8867dc864c2bfe00e55c820a4bea53) 钉住的版本与 Python 3.11 计算。 **微基准**ruff_benchmark crate 对单文件基准化 linter 与 formatter。cargo benchmark 即 .cargo/config.toml 中的 alias等价于 cargo bench -p ruff_benchmark --bench linter --bench formatter --。Ruff 使用 Criterion.rs支持基线对比benchmark-driven development shell # 在基线代码如 main上存一次基线 cargo bench -p ruff_benchmark -- --save-baselinemain # 迭代开发时与基线对比 cargo bench -p ruff_benchmark -- --baselinemain PR 总结时可用 critcmpcargo install --locked critcmp对 main 与 pr 两次录制做可视化对比。常用技巧cargo bench -p ruff_benchmark lexer 只跑 lexer 基准-- --quiet 精简输出-- --quick 加快但噪声更大。 **项目级剖析** - Linux安装 perf以 profiling profile 构建 ruff_benchmarkworkspace 中定义了 [profile.profiling]继承 release 但 strip false、debug full、lto false专供基准与符号化 shell cargo bench -p ruff_benchmark --no-run --profileprofiling perf record --call-graph dwarf -F 9999 cargo bench -p ruff_benchmark --profileprofiling -- --profile-time1 也可用 ruff_dev 的 repeat 子命令对某仓库反复执行 ruff check 以积累足够样本示例中 --repeat 30 --exit-zero --no-cache采样率 999 均可按需调整 shell cargo build --bin ruff_dev --profileprofiling perf record -g -F 999 target/profiling/ruff_dev repeat --repeat 30 --exit-zero --no-cache path/to/cpython /dev/null perf script -F pid /tmp/test.perf 产物可用 Firefox Profiler 打开或用 flamegraphcargo install flamegraph转成 flamegraph.svgflamegraph --perfdata perf.data --no-inline。 - Maccargo install --locked cargo-instruments然后 shell cargo instruments -t time --bench linter --profile profiling -p ruff_benchmark -- --profile-time1 -t 选择剖析维度time 剖析墙钟时间alloc 剖析内存分配并可追加过滤只跑单个基准文件其余步骤同 Linux。 ### 编译管线Compilation Pipeline 若把 Ruff 视为一个编译器——输入是 Python 文件路径、输出是诊断——其管线为 1. **File discovery**给定 foo/ 等路径在指定子目录中定位全部 Python 文件考虑分层配置系统与 exclude 选项 2. **Package resolution**向上遍历父目录寻找 __init__.py确定每个文件的包根package root 3. **Cache initialization**为每个包根初始化空缓存 4. **Analysis**每个文件并行 1. **Cache read**文件修改时间戳未变则直接短路返回缓存诊断即第七节缓存对比基准里 6 倍加速的来源实现见 crates/ruff_cache 2. **Tokenization**lexer 生成 token 流 3. **Indexing**从 token 流抽取元数据——注释区间、# noqa 位置、# isort: off 位置、doc lines 等 4. **Token-based rule evaluation**跑基于 token 流的规则如注释掉的代码 5. **Filesystem-based rule evaluation**跑基于文件系统的规则如包缺少 __init__.py 6. **Logical line-based rule evaluation**跑基于逻辑行的规则风格类规则 7. **Parsing**把 token 流解析成 ASTtoken 流在此被消耗所以依赖 token 流的步骤必须在此之前完成 8. **AST-based rule evaluation**跑基于 AST 的规则——绝大多数 lint 规则属于此类。遍历 AST 时同步构建语义模型部分规则即时求值部分延迟求值例如 unused imports 必须等整个文件分析完才能判定延迟规则在初次遍历结束后执行 9. **Import-based rule evaluation**跑基于模块 import 的规则如 import 排序理论上可并入 AST 阶段单独拆出仅为简化 10. **Physical line-based rule evaluation**跑基于物理行的规则如行宽 11. **Suppression enforcement**移除被 # noqa 或 per-file-ignores 抑制的违规 12. **Cache write**以文件为键把诊断写入包级缓存 5. **Reporting**按指定格式text、JSON 等与输出通道stdout、文件等打印诊断。 这条管线解释了第四节中新规则放哪个 checker的选型依据token 规则、文件系统规则、逻辑行规则、物理行规则、AST 规则、import 规则各有独立执行阶段分别对应 checkers/ 下的 tokens.rs、filesystem.rs、logical_lines.rs、physical_lines.rs、ast/、imports.rs。 ### Import 归类project root、package root 与五分类 理解 Ruff 的 import 归类排序与格式化 import 块的核心先明确两个概念 - **Project root**包含 pyproject.toml、ruff.toml 或 .ruff.toml 的目录取每个 Python 文件的最近配置目录通过 ruff --config /path/to/pyproject.toml 运行时当前工作目录即被用作 project root - **Package root**包含给定 Python 文件的 Python 包的最上层目录——沿父目录向上走直到遇到不含 __init__.py 的目录或被标记为 namespace package 的子树取其前一级目录。 示例布局 text my_project ├── pyproject.toml └── src └── foo ├── __init__.py └── bar ├── __init__.py └── baz.py【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考