From 2a3f094a6282f8826f4f08cb601041a51426ca77 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Mon, 22 Dec 2025 13:24:07 -0500 Subject: [PATCH] cache checker.path.ends_with("__init__.py") checks this is actually the only reason Checker::path() was used and nearly the only reason the field Checker::path exists. there's only one remaining reference to the field in a debug logging call --- .../checkers/ast/analyze/unresolved_references.rs | 2 +- crates/ruff_linter/src/checkers/ast/mod.rs | 15 ++++++++++----- .../src/rules/pyflakes/rules/unused_import.rs | 2 +- .../rules/pylint/rules/useless_import_alias.rs | 4 ++-- .../src/rules/ruff/rules/non_empty_init_module.rs | 2 +- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/unresolved_references.rs b/crates/ruff_linter/src/checkers/ast/analyze/unresolved_references.rs index 4a6764a119..fd781b8452 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/unresolved_references.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/unresolved_references.rs @@ -33,7 +33,7 @@ pub(crate) fn unresolved_references(checker: &Checker) { } // Allow __path__. - if checker.path.ends_with("__init__.py") { + if checker.in_init_module() { if reference.name(checker.source()) == "__path__" { continue; } diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 37422cbf18..be8bc4b275 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -21,7 +21,7 @@ //! represents the lint-rule analysis phase. In the future, these steps may be separated into //! distinct passes over the AST. -use std::cell::RefCell; +use std::cell::{OnceCell, RefCell}; use std::path::Path; use itertools::Itertools; @@ -198,6 +198,8 @@ pub(crate) struct Checker<'a> { parsed_type_annotation: Option<&'a ParsedAnnotation>, /// The [`Path`] to the file under analysis. path: &'a Path, + /// Whether `path` points to an `__init__.py` file. + in_init_module: OnceCell, /// The [`Path`] to the package containing the current file. package: Option>, /// The module representation of the current file (e.g., `foo.bar`). @@ -274,6 +276,7 @@ impl<'a> Checker<'a> { noqa_line_for, noqa, path, + in_init_module: OnceCell::new(), package, module, source_type, @@ -482,9 +485,11 @@ impl<'a> Checker<'a> { self.context.settings } - /// The [`Path`] to the file under analysis. - pub(crate) const fn path(&self) -> &'a Path { - self.path + /// Returns whether the file under analysis is an `__init__.py` file. + pub(crate) fn in_init_module(&self) -> bool { + *self + .in_init_module + .get_or_init(|| self.path.ends_with("__init__.py")) } /// The [`Path`] to the package containing the current file. @@ -3171,7 +3176,7 @@ impl<'a> Checker<'a> { // F822 if self.is_rule_enabled(Rule::UndefinedExport) { if is_undefined_export_in_dunder_init_enabled(self.settings()) - || !self.path.ends_with("__init__.py") + || !self.in_init_module() { self.report_diagnostic( pyflakes::rules::UndefinedExport { diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs index 88936e22ab..af1ae56a0d 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs @@ -389,7 +389,7 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope) { } } - let in_init = checker.path().ends_with("__init__.py"); + let in_init = checker.in_init_module(); let fix_init = !checker.settings().ignore_init_module_imports; let preview_mode = is_dunder_init_fix_unused_import_enabled(checker.settings()); let dunder_all_exprs = find_dunder_all_exprs(checker.semantic()); diff --git a/crates/ruff_linter/src/rules/pylint/rules/useless_import_alias.rs b/crates/ruff_linter/src/rules/pylint/rules/useless_import_alias.rs index 63f53fe8fb..8e5332e92f 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/useless_import_alias.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/useless_import_alias.rs @@ -70,7 +70,7 @@ pub(crate) fn useless_import_alias(checker: &Checker, alias: &Alias) { } // A re-export in __init__.py is probably intentional. - if checker.path().ends_with("__init__.py") { + if checker.in_init_module() { return; } @@ -109,7 +109,7 @@ pub(crate) fn useless_import_from_alias( } // A re-export in __init__.py is probably intentional. - if checker.path().ends_with("__init__.py") { + if checker.in_init_module() { return; } diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_empty_init_module.rs b/crates/ruff_linter/src/rules/ruff/rules/non_empty_init_module.rs index aeccb73b80..da71c9728f 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_empty_init_module.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_empty_init_module.rs @@ -66,7 +66,7 @@ impl Violation for NonEmptyInitModule { /// RUF070 pub(crate) fn non_empty_init_module(checker: &Checker, stmt: &ast::Stmt) { - if !checker.path().ends_with("__init__.py") { + if !checker.in_init_module() { return; }