mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-02 18:02:58 +00:00
Respect noqa directives on ImportFrom
parents for type-checking rules (#4889)
This commit is contained in:
parent
c2a3e97b7f
commit
7b0fb1a3b4
5 changed files with 59 additions and 35 deletions
|
@ -150,3 +150,17 @@ def f():
|
|||
|
||||
def f():
|
||||
import pandas as pd
|
||||
|
||||
|
||||
def f():
|
||||
from pandas import DataFrame # noqa: TCH002
|
||||
|
||||
x: DataFrame = 2
|
||||
|
||||
|
||||
def f():
|
||||
from pandas import ( # noqa: TCH002
|
||||
DataFrame,
|
||||
)
|
||||
|
||||
x: DataFrame = 2
|
||||
|
|
|
@ -4410,13 +4410,8 @@ impl<'a> Checker<'a> {
|
|||
},
|
||||
binding.trimmed_range(&self.semantic_model, self.locator),
|
||||
);
|
||||
if let Some(parent) = binding.source {
|
||||
let parent = self.semantic_model.stmts[parent];
|
||||
if parent.is_import_from_stmt()
|
||||
&& parent.range().contains_range(binding.range)
|
||||
{
|
||||
diagnostic.set_parent(parent.start());
|
||||
}
|
||||
if let Some(range) = binding.parent_range(&self.semantic_model) {
|
||||
diagnostic.set_parent(range.start());
|
||||
}
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
@ -5044,13 +5039,8 @@ impl<'a> Checker<'a> {
|
|||
},
|
||||
binding.trimmed_range(&self.semantic_model, self.locator),
|
||||
);
|
||||
if let Some(parent) = binding
|
||||
.source
|
||||
.map(|source| &self.semantic_model.stmts[source])
|
||||
{
|
||||
if parent.is_import_from_stmt() {
|
||||
diagnostic.set_parent(parent.start());
|
||||
}
|
||||
if let Some(range) = binding.parent_range(&self.semantic_model) {
|
||||
diagnostic.set_parent(range.start());
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
|
@ -86,8 +86,11 @@ pub(crate) fn runtime_import_in_type_checking_block(
|
|||
RuntimeImportInTypeCheckingBlock {
|
||||
qualified_name: qualified_name.to_string(),
|
||||
},
|
||||
binding.range,
|
||||
binding.trimmed_range(checker.semantic_model(), checker.locator),
|
||||
);
|
||||
if let Some(range) = binding.parent_range(checker.semantic_model()) {
|
||||
diagnostic.set_parent(range.start());
|
||||
}
|
||||
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
diagnostic.try_set_fix(|| {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_diagnostics::{AutofixKind, Diagnostic, Fix, Violation};
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic, DiagnosticKind, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_semantic::binding::Binding;
|
||||
|
||||
|
@ -263,7 +263,7 @@ pub(crate) fn typing_only_runtime_import(
|
|||
.unwrap();
|
||||
|
||||
// Categorize the import.
|
||||
let mut diagnostic = match categorize(
|
||||
let kind: DiagnosticKind = match categorize(
|
||||
qualified_name,
|
||||
Some(level),
|
||||
&checker.settings.src,
|
||||
|
@ -272,32 +272,35 @@ pub(crate) fn typing_only_runtime_import(
|
|||
checker.settings.target_version,
|
||||
) {
|
||||
ImportSection::Known(ImportType::LocalFolder | ImportType::FirstParty) => {
|
||||
Diagnostic::new(
|
||||
TypingOnlyFirstPartyImport {
|
||||
qualified_name: qualified_name.to_string(),
|
||||
},
|
||||
binding.range,
|
||||
)
|
||||
TypingOnlyFirstPartyImport {
|
||||
qualified_name: qualified_name.to_string(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
ImportSection::Known(ImportType::ThirdParty) | ImportSection::UserDefined(_) => {
|
||||
Diagnostic::new(
|
||||
TypingOnlyThirdPartyImport {
|
||||
qualified_name: qualified_name.to_string(),
|
||||
},
|
||||
binding.range,
|
||||
)
|
||||
}
|
||||
ImportSection::Known(ImportType::StandardLibrary) => Diagnostic::new(
|
||||
TypingOnlyStandardLibraryImport {
|
||||
TypingOnlyThirdPartyImport {
|
||||
qualified_name: qualified_name.to_string(),
|
||||
},
|
||||
binding.range,
|
||||
),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
ImportSection::Known(ImportType::StandardLibrary) => TypingOnlyStandardLibraryImport {
|
||||
qualified_name: qualified_name.to_string(),
|
||||
}
|
||||
.into(),
|
||||
|
||||
ImportSection::Known(ImportType::Future) => {
|
||||
unreachable!("`__future__` imports should be marked as used")
|
||||
}
|
||||
};
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
kind,
|
||||
binding.trimmed_range(checker.semantic_model(), checker.locator),
|
||||
);
|
||||
if let Some(range) = binding.parent_range(checker.semantic_model()) {
|
||||
diagnostic.set_parent(range.start());
|
||||
}
|
||||
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
diagnostic.try_set_fix(|| {
|
||||
// Step 1) Remove the import.
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::ops::{Deref, DerefMut};
|
|||
|
||||
use bitflags::bitflags;
|
||||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::Ranged;
|
||||
|
||||
use ruff_index::{newtype_index, IndexSlice, IndexVec};
|
||||
use ruff_python_ast::helpers;
|
||||
|
@ -143,6 +144,19 @@ impl<'a> Binding<'a> {
|
|||
_ => self.range,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the range of the binding's parent.
|
||||
pub fn parent_range(&self, semantic_model: &SemanticModel) -> Option<TextRange> {
|
||||
self.source
|
||||
.map(|node_id| semantic_model.stmts[node_id])
|
||||
.and_then(|parent| {
|
||||
if parent.is_import_from_stmt() {
|
||||
Some(parent.range())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue