mirror of https://github.com/astral-sh/ruff
Add autofix for flake8-type-checking (#4742)
This commit is contained in:
parent
4bd395a850
commit
1a53996f53
|
|
@ -123,3 +123,88 @@ pub(crate) fn remove_imports<'a>(
|
||||||
|
|
||||||
Ok(Some(state.to_string()))
|
Ok(Some(state.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given an import statement, remove any imports that are not specified in the `imports` slice.
|
||||||
|
///
|
||||||
|
/// Returns the modified import statement.
|
||||||
|
pub(crate) fn retain_imports(
|
||||||
|
imports: &[&str],
|
||||||
|
stmt: &Stmt,
|
||||||
|
locator: &Locator,
|
||||||
|
stylist: &Stylist,
|
||||||
|
) -> Result<String> {
|
||||||
|
let module_text = locator.slice(stmt.range());
|
||||||
|
let mut tree = match_statement(module_text)?;
|
||||||
|
|
||||||
|
let Statement::Simple(body) = &mut tree else {
|
||||||
|
bail!("Expected Statement::Simple");
|
||||||
|
};
|
||||||
|
|
||||||
|
let (aliases, import_module) = match body.body.first_mut() {
|
||||||
|
Some(SmallStatement::Import(import_body)) => (&mut import_body.names, None),
|
||||||
|
Some(SmallStatement::ImportFrom(import_body)) => {
|
||||||
|
if let ImportNames::Aliases(names) = &mut import_body.names {
|
||||||
|
(
|
||||||
|
names,
|
||||||
|
Some((&import_body.relative, import_body.module.as_ref())),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
bail!("Expected: ImportNames::Aliases");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => bail!("Expected: SmallStatement::ImportFrom | SmallStatement::Import"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Preserve the trailing comma (or not) from the last entry.
|
||||||
|
let trailing_comma = aliases.last().and_then(|alias| alias.comma.clone());
|
||||||
|
|
||||||
|
aliases.retain(|alias| {
|
||||||
|
imports.iter().any(|import| {
|
||||||
|
let full_name = match import_module {
|
||||||
|
Some((relative, module)) => {
|
||||||
|
let module = module.map(compose_module_path);
|
||||||
|
let member = compose_module_path(&alias.name);
|
||||||
|
let mut full_name = String::with_capacity(
|
||||||
|
relative.len() + module.as_ref().map_or(0, String::len) + member.len() + 1,
|
||||||
|
);
|
||||||
|
for _ in 0..relative.len() {
|
||||||
|
full_name.push('.');
|
||||||
|
}
|
||||||
|
if let Some(module) = module {
|
||||||
|
full_name.push_str(&module);
|
||||||
|
full_name.push('.');
|
||||||
|
}
|
||||||
|
full_name.push_str(&member);
|
||||||
|
full_name
|
||||||
|
}
|
||||||
|
None => compose_module_path(&alias.name),
|
||||||
|
};
|
||||||
|
full_name == *import
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// But avoid destroying any trailing comments.
|
||||||
|
if let Some(alias) = aliases.last_mut() {
|
||||||
|
let has_comment = if let Some(comma) = &alias.comma {
|
||||||
|
match &comma.whitespace_after {
|
||||||
|
ParenthesizableWhitespace::SimpleWhitespace(_) => false,
|
||||||
|
ParenthesizableWhitespace::ParenthesizedWhitespace(whitespace) => {
|
||||||
|
whitespace.first_line.comment.is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if !has_comment {
|
||||||
|
alias.comma = trailing_comma;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut state = CodegenState {
|
||||||
|
default_newline: &stylist.line_ending(),
|
||||||
|
default_indent: stylist.indentation(),
|
||||||
|
..CodegenState::default()
|
||||||
|
};
|
||||||
|
tree.codegen(&mut state);
|
||||||
|
Ok(state.to_string())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ pub(crate) fn delete_stmt(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a `Fix` to remove any unused imports from an `import` statement.
|
/// Generate a `Fix` to remove the specified imports from an `import` statement.
|
||||||
pub(crate) fn remove_unused_imports<'a>(
|
pub(crate) fn remove_unused_imports<'a>(
|
||||||
unused_imports: impl Iterator<Item = &'a str>,
|
unused_imports: impl Iterator<Item = &'a str>,
|
||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
//! Insert statements into Python code.
|
//! Insert statements into Python code.
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use ruff_text_size::TextSize;
|
use ruff_text_size::TextSize;
|
||||||
use rustpython_parser::ast::{Ranged, Stmt};
|
use rustpython_parser::ast::{Ranged, Stmt};
|
||||||
use rustpython_parser::{lexer, Mode, Tok};
|
use rustpython_parser::{lexer, Mode, Tok};
|
||||||
|
|
@ -182,6 +180,7 @@ impl<'a> Insertion<'a> {
|
||||||
},
|
},
|
||||||
// Once we've seen the newline, we're looking for the indentation of the block body.
|
// Once we've seen the newline, we're looking for the indentation of the block body.
|
||||||
Awaiting::Indent => match tok {
|
Awaiting::Indent => match tok {
|
||||||
|
Tok::Comment(..) => {}
|
||||||
Tok::NonLogicalNewline => {}
|
Tok::NonLogicalNewline => {}
|
||||||
Tok::Indent => {
|
Tok::Indent => {
|
||||||
// This is like:
|
// This is like:
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@ use libcst_native::{Codegen, CodegenState, ImportAlias, Name, NameOrAttribute};
|
||||||
use ruff_text_size::TextSize;
|
use ruff_text_size::TextSize;
|
||||||
use rustpython_parser::ast::{self, Ranged, Stmt, Suite};
|
use rustpython_parser::ast::{self, Ranged, Stmt, Suite};
|
||||||
|
|
||||||
|
use crate::autofix;
|
||||||
use ruff_diagnostics::Edit;
|
use ruff_diagnostics::Edit;
|
||||||
use ruff_python_ast::imports::{AnyImport, Import, ImportFrom};
|
use ruff_python_ast::imports::{AnyImport, Import, ImportFrom};
|
||||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||||
use ruff_python_semantic::model::SemanticModel;
|
use ruff_python_semantic::model::SemanticModel;
|
||||||
|
use ruff_textwrap::indent;
|
||||||
|
|
||||||
use crate::cst::matchers::{match_aliases, match_import_from, match_statement};
|
use crate::cst::matchers::{match_aliases, match_import_from, match_statement};
|
||||||
use crate::importer::insertion::Insertion;
|
use crate::importer::insertion::Insertion;
|
||||||
|
|
@ -73,6 +75,55 @@ impl<'a> Importer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Move an existing import into a `TYPE_CHECKING` block.
|
||||||
|
///
|
||||||
|
/// If there are no existing `TYPE_CHECKING` blocks, a new one will be added at the top
|
||||||
|
/// of the file. Otherwise, it will be added after the most recent top-level
|
||||||
|
/// `TYPE_CHECKING` block.
|
||||||
|
pub(crate) fn typing_import_edit(
|
||||||
|
&self,
|
||||||
|
import: &StmtImport,
|
||||||
|
at: TextSize,
|
||||||
|
semantic_model: &SemanticModel,
|
||||||
|
) -> Result<TypingImportEdit> {
|
||||||
|
// Generate the modified import statement.
|
||||||
|
let content = autofix::codemods::retain_imports(
|
||||||
|
&[import.full_name],
|
||||||
|
import.stmt,
|
||||||
|
self.locator,
|
||||||
|
self.stylist,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Import the `TYPE_CHECKING` symbol from the typing module.
|
||||||
|
let (type_checking_edit, type_checking) = self.get_or_import_symbol(
|
||||||
|
&ImportRequest::import_from("typing", "TYPE_CHECKING"),
|
||||||
|
at,
|
||||||
|
semantic_model,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Add the import to a `TYPE_CHECKING` block.
|
||||||
|
let add_import_edit = if let Some(block) = self.preceding_type_checking_block(at) {
|
||||||
|
// Add the import to the `TYPE_CHECKING` block.
|
||||||
|
self.add_to_type_checking_block(&content, block.start())
|
||||||
|
} else {
|
||||||
|
// Add the import to a new `TYPE_CHECKING` block.
|
||||||
|
self.add_type_checking_block(
|
||||||
|
&format!(
|
||||||
|
"{}if {type_checking}:{}{}",
|
||||||
|
self.stylist.line_ending().as_str(),
|
||||||
|
self.stylist.line_ending().as_str(),
|
||||||
|
indent(&content, self.stylist.indentation())
|
||||||
|
),
|
||||||
|
at,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(TypingImportEdit {
|
||||||
|
type_checking_edit,
|
||||||
|
add_import_edit,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate an [`Edit`] to reference the given symbol. Returns the [`Edit`] necessary to make
|
/// Generate an [`Edit`] to reference the given symbol. Returns the [`Edit`] necessary to make
|
||||||
/// the symbol available in the current scope along with the bound name of the symbol.
|
/// the symbol available in the current scope along with the bound name of the symbol.
|
||||||
///
|
///
|
||||||
|
|
@ -204,14 +255,6 @@ impl<'a> Importer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the import statement that precedes the given position, if any.
|
|
||||||
fn preceding_import(&self, at: TextSize) -> Option<&Stmt> {
|
|
||||||
self.runtime_imports
|
|
||||||
.partition_point(|stmt| stmt.start() < at)
|
|
||||||
.checked_sub(1)
|
|
||||||
.map(|idx| self.runtime_imports[idx])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the top-level [`Stmt`] that imports the given module using `Stmt::ImportFrom`
|
/// Return the top-level [`Stmt`] that imports the given module using `Stmt::ImportFrom`
|
||||||
/// preceding the given position, if any.
|
/// preceding the given position, if any.
|
||||||
fn find_import_from(&self, module: &str, at: TextSize) -> Option<&Stmt> {
|
fn find_import_from(&self, module: &str, at: TextSize) -> Option<&Stmt> {
|
||||||
|
|
@ -258,6 +301,62 @@ impl<'a> Importer<'a> {
|
||||||
statement.codegen(&mut state);
|
statement.codegen(&mut state);
|
||||||
Ok(Edit::range_replacement(state.to_string(), stmt.range()))
|
Ok(Edit::range_replacement(state.to_string(), stmt.range()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a `TYPE_CHECKING` block to the given module.
|
||||||
|
fn add_type_checking_block(&self, content: &str, at: TextSize) -> Result<Edit> {
|
||||||
|
let insertion = if let Some(stmt) = self.preceding_import(at) {
|
||||||
|
// Insert after the last top-level import.
|
||||||
|
Insertion::end_of_statement(stmt, self.locator, self.stylist)
|
||||||
|
} else {
|
||||||
|
// Insert at the start of the file.
|
||||||
|
Insertion::start_of_file(self.python_ast, self.locator, self.stylist)
|
||||||
|
};
|
||||||
|
if insertion.is_inline() {
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"Cannot insert `TYPE_CHECKING` block inline"
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(insertion.into_edit(content))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an import statement to an existing `TYPE_CHECKING` block.
|
||||||
|
fn add_to_type_checking_block(&self, content: &str, at: TextSize) -> Edit {
|
||||||
|
Insertion::start_of_block(at, self.locator, self.stylist).into_edit(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the import statement that precedes the given position, if any.
|
||||||
|
fn preceding_import(&self, at: TextSize) -> Option<&'a Stmt> {
|
||||||
|
self.runtime_imports
|
||||||
|
.partition_point(|stmt| stmt.start() < at)
|
||||||
|
.checked_sub(1)
|
||||||
|
.map(|idx| self.runtime_imports[idx])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the `TYPE_CHECKING` block that precedes the given position, if any.
|
||||||
|
fn preceding_type_checking_block(&self, at: TextSize) -> Option<&'a Stmt> {
|
||||||
|
let block = self.type_checking_blocks.first()?;
|
||||||
|
if block.start() <= at {
|
||||||
|
Some(block)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An edit to an import to a typing-only context.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct TypingImportEdit {
|
||||||
|
/// The edit to add the `TYPE_CHECKING` symbol to the module.
|
||||||
|
type_checking_edit: Edit,
|
||||||
|
/// The edit to add the import to a `TYPE_CHECKING` block.
|
||||||
|
add_import_edit: Edit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypingImportEdit {
|
||||||
|
pub(crate) fn into_edits(self) -> Vec<Edit> {
|
||||||
|
vec![self.type_checking_edit, self.add_import_edit]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -301,6 +400,14 @@ impl<'a> ImportRequest<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An existing module or member import, located within an import statement.
|
||||||
|
pub(crate) struct StmtImport<'a> {
|
||||||
|
/// The import statement.
|
||||||
|
pub(crate) stmt: &'a Stmt,
|
||||||
|
/// The "full name" of the imported module or member.
|
||||||
|
pub(crate) full_name: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
/// The result of an [`Importer::get_or_import_symbol`] call.
|
/// The result of an [`Importer::get_or_import_symbol`] call.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum ResolutionError {
|
pub(crate) enum ResolutionError {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use std::fmt::{Display, Formatter};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
use colored::{Color, ColoredString, Colorize, Styles};
|
use colored::{Color, ColoredString, Colorize, Styles};
|
||||||
|
use itertools::Itertools;
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
use similar::{ChangeTag, TextDiff};
|
use similar::{ChangeTag, TextDiff};
|
||||||
|
|
||||||
|
|
@ -37,7 +38,12 @@ impl Display for Diff<'_> {
|
||||||
let mut output = String::with_capacity(self.source_code.source_text().len());
|
let mut output = String::with_capacity(self.source_code.source_text().len());
|
||||||
let mut last_end = TextSize::default();
|
let mut last_end = TextSize::default();
|
||||||
|
|
||||||
for edit in self.fix.edits() {
|
for edit in self
|
||||||
|
.fix
|
||||||
|
.edits()
|
||||||
|
.iter()
|
||||||
|
.sorted_unstable_by_key(|edit| edit.start())
|
||||||
|
{
|
||||||
output.push_str(
|
output.push_str(
|
||||||
self.source_code
|
self.source_code
|
||||||
.slice(TextRange::new(last_end, edit.start())),
|
.slice(TextRange::new(last_end, edit.start())),
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ mod tests {
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
use crate::registry::Rule;
|
use crate::registry::{Linter, Rule};
|
||||||
use crate::test::test_path;
|
use crate::test::{test_path, test_snippet};
|
||||||
use crate::{assert_messages, settings};
|
use crate::{assert_messages, settings};
|
||||||
|
|
||||||
#[test_case(Rule::TypingOnlyFirstPartyImport, Path::new("TCH001.py"))]
|
#[test_case(Rule::TypingOnlyFirstPartyImport, Path::new("TCH001.py"))]
|
||||||
|
|
@ -134,4 +134,159 @@ mod tests {
|
||||||
assert_messages!(snapshot, diagnostics);
|
assert_messages!(snapshot, diagnostics);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
def f(x: pd.DataFrame):
|
||||||
|
pass
|
||||||
|
"#,
|
||||||
|
"no_typing_import"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
def f(x: pd.DataFrame):
|
||||||
|
pass
|
||||||
|
"#,
|
||||||
|
"typing_import_before_package_import"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
def f(x: pd.DataFrame):
|
||||||
|
pass
|
||||||
|
"#,
|
||||||
|
"typing_import_after_package_import"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
def f(x: pd.DataFrame):
|
||||||
|
pass
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
"#,
|
||||||
|
"typing_import_after_usage"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
import os
|
||||||
|
|
||||||
|
def f(x: pd.DataFrame):
|
||||||
|
pass
|
||||||
|
"#,
|
||||||
|
"type_checking_block_own_line"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
if TYPE_CHECKING: import os
|
||||||
|
|
||||||
|
def f(x: pd.DataFrame):
|
||||||
|
pass
|
||||||
|
"#,
|
||||||
|
"type_checking_block_inline"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
# This is a comment.
|
||||||
|
import os
|
||||||
|
|
||||||
|
def f(x: pd.DataFrame):
|
||||||
|
pass
|
||||||
|
"#,
|
||||||
|
"type_checking_block_comment"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
def f(x: pd.DataFrame):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
import os
|
||||||
|
"#,
|
||||||
|
"type_checking_block_after_usage"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pandas import (
|
||||||
|
DataFrame, # DataFrame
|
||||||
|
Series, # Series
|
||||||
|
)
|
||||||
|
|
||||||
|
def f(x: DataFrame):
|
||||||
|
pass
|
||||||
|
"#,
|
||||||
|
"import_from"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r#"
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from pandas import (
|
||||||
|
DataFrame, # DataFrame
|
||||||
|
Series, # Series
|
||||||
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
import os
|
||||||
|
|
||||||
|
def f(x: DataFrame):
|
||||||
|
pass
|
||||||
|
"#,
|
||||||
|
"import_from_type_checking_block"
|
||||||
|
)]
|
||||||
|
fn contents(contents: &str, snapshot: &str) {
|
||||||
|
let diagnostics = test_snippet(
|
||||||
|
contents,
|
||||||
|
&settings::Settings::for_rules(&Linter::Flake8TypeChecking),
|
||||||
|
);
|
||||||
|
assert_messages!(snapshot, diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use rustpython_parser::ast::Stmt;
|
||||||
|
|
||||||
|
use ruff_diagnostics::{AutofixKind, Diagnostic, Fix, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_semantic::binding::{
|
use ruff_python_semantic::binding::{
|
||||||
Binding, BindingKind, FromImportation, Importation, SubmoduleImportation,
|
Binding, BindingKind, FromImportation, Importation, SubmoduleImportation,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::autofix;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::importer::StmtImport;
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
use crate::rules::isort::{categorize, ImportSection, ImportType};
|
use crate::rules::isort::{categorize, ImportSection, ImportType};
|
||||||
|
|
||||||
|
|
@ -49,6 +53,8 @@ pub struct TypingOnlyFirstPartyImport {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for TypingOnlyFirstPartyImport {
|
impl Violation for TypingOnlyFirstPartyImport {
|
||||||
|
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||||
|
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
|
|
@ -56,6 +62,10 @@ impl Violation for TypingOnlyFirstPartyImport {
|
||||||
self.full_name
|
self.full_name
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn autofix_title(&self) -> Option<String> {
|
||||||
|
Some("Move into type-checking block".to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
|
@ -99,6 +109,8 @@ pub struct TypingOnlyThirdPartyImport {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for TypingOnlyThirdPartyImport {
|
impl Violation for TypingOnlyThirdPartyImport {
|
||||||
|
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||||
|
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
|
|
@ -106,6 +118,10 @@ impl Violation for TypingOnlyThirdPartyImport {
|
||||||
self.full_name
|
self.full_name
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn autofix_title(&self) -> Option<String> {
|
||||||
|
Some("Move into type-checking block".to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
|
@ -149,6 +165,8 @@ pub struct TypingOnlyStandardLibraryImport {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for TypingOnlyStandardLibraryImport {
|
impl Violation for TypingOnlyStandardLibraryImport {
|
||||||
|
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||||
|
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
|
|
@ -156,6 +174,10 @@ impl Violation for TypingOnlyStandardLibraryImport {
|
||||||
self.full_name
|
self.full_name
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn autofix_title(&self) -> Option<String> {
|
||||||
|
Some("Move into type-checking block".to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if `this` is implicitly loaded via importing `that`.
|
/// Return `true` if `this` is implicitly loaded via importing `that`.
|
||||||
|
|
@ -285,6 +307,10 @@ pub(crate) fn typing_only_runtime_import(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let Some(reference_id) = binding.references.first() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
if binding.context.is_runtime()
|
if binding.context.is_runtime()
|
||||||
&& binding.is_used()
|
&& binding.is_used()
|
||||||
&& binding.references().all(|reference_id| {
|
&& binding.references().all(|reference_id| {
|
||||||
|
|
@ -307,7 +333,7 @@ pub(crate) fn typing_only_runtime_import(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Categorize the import.
|
// Categorize the import.
|
||||||
let diagnostic = match categorize(
|
let mut diagnostic = match categorize(
|
||||||
full_name,
|
full_name,
|
||||||
Some(level),
|
Some(level),
|
||||||
&checker.settings.src,
|
&checker.settings.src,
|
||||||
|
|
@ -342,6 +368,43 @@ pub(crate) fn typing_only_runtime_import(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if checker.patch(diagnostic.kind.rule()) {
|
||||||
|
diagnostic.try_set_fix(|| {
|
||||||
|
// Step 1) Remove the import.
|
||||||
|
// SAFETY: All non-builtin bindings have a source.
|
||||||
|
let source = binding.source.unwrap();
|
||||||
|
let deleted: Vec<&Stmt> = checker.deletions.iter().map(Into::into).collect();
|
||||||
|
let stmt = checker.semantic_model().stmts[source];
|
||||||
|
let parent = checker
|
||||||
|
.semantic_model()
|
||||||
|
.stmts
|
||||||
|
.parent_id(source)
|
||||||
|
.map(|id| checker.semantic_model().stmts[id]);
|
||||||
|
let remove_import_edit = autofix::edits::remove_unused_imports(
|
||||||
|
std::iter::once(full_name),
|
||||||
|
stmt,
|
||||||
|
parent,
|
||||||
|
&deleted,
|
||||||
|
checker.locator,
|
||||||
|
checker.indexer,
|
||||||
|
checker.stylist,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Step 2) Add the import to a `TYPE_CHECKING` block.
|
||||||
|
let reference = checker.semantic_model().references.resolve(*reference_id);
|
||||||
|
let add_import_edit = checker.importer.typing_import_edit(
|
||||||
|
&StmtImport { stmt, full_name },
|
||||||
|
reference.range().start(),
|
||||||
|
checker.semantic_model(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(Fix::suggested_edits(
|
||||||
|
remove_import_edit,
|
||||||
|
add_import_edit.into_edits(),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if checker.enabled(diagnostic.kind.rule()) {
|
if checker.enabled(diagnostic.kind.rule()) {
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
exempt_modules.py:14:12: TCH002 Move third-party import `flask` into a type-checking block
|
exempt_modules.py:14:12: TCH002 [*] Move third-party import `flask` into a type-checking block
|
||||||
|
|
|
|
||||||
14 | def f():
|
14 | def f():
|
||||||
15 | import flask
|
15 | import flask
|
||||||
|
|
@ -9,5 +9,22 @@ exempt_modules.py:14:12: TCH002 Move third-party import `flask` into a type-chec
|
||||||
16 |
|
16 |
|
||||||
17 | x: flask
|
17 | x: flask
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
1 |+from typing import TYPE_CHECKING
|
||||||
|
2 |+
|
||||||
|
3 |+if TYPE_CHECKING:
|
||||||
|
4 |+ import flask
|
||||||
|
1 5 | def f():
|
||||||
|
2 6 | import pandas as pd
|
||||||
|
3 7 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
11 15 |
|
||||||
|
12 16 |
|
||||||
|
13 17 | def f():
|
||||||
|
14 |- import flask
|
||||||
|
15 18 |
|
||||||
|
16 19 | x: flask
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:5:5: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block
|
||||||
|
|
|
||||||
|
5 | from pandas import (
|
||||||
|
6 | DataFrame, # DataFrame
|
||||||
|
| ^^^^^^^^^ TCH002
|
||||||
|
7 | Series, # Series
|
||||||
|
8 | )
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
2 2 | from __future__ import annotations
|
||||||
|
3 3 |
|
||||||
|
4 4 | from pandas import (
|
||||||
|
5 |- DataFrame, # DataFrame
|
||||||
|
6 5 | Series, # Series
|
||||||
|
7 6 | )
|
||||||
|
7 |+from typing import TYPE_CHECKING
|
||||||
|
8 |+
|
||||||
|
9 |+if TYPE_CHECKING:
|
||||||
|
10 |+ from pandas import (
|
||||||
|
11 |+ DataFrame, # DataFrame
|
||||||
|
12 |+ )
|
||||||
|
8 13 |
|
||||||
|
9 14 | def f(x: DataFrame):
|
||||||
|
10 15 | pass
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:7:5: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block
|
||||||
|
|
|
||||||
|
7 | from pandas import (
|
||||||
|
8 | DataFrame, # DataFrame
|
||||||
|
| ^^^^^^^^^ TCH002
|
||||||
|
9 | Series, # Series
|
||||||
|
10 | )
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
4 4 | from typing import TYPE_CHECKING
|
||||||
|
5 5 |
|
||||||
|
6 6 | from pandas import (
|
||||||
|
7 |- DataFrame, # DataFrame
|
||||||
|
8 7 | Series, # Series
|
||||||
|
9 8 | )
|
||||||
|
10 9 |
|
||||||
|
11 10 | if TYPE_CHECKING:
|
||||||
|
11 |+ from pandas import (
|
||||||
|
12 |+ DataFrame, # DataFrame
|
||||||
|
13 |+ )
|
||||||
|
12 14 | import os
|
||||||
|
13 15 |
|
||||||
|
14 16 | def f(x: DataFrame):
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:4:8: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
||||||
|
4 | from __future__ import annotations
|
||||||
|
5 |
|
||||||
|
6 | import pandas as pd
|
||||||
|
| ^^^^^^^^^^^^ TCH002
|
||||||
|
7 |
|
||||||
|
8 | def f(x: pd.DataFrame):
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
1 1 |
|
||||||
|
2 2 | from __future__ import annotations
|
||||||
|
3 3 |
|
||||||
|
4 |-import pandas as pd
|
||||||
|
4 |+from typing import TYPE_CHECKING
|
||||||
|
5 |+
|
||||||
|
6 |+if TYPE_CHECKING:
|
||||||
|
7 |+ import pandas as pd
|
||||||
|
5 8 |
|
||||||
|
6 9 | def f(x: pd.DataFrame):
|
||||||
|
7 10 | pass
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
strict.py:27:21: TCH002 Move third-party import `pkg.A` into a type-checking block
|
strict.py:27:21: TCH002 [*] Move third-party import `pkg.A` into a type-checking block
|
||||||
|
|
|
|
||||||
27 | # In un-strict mode, this shouldn't rase an error, since `pkg` is used at runtime.
|
27 | # In un-strict mode, this shouldn't rase an error, since `pkg` is used at runtime.
|
||||||
28 | import pkg
|
28 | import pkg
|
||||||
|
|
@ -10,8 +10,27 @@ strict.py:27:21: TCH002 Move third-party import `pkg.A` into a type-checking blo
|
||||||
30 |
|
30 |
|
||||||
31 | def test(value: A):
|
31 | def test(value: A):
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
strict.py:35:21: TCH002 Move third-party import `pkg.A` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ from pkg import A
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
24 28 | def f():
|
||||||
|
25 29 | # In un-strict mode, this shouldn't rase an error, since `pkg` is used at runtime.
|
||||||
|
26 30 | import pkg
|
||||||
|
27 |- from pkg import A
|
||||||
|
28 31 |
|
||||||
|
29 32 | def test(value: A):
|
||||||
|
30 33 | return pkg.B()
|
||||||
|
|
||||||
|
strict.py:35:21: TCH002 [*] Move third-party import `pkg.A` into a type-checking block
|
||||||
|
|
|
|
||||||
35 | def f():
|
35 | def f():
|
||||||
36 | # In un-strict mode, this shouldn't rase an error, since `pkg` is used at runtime.
|
36 | # In un-strict mode, this shouldn't rase an error, since `pkg` is used at runtime.
|
||||||
|
|
@ -20,8 +39,28 @@ strict.py:35:21: TCH002 Move third-party import `pkg.A` into a type-checking blo
|
||||||
38 |
|
38 |
|
||||||
39 | def test(value: A):
|
39 | def test(value: A):
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
strict.py:54:25: TCH002 Move third-party import `pkg.bar.A` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ from pkg import A
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
32 36 |
|
||||||
|
33 37 | def f():
|
||||||
|
34 38 | # In un-strict mode, this shouldn't rase an error, since `pkg` is used at runtime.
|
||||||
|
35 |- from pkg import A, B
|
||||||
|
39 |+ from pkg import B
|
||||||
|
36 40 |
|
||||||
|
37 41 | def test(value: A):
|
||||||
|
38 42 | return B()
|
||||||
|
|
||||||
|
strict.py:54:25: TCH002 [*] Move third-party import `pkg.bar.A` into a type-checking block
|
||||||
|
|
|
|
||||||
54 | # In un-strict mode, this _should_ rase an error, since `pkg` is used at runtime.
|
54 | # In un-strict mode, this _should_ rase an error, since `pkg` is used at runtime.
|
||||||
55 | import pkg
|
55 | import pkg
|
||||||
|
|
@ -30,8 +69,27 @@ strict.py:54:25: TCH002 Move third-party import `pkg.bar.A` into a type-checking
|
||||||
57 |
|
57 |
|
||||||
58 | def test(value: A):
|
58 | def test(value: A):
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
strict.py:62:12: TCH002 Move third-party import `pkg` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ from pkg.bar import A
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
51 55 | def f():
|
||||||
|
52 56 | # In un-strict mode, this _should_ rase an error, since `pkg` is used at runtime.
|
||||||
|
53 57 | import pkg
|
||||||
|
54 |- from pkg.bar import A
|
||||||
|
55 58 |
|
||||||
|
56 59 | def test(value: A):
|
||||||
|
57 60 | return pkg.B()
|
||||||
|
|
||||||
|
strict.py:62:12: TCH002 [*] Move third-party import `pkg` into a type-checking block
|
||||||
|
|
|
|
||||||
62 | def f():
|
62 | def f():
|
||||||
63 | # In un-strict mode, this shouldn't rase an error, since `pkg.bar` is used at runtime.
|
63 | # In un-strict mode, this shouldn't rase an error, since `pkg.bar` is used at runtime.
|
||||||
|
|
@ -39,8 +97,27 @@ strict.py:62:12: TCH002 Move third-party import `pkg` into a type-checking block
|
||||||
| ^^^ TCH002
|
| ^^^ TCH002
|
||||||
65 | import pkg.bar as B
|
65 | import pkg.bar as B
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
strict.py:71:12: TCH002 Move third-party import `pkg.foo` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pkg
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
59 63 |
|
||||||
|
60 64 | def f():
|
||||||
|
61 65 | # In un-strict mode, this shouldn't rase an error, since `pkg.bar` is used at runtime.
|
||||||
|
62 |- import pkg
|
||||||
|
63 66 | import pkg.bar as B
|
||||||
|
64 67 |
|
||||||
|
65 68 | def test(value: pkg.A):
|
||||||
|
|
||||||
|
strict.py:71:12: TCH002 [*] Move third-party import `pkg.foo` into a type-checking block
|
||||||
|
|
|
|
||||||
71 | def f():
|
71 | def f():
|
||||||
72 | # In un-strict mode, this shouldn't rase an error, since `pkg.foo.bar` is used at runtime.
|
72 | # In un-strict mode, this shouldn't rase an error, since `pkg.foo.bar` is used at runtime.
|
||||||
|
|
@ -48,8 +125,27 @@ strict.py:71:12: TCH002 Move third-party import `pkg.foo` into a type-checking b
|
||||||
| ^^^^^^^^^^^^ TCH002
|
| ^^^^^^^^^^^^ TCH002
|
||||||
74 | import pkg.foo.bar as B
|
74 | import pkg.foo.bar as B
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
strict.py:80:12: TCH002 Move third-party import `pkg` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pkg.foo as F
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
68 72 |
|
||||||
|
69 73 | def f():
|
||||||
|
70 74 | # In un-strict mode, this shouldn't rase an error, since `pkg.foo.bar` is used at runtime.
|
||||||
|
71 |- import pkg.foo as F
|
||||||
|
72 75 | import pkg.foo.bar as B
|
||||||
|
73 76 |
|
||||||
|
74 77 | def test(value: F.Foo):
|
||||||
|
|
||||||
|
strict.py:80:12: TCH002 [*] Move third-party import `pkg` into a type-checking block
|
||||||
|
|
|
|
||||||
80 | def f():
|
80 | def f():
|
||||||
81 | # In un-strict mode, this shouldn't rase an error, since `pkg.foo.bar` is used at runtime.
|
81 | # In un-strict mode, this shouldn't rase an error, since `pkg.foo.bar` is used at runtime.
|
||||||
|
|
@ -57,8 +153,27 @@ strict.py:80:12: TCH002 Move third-party import `pkg` into a type-checking block
|
||||||
| ^^^ TCH002
|
| ^^^ TCH002
|
||||||
83 | import pkg.foo.bar as B
|
83 | import pkg.foo.bar as B
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
strict.py:91:12: TCH002 Move third-party import `pkg` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pkg
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
77 81 |
|
||||||
|
78 82 | def f():
|
||||||
|
79 83 | # In un-strict mode, this shouldn't rase an error, since `pkg.foo.bar` is used at runtime.
|
||||||
|
80 |- import pkg
|
||||||
|
81 84 | import pkg.foo.bar as B
|
||||||
|
82 85 |
|
||||||
|
83 86 | def test(value: pkg.A):
|
||||||
|
|
||||||
|
strict.py:91:12: TCH002 [*] Move third-party import `pkg` into a type-checking block
|
||||||
|
|
|
|
||||||
91 | # Note that `pkg` is a prefix of `pkgfoo` which are both different modules. This is
|
91 | # Note that `pkg` is a prefix of `pkgfoo` which are both different modules. This is
|
||||||
92 | # testing the implementation.
|
92 | # testing the implementation.
|
||||||
|
|
@ -66,8 +181,27 @@ strict.py:91:12: TCH002 Move third-party import `pkg` into a type-checking block
|
||||||
| ^^^ TCH002
|
| ^^^ TCH002
|
||||||
94 | import pkgfoo.bar as B
|
94 | import pkgfoo.bar as B
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
strict.py:101:12: TCH002 Move third-party import `pkg.foo` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pkg
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
88 92 | # In un-strict mode, this _should_ rase an error, since `pkgfoo.bar` is used at runtime.
|
||||||
|
89 93 | # Note that `pkg` is a prefix of `pkgfoo` which are both different modules. This is
|
||||||
|
90 94 | # testing the implementation.
|
||||||
|
91 |- import pkg
|
||||||
|
92 95 | import pkgfoo.bar as B
|
||||||
|
93 96 |
|
||||||
|
94 97 | def test(value: pkg.A):
|
||||||
|
|
||||||
|
strict.py:101:12: TCH002 [*] Move third-party import `pkg.foo` into a type-checking block
|
||||||
|
|
|
|
||||||
101 | # In un-strict mode, this shouldn't raise an error, since `pkg.bar` is used at runtime.
|
101 | # In un-strict mode, this shouldn't raise an error, since `pkg.bar` is used at runtime.
|
||||||
102 | import pkg.bar as B
|
102 | import pkg.bar as B
|
||||||
|
|
@ -76,5 +210,24 @@ strict.py:101:12: TCH002 Move third-party import `pkg.foo` into a type-checking
|
||||||
104 |
|
104 |
|
||||||
105 | def test(value: F.Foo):
|
105 | def test(value: F.Foo):
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pkg.foo as F
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
98 102 | def f():
|
||||||
|
99 103 | # In un-strict mode, this shouldn't raise an error, since `pkg.bar` is used at runtime.
|
||||||
|
100 104 | import pkg.bar as B
|
||||||
|
101 |- import pkg.foo as F
|
||||||
|
102 105 |
|
||||||
|
103 106 | def test(value: F.Foo):
|
||||||
|
104 107 | return B.Bar()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:6:8: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
||||||
|
6 | from typing import TYPE_CHECKING
|
||||||
|
7 |
|
||||||
|
8 | import pandas as pd
|
||||||
|
| ^^^^^^^^^^^^ TCH002
|
||||||
|
9 |
|
||||||
|
10 | def f(x: pd.DataFrame):
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
3 3 |
|
||||||
|
4 4 | from typing import TYPE_CHECKING
|
||||||
|
5 5 |
|
||||||
|
6 |-import pandas as pd
|
||||||
|
7 6 |
|
||||||
|
7 |+if TYPE_CHECKING:
|
||||||
|
8 |+ import pandas as pd
|
||||||
|
9 |+
|
||||||
|
8 10 | def f(x: pd.DataFrame):
|
||||||
|
9 11 | pass
|
||||||
|
10 12 |
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:6:8: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
||||||
|
6 | from typing import TYPE_CHECKING
|
||||||
|
7 |
|
||||||
|
8 | import pandas as pd
|
||||||
|
| ^^^^^^^^^^^^ TCH002
|
||||||
|
9 |
|
||||||
|
10 | if TYPE_CHECKING:
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
3 3 |
|
||||||
|
4 4 | from typing import TYPE_CHECKING
|
||||||
|
5 5 |
|
||||||
|
6 |-import pandas as pd
|
||||||
|
7 6 |
|
||||||
|
8 7 | if TYPE_CHECKING:
|
||||||
|
9 8 | # This is a comment.
|
||||||
|
9 |+ import pandas as pd
|
||||||
|
10 10 | import os
|
||||||
|
11 11 |
|
||||||
|
12 12 | def f(x: pd.DataFrame):
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:6:8: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
||||||
|
6 | from typing import TYPE_CHECKING
|
||||||
|
7 |
|
||||||
|
8 | import pandas as pd
|
||||||
|
| ^^^^^^^^^^^^ TCH002
|
||||||
|
9 |
|
||||||
|
10 | if TYPE_CHECKING: import os
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
3 3 |
|
||||||
|
4 4 | from typing import TYPE_CHECKING
|
||||||
|
5 5 |
|
||||||
|
6 |-import pandas as pd
|
||||||
|
7 6 |
|
||||||
|
8 |-if TYPE_CHECKING: import os
|
||||||
|
7 |+if TYPE_CHECKING: import pandas as pd; import os
|
||||||
|
9 8 |
|
||||||
|
10 9 | def f(x: pd.DataFrame):
|
||||||
|
11 10 | pass
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:6:8: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
||||||
|
6 | from typing import TYPE_CHECKING
|
||||||
|
7 |
|
||||||
|
8 | import pandas as pd
|
||||||
|
| ^^^^^^^^^^^^ TCH002
|
||||||
|
9 |
|
||||||
|
10 | if TYPE_CHECKING:
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
3 3 |
|
||||||
|
4 4 | from typing import TYPE_CHECKING
|
||||||
|
5 5 |
|
||||||
|
6 |-import pandas as pd
|
||||||
|
7 6 |
|
||||||
|
8 7 | if TYPE_CHECKING:
|
||||||
|
8 |+ import pandas as pd
|
||||||
|
9 9 | import os
|
||||||
|
10 10 |
|
||||||
|
11 11 | def f(x: pd.DataFrame):
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
TCH001.py:20:19: TCH001 Move application import `.TYP001` into a type-checking block
|
TCH001.py:20:19: TCH001 [*] Move application import `.TYP001` into a type-checking block
|
||||||
|
|
|
|
||||||
20 | def f():
|
20 | def f():
|
||||||
21 | from . import TYP001
|
21 | from . import TYP001
|
||||||
|
|
@ -9,5 +9,26 @@ TCH001.py:20:19: TCH001 Move application import `.TYP001` into a type-checking b
|
||||||
22 |
|
22 |
|
||||||
23 | x: TYP001
|
23 | x: TYP001
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
2 2 |
|
||||||
|
3 3 | For typing-only import detection tests, see `TCH002.py`.
|
||||||
|
4 4 | """
|
||||||
|
5 |+from typing import TYPE_CHECKING
|
||||||
|
6 |+
|
||||||
|
7 |+if TYPE_CHECKING:
|
||||||
|
8 |+ from . import TYP001
|
||||||
|
5 9 |
|
||||||
|
6 10 |
|
||||||
|
7 11 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
17 21 |
|
||||||
|
18 22 |
|
||||||
|
19 23 | def f():
|
||||||
|
20 |- from . import TYP001
|
||||||
|
21 24 |
|
||||||
|
22 25 | x: TYP001
|
||||||
|
23 26 |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
TCH003.py:8:12: TCH003 Move standard library import `os` into a type-checking block
|
TCH003.py:8:12: TCH003 [*] Move standard library import `os` into a type-checking block
|
||||||
|
|
|
|
||||||
8 | def f():
|
8 | def f():
|
||||||
9 | import os
|
9 | import os
|
||||||
|
|
@ -9,5 +9,22 @@ TCH003.py:8:12: TCH003 Move standard library import `os` into a type-checking bl
|
||||||
10 |
|
10 |
|
||||||
11 | x: os
|
11 | x: os
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
2 2 |
|
||||||
|
3 3 | For typing-only import detection tests, see `TCH002.py`.
|
||||||
|
4 4 | """
|
||||||
|
5 |+from typing import TYPE_CHECKING
|
||||||
|
6 |+
|
||||||
|
7 |+if TYPE_CHECKING:
|
||||||
|
8 |+ import os
|
||||||
|
5 9 |
|
||||||
|
6 10 |
|
||||||
|
7 11 | def f():
|
||||||
|
8 |- import os
|
||||||
|
9 12 |
|
||||||
|
10 13 | x: os
|
||||||
|
11 14 |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
runtime_evaluated_base_classes_3.py:5:18: TCH003 Move standard library import `uuid.UUID` into a type-checking block
|
runtime_evaluated_base_classes_3.py:5:18: TCH003 [*] Move standard library import `uuid.UUID` into a type-checking block
|
||||||
|
|
|
|
||||||
5 | import datetime
|
5 | import datetime
|
||||||
6 | import pathlib
|
6 | import pathlib
|
||||||
|
|
@ -10,5 +10,22 @@ runtime_evaluated_base_classes_3.py:5:18: TCH003 Move standard library import `u
|
||||||
8 |
|
8 |
|
||||||
9 | import pydantic
|
9 | import pydantic
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
2 2 |
|
||||||
|
3 3 | import datetime
|
||||||
|
4 4 | import pathlib
|
||||||
|
5 |-from uuid import UUID # TCH003
|
||||||
|
6 5 |
|
||||||
|
7 6 | import pydantic
|
||||||
|
8 7 | from pydantic import BaseModel
|
||||||
|
8 |+from typing import TYPE_CHECKING
|
||||||
|
9 |+
|
||||||
|
10 |+if TYPE_CHECKING:
|
||||||
|
11 |+ from uuid import UUID
|
||||||
|
9 12 |
|
||||||
|
10 13 |
|
||||||
|
11 14 | class A(pydantic.BaseModel):
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
runtime_evaluated_decorators_3.py:6:18: TCH003 Move standard library import `uuid.UUID` into a type-checking block
|
runtime_evaluated_decorators_3.py:6:18: TCH003 [*] Move standard library import `uuid.UUID` into a type-checking block
|
||||||
|
|
|
|
||||||
6 | from array import array
|
6 | from array import array
|
||||||
7 | from dataclasses import dataclass
|
7 | from dataclasses import dataclass
|
||||||
|
|
@ -10,5 +10,22 @@ runtime_evaluated_decorators_3.py:6:18: TCH003 Move standard library import `uui
|
||||||
9 |
|
9 |
|
||||||
10 | import attrs
|
10 | import attrs
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
3 3 | import datetime
|
||||||
|
4 4 | from array import array
|
||||||
|
5 5 | from dataclasses import dataclass
|
||||||
|
6 |-from uuid import UUID # TCH003
|
||||||
|
7 6 |
|
||||||
|
8 7 | import attrs
|
||||||
|
9 8 | from attrs import frozen
|
||||||
|
9 |+from typing import TYPE_CHECKING
|
||||||
|
10 |+
|
||||||
|
11 |+if TYPE_CHECKING:
|
||||||
|
12 |+ from uuid import UUID
|
||||||
|
10 13 |
|
||||||
|
11 14 |
|
||||||
|
12 15 | @attrs.define(auto_attribs=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
TCH002.py:5:12: TCH002 Move third-party import `pandas` into a type-checking block
|
TCH002.py:5:12: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
|
||||||
5 | def f():
|
5 | def f():
|
||||||
6 | import pandas as pd # TCH002
|
6 | import pandas as pd # TCH002
|
||||||
|
|
@ -9,8 +9,23 @@ TCH002.py:5:12: TCH002 Move third-party import `pandas` into a type-checking blo
|
||||||
7 |
|
7 |
|
||||||
8 | x: pd.DataFrame
|
8 | x: pd.DataFrame
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
TCH002.py:11:24: TCH002 Move third-party import `pandas.DataFrame` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | """Tests to determine accurate detection of typing-only imports."""
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pandas as pd
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
5 |- import pandas as pd # TCH002
|
||||||
|
6 9 |
|
||||||
|
7 10 | x: pd.DataFrame
|
||||||
|
8 11 |
|
||||||
|
|
||||||
|
TCH002.py:11:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block
|
||||||
|
|
|
|
||||||
11 | def f():
|
11 | def f():
|
||||||
12 | from pandas import DataFrame # TCH002
|
12 | from pandas import DataFrame # TCH002
|
||||||
|
|
@ -18,8 +33,27 @@ TCH002.py:11:24: TCH002 Move third-party import `pandas.DataFrame` into a type-c
|
||||||
13 |
|
13 |
|
||||||
14 | x: DataFrame
|
14 | x: DataFrame
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
TCH002.py:17:24: TCH002 Move third-party import `pandas.DataFrame` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | """Tests to determine accurate detection of typing-only imports."""
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ from pandas import DataFrame
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
8 12 |
|
||||||
|
9 13 |
|
||||||
|
10 14 | def f():
|
||||||
|
11 |- from pandas import DataFrame # TCH002
|
||||||
|
12 15 |
|
||||||
|
13 16 | x: DataFrame
|
||||||
|
14 17 |
|
||||||
|
|
||||||
|
TCH002.py:17:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block
|
||||||
|
|
|
|
||||||
17 | def f():
|
17 | def f():
|
||||||
18 | from pandas import DataFrame as df # TCH002
|
18 | from pandas import DataFrame as df # TCH002
|
||||||
|
|
@ -27,8 +61,27 @@ TCH002.py:17:24: TCH002 Move third-party import `pandas.DataFrame` into a type-c
|
||||||
19 |
|
19 |
|
||||||
20 | x: df
|
20 | x: df
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
TCH002.py:23:12: TCH002 Move third-party import `pandas` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | """Tests to determine accurate detection of typing-only imports."""
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ from pandas import DataFrame as df
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
14 18 |
|
||||||
|
15 19 |
|
||||||
|
16 20 | def f():
|
||||||
|
17 |- from pandas import DataFrame as df # TCH002
|
||||||
|
18 21 |
|
||||||
|
19 22 | x: df
|
||||||
|
20 23 |
|
||||||
|
|
||||||
|
TCH002.py:23:12: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
|
||||||
23 | def f():
|
23 | def f():
|
||||||
24 | import pandas as pd # TCH002
|
24 | import pandas as pd # TCH002
|
||||||
|
|
@ -36,8 +89,27 @@ TCH002.py:23:12: TCH002 Move third-party import `pandas` into a type-checking bl
|
||||||
25 |
|
25 |
|
||||||
26 | x: pd.DataFrame = 1
|
26 | x: pd.DataFrame = 1
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
TCH002.py:29:24: TCH002 Move third-party import `pandas.DataFrame` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | """Tests to determine accurate detection of typing-only imports."""
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pandas as pd
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
20 24 |
|
||||||
|
21 25 |
|
||||||
|
22 26 | def f():
|
||||||
|
23 |- import pandas as pd # TCH002
|
||||||
|
24 27 |
|
||||||
|
25 28 | x: pd.DataFrame = 1
|
||||||
|
26 29 |
|
||||||
|
|
||||||
|
TCH002.py:29:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block
|
||||||
|
|
|
|
||||||
29 | def f():
|
29 | def f():
|
||||||
30 | from pandas import DataFrame # TCH002
|
30 | from pandas import DataFrame # TCH002
|
||||||
|
|
@ -45,8 +117,27 @@ TCH002.py:29:24: TCH002 Move third-party import `pandas.DataFrame` into a type-c
|
||||||
31 |
|
31 |
|
||||||
32 | x: DataFrame = 2
|
32 | x: DataFrame = 2
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
TCH002.py:35:24: TCH002 Move third-party import `pandas.DataFrame` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | """Tests to determine accurate detection of typing-only imports."""
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ from pandas import DataFrame
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
26 30 |
|
||||||
|
27 31 |
|
||||||
|
28 32 | def f():
|
||||||
|
29 |- from pandas import DataFrame # TCH002
|
||||||
|
30 33 |
|
||||||
|
31 34 | x: DataFrame = 2
|
||||||
|
32 35 |
|
||||||
|
|
||||||
|
TCH002.py:35:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block
|
||||||
|
|
|
|
||||||
35 | def f():
|
35 | def f():
|
||||||
36 | from pandas import DataFrame as df # TCH002
|
36 | from pandas import DataFrame as df # TCH002
|
||||||
|
|
@ -54,8 +145,27 @@ TCH002.py:35:24: TCH002 Move third-party import `pandas.DataFrame` into a type-c
|
||||||
37 |
|
37 |
|
||||||
38 | x: df = 3
|
38 | x: df = 3
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
TCH002.py:41:12: TCH002 Move third-party import `pandas` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | """Tests to determine accurate detection of typing-only imports."""
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ from pandas import DataFrame as df
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
32 36 |
|
||||||
|
33 37 |
|
||||||
|
34 38 | def f():
|
||||||
|
35 |- from pandas import DataFrame as df # TCH002
|
||||||
|
36 39 |
|
||||||
|
37 40 | x: df = 3
|
||||||
|
38 41 |
|
||||||
|
|
||||||
|
TCH002.py:41:12: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
|
||||||
41 | def f():
|
41 | def f():
|
||||||
42 | import pandas as pd # TCH002
|
42 | import pandas as pd # TCH002
|
||||||
|
|
@ -63,8 +173,27 @@ TCH002.py:41:12: TCH002 Move third-party import `pandas` into a type-checking bl
|
||||||
43 |
|
43 |
|
||||||
44 | x: "pd.DataFrame" = 1
|
44 | x: "pd.DataFrame" = 1
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
TCH002.py:47:12: TCH002 Move third-party import `pandas` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | """Tests to determine accurate detection of typing-only imports."""
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pandas as pd
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
38 42 |
|
||||||
|
39 43 |
|
||||||
|
40 44 | def f():
|
||||||
|
41 |- import pandas as pd # TCH002
|
||||||
|
42 45 |
|
||||||
|
43 46 | x: "pd.DataFrame" = 1
|
||||||
|
44 47 |
|
||||||
|
|
||||||
|
TCH002.py:47:12: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
|
||||||
47 | def f():
|
47 | def f():
|
||||||
48 | import pandas as pd # TCH002
|
48 | import pandas as pd # TCH002
|
||||||
|
|
@ -72,5 +201,24 @@ TCH002.py:47:12: TCH002 Move third-party import `pandas` into a type-checking bl
|
||||||
49 |
|
49 |
|
||||||
50 | x = dict["pd.DataFrame", "pd.DataFrame"]
|
50 | x = dict["pd.DataFrame", "pd.DataFrame"]
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
1 1 | """Tests to determine accurate detection of typing-only imports."""
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pandas as pd
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
44 48 |
|
||||||
|
45 49 |
|
||||||
|
46 50 | def f():
|
||||||
|
47 |- import pandas as pd # TCH002
|
||||||
|
48 51 |
|
||||||
|
49 52 | x = dict["pd.DataFrame", "pd.DataFrame"]
|
||||||
|
50 53 |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
runtime_evaluated_base_classes_2.py:3:8: TCH002 Move third-party import `geopandas` into a type-checking block
|
runtime_evaluated_base_classes_2.py:3:8: TCH002 [*] Move third-party import `geopandas` into a type-checking block
|
||||||
|
|
|
|
||||||
3 | from __future__ import annotations
|
3 | from __future__ import annotations
|
||||||
4 |
|
4 |
|
||||||
|
|
@ -10,8 +10,26 @@ runtime_evaluated_base_classes_2.py:3:8: TCH002 Move third-party import `geopand
|
||||||
6 | import pydantic
|
6 | import pydantic
|
||||||
7 | import pyproj # TCH002
|
7 | import pyproj # TCH002
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
runtime_evaluated_base_classes_2.py:5:8: TCH002 Move third-party import `pyproj` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 2 |
|
||||||
|
3 |-import geopandas as gpd # TCH002
|
||||||
|
4 3 | import pydantic
|
||||||
|
5 4 | import pyproj # TCH002
|
||||||
|
6 5 | from pydantic import BaseModel
|
||||||
|
7 6 |
|
||||||
|
8 7 | import numpy
|
||||||
|
8 |+from typing import TYPE_CHECKING
|
||||||
|
9 |+
|
||||||
|
10 |+if TYPE_CHECKING:
|
||||||
|
11 |+ import geopandas as gpd
|
||||||
|
9 12 |
|
||||||
|
10 13 |
|
||||||
|
11 14 | class A(BaseModel):
|
||||||
|
|
||||||
|
runtime_evaluated_base_classes_2.py:5:8: TCH002 [*] Move third-party import `pyproj` into a type-checking block
|
||||||
|
|
|
|
||||||
5 | import geopandas as gpd # TCH002
|
5 | import geopandas as gpd # TCH002
|
||||||
6 | import pydantic
|
6 | import pydantic
|
||||||
|
|
@ -19,5 +37,22 @@ runtime_evaluated_base_classes_2.py:5:8: TCH002 Move third-party import `pyproj`
|
||||||
| ^^^^^^ TCH002
|
| ^^^^^^ TCH002
|
||||||
8 | from pydantic import BaseModel
|
8 | from pydantic import BaseModel
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
2 2 |
|
||||||
|
3 3 | import geopandas as gpd # TCH002
|
||||||
|
4 4 | import pydantic
|
||||||
|
5 |-import pyproj # TCH002
|
||||||
|
6 5 | from pydantic import BaseModel
|
||||||
|
7 6 |
|
||||||
|
8 7 | import numpy
|
||||||
|
8 |+from typing import TYPE_CHECKING
|
||||||
|
9 |+
|
||||||
|
10 |+if TYPE_CHECKING:
|
||||||
|
11 |+ import pyproj
|
||||||
|
9 12 |
|
||||||
|
10 13 |
|
||||||
|
11 14 | class A(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,26 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
runtime_evaluated_decorators_2.py:10:8: TCH002 Move third-party import `numpy` into a type-checking block
|
runtime_evaluated_decorators_2.py:10:8: TCH002 [*] Move third-party import `numpy` into a type-checking block
|
||||||
|
|
|
|
||||||
10 | from attrs import frozen
|
10 | from attrs import frozen
|
||||||
11 |
|
11 |
|
||||||
12 | import numpy # TCH002
|
12 | import numpy # TCH002
|
||||||
| ^^^^^ TCH002
|
| ^^^^^ TCH002
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
7 7 | import pyproj
|
||||||
|
8 8 | from attrs import frozen
|
||||||
|
9 9 |
|
||||||
|
10 |-import numpy # TCH002
|
||||||
|
10 |+from typing import TYPE_CHECKING
|
||||||
|
11 |+
|
||||||
|
12 |+if TYPE_CHECKING:
|
||||||
|
13 |+ import numpy
|
||||||
|
11 14 |
|
||||||
|
12 15 |
|
||||||
|
13 16 | @attrs.define(auto_attribs=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
---
|
---
|
||||||
strict.py:54:25: TCH002 Move third-party import `pkg.bar.A` into a type-checking block
|
strict.py:54:25: TCH002 [*] Move third-party import `pkg.bar.A` into a type-checking block
|
||||||
|
|
|
|
||||||
54 | # In un-strict mode, this _should_ rase an error, since `pkg` is used at runtime.
|
54 | # In un-strict mode, this _should_ rase an error, since `pkg` is used at runtime.
|
||||||
55 | import pkg
|
55 | import pkg
|
||||||
|
|
@ -10,8 +10,27 @@ strict.py:54:25: TCH002 Move third-party import `pkg.bar.A` into a type-checking
|
||||||
57 |
|
57 |
|
||||||
58 | def test(value: A):
|
58 | def test(value: A):
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
strict.py:91:12: TCH002 Move third-party import `pkg` into a type-checking block
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ from pkg.bar import A
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
51 55 | def f():
|
||||||
|
52 56 | # In un-strict mode, this _should_ rase an error, since `pkg` is used at runtime.
|
||||||
|
53 57 | import pkg
|
||||||
|
54 |- from pkg.bar import A
|
||||||
|
55 58 |
|
||||||
|
56 59 | def test(value: A):
|
||||||
|
57 60 | return pkg.B()
|
||||||
|
|
||||||
|
strict.py:91:12: TCH002 [*] Move third-party import `pkg` into a type-checking block
|
||||||
|
|
|
|
||||||
91 | # Note that `pkg` is a prefix of `pkgfoo` which are both different modules. This is
|
91 | # Note that `pkg` is a prefix of `pkgfoo` which are both different modules. This is
|
||||||
92 | # testing the implementation.
|
92 | # testing the implementation.
|
||||||
|
|
@ -19,5 +38,24 @@ strict.py:91:12: TCH002 Move third-party import `pkg` into a type-checking block
|
||||||
| ^^^ TCH002
|
| ^^^ TCH002
|
||||||
94 | import pkgfoo.bar as B
|
94 | import pkgfoo.bar as B
|
||||||
|
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
1 1 | from __future__ import annotations
|
||||||
|
2 |+from typing import TYPE_CHECKING
|
||||||
|
3 |+
|
||||||
|
4 |+if TYPE_CHECKING:
|
||||||
|
5 |+ import pkg
|
||||||
|
2 6 |
|
||||||
|
3 7 |
|
||||||
|
4 8 | def f():
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
88 92 | # In un-strict mode, this _should_ rase an error, since `pkgfoo.bar` is used at runtime.
|
||||||
|
89 93 | # Note that `pkg` is a prefix of `pkgfoo` which are both different modules. This is
|
||||||
|
90 94 | # testing the implementation.
|
||||||
|
91 |- import pkg
|
||||||
|
92 95 | import pkgfoo.bar as B
|
||||||
|
93 96 |
|
||||||
|
94 97 | def test(value: pkg.A):
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:4:8: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
||||||
|
4 | from __future__ import annotations
|
||||||
|
5 |
|
||||||
|
6 | import pandas as pd
|
||||||
|
| ^^^^^^^^^^^^ TCH002
|
||||||
|
7 |
|
||||||
|
8 | from typing import TYPE_CHECKING
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
1 1 |
|
||||||
|
2 2 | from __future__ import annotations
|
||||||
|
3 3 |
|
||||||
|
4 |-import pandas as pd
|
||||||
|
5 4 |
|
||||||
|
6 5 | from typing import TYPE_CHECKING
|
||||||
|
7 6 |
|
||||||
|
7 |+if TYPE_CHECKING:
|
||||||
|
8 |+ import pandas as pd
|
||||||
|
9 |+
|
||||||
|
8 10 | def f(x: pd.DataFrame):
|
||||||
|
9 11 | pass
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:4:8: TCH002 Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
||||||
|
4 | from __future__ import annotations
|
||||||
|
5 |
|
||||||
|
6 | import pandas as pd
|
||||||
|
| ^^^^^^^^^^^^ TCH002
|
||||||
|
7 |
|
||||||
|
8 | def f(x: pd.DataFrame):
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
<filename>:6:8: TCH002 [*] Move third-party import `pandas` into a type-checking block
|
||||||
|
|
|
||||||
|
6 | from typing import TYPE_CHECKING
|
||||||
|
7 |
|
||||||
|
8 | import pandas as pd
|
||||||
|
| ^^^^^^^^^^^^ TCH002
|
||||||
|
9 |
|
||||||
|
10 | def f(x: pd.DataFrame):
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
3 3 |
|
||||||
|
4 4 | from typing import TYPE_CHECKING
|
||||||
|
5 5 |
|
||||||
|
6 |-import pandas as pd
|
||||||
|
7 6 |
|
||||||
|
7 |+if TYPE_CHECKING:
|
||||||
|
8 |+ import pandas as pd
|
||||||
|
9 |+
|
||||||
|
8 10 | def f(x: pd.DataFrame):
|
||||||
|
9 11 | pass
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue