mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 06:41:23 +00:00
Add autofix for flake8-type-checking (#4742)
This commit is contained in:
parent
4bd395a850
commit
1a53996f53
27 changed files with 1204 additions and 42 deletions
|
@ -123,3 +123,88 @@ pub(crate) fn remove_imports<'a>(
|
|||
|
||||
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>(
|
||||
unused_imports: impl Iterator<Item = &'a str>,
|
||||
stmt: &Stmt,
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
//! Insert statements into Python code.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use ruff_text_size::TextSize;
|
||||
use rustpython_parser::ast::{Ranged, Stmt};
|
||||
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.
|
||||
Awaiting::Indent => match tok {
|
||||
Tok::Comment(..) => {}
|
||||
Tok::NonLogicalNewline => {}
|
||||
Tok::Indent => {
|
||||
// This is like:
|
||||
|
|
|
@ -7,10 +7,12 @@ use libcst_native::{Codegen, CodegenState, ImportAlias, Name, NameOrAttribute};
|
|||
use ruff_text_size::TextSize;
|
||||
use rustpython_parser::ast::{self, Ranged, Stmt, Suite};
|
||||
|
||||
use crate::autofix;
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::imports::{AnyImport, Import, ImportFrom};
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
use ruff_python_semantic::model::SemanticModel;
|
||||
use ruff_textwrap::indent;
|
||||
|
||||
use crate::cst::matchers::{match_aliases, match_import_from, match_statement};
|
||||
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
|
||||
/// 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`
|
||||
/// preceding the given position, if any.
|
||||
fn find_import_from(&self, module: &str, at: TextSize) -> Option<&Stmt> {
|
||||
|
@ -258,6 +301,62 @@ impl<'a> Importer<'a> {
|
|||
statement.codegen(&mut state);
|
||||
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)]
|
||||
|
@ -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.
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ResolutionError {
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::fmt::{Display, Formatter};
|
|||
use std::num::NonZeroUsize;
|
||||
|
||||
use colored::{Color, ColoredString, Colorize, Styles};
|
||||
use itertools::Itertools;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
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 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(
|
||||
self.source_code
|
||||
.slice(TextRange::new(last_end, edit.start())),
|
||||
|
|
|
@ -11,8 +11,8 @@ mod tests {
|
|||
use anyhow::Result;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::test::test_path;
|
||||
use crate::registry::{Linter, Rule};
|
||||
use crate::test::{test_path, test_snippet};
|
||||
use crate::{assert_messages, settings};
|
||||
|
||||
#[test_case(Rule::TypingOnlyFirstPartyImport, Path::new("TCH001.py"))]
|
||||
|
@ -134,4 +134,159 @@ mod tests {
|
|||
assert_messages!(snapshot, diagnostics);
|
||||
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_python_semantic::binding::{
|
||||
Binding, BindingKind, FromImportation, Importation, SubmoduleImportation,
|
||||
};
|
||||
|
||||
use crate::autofix;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::importer::StmtImport;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::isort::{categorize, ImportSection, ImportType};
|
||||
|
||||
|
@ -49,6 +53,8 @@ pub struct TypingOnlyFirstPartyImport {
|
|||
}
|
||||
|
||||
impl Violation for TypingOnlyFirstPartyImport {
|
||||
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!(
|
||||
|
@ -56,6 +62,10 @@ impl Violation for TypingOnlyFirstPartyImport {
|
|||
self.full_name
|
||||
)
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> Option<String> {
|
||||
Some("Move into type-checking block".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
|
@ -99,6 +109,8 @@ pub struct TypingOnlyThirdPartyImport {
|
|||
}
|
||||
|
||||
impl Violation for TypingOnlyThirdPartyImport {
|
||||
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!(
|
||||
|
@ -106,6 +118,10 @@ impl Violation for TypingOnlyThirdPartyImport {
|
|||
self.full_name
|
||||
)
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> Option<String> {
|
||||
Some("Move into type-checking block".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
|
@ -149,6 +165,8 @@ pub struct TypingOnlyStandardLibraryImport {
|
|||
}
|
||||
|
||||
impl Violation for TypingOnlyStandardLibraryImport {
|
||||
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!(
|
||||
|
@ -156,6 +174,10 @@ impl Violation for TypingOnlyStandardLibraryImport {
|
|||
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`.
|
||||
|
@ -285,6 +307,10 @@ pub(crate) fn typing_only_runtime_import(
|
|||
return;
|
||||
}
|
||||
|
||||
let Some(reference_id) = binding.references.first() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if binding.context.is_runtime()
|
||||
&& binding.is_used()
|
||||
&& binding.references().all(|reference_id| {
|
||||
|
@ -307,7 +333,7 @@ pub(crate) fn typing_only_runtime_import(
|
|||
.unwrap();
|
||||
|
||||
// Categorize the import.
|
||||
let diagnostic = match categorize(
|
||||
let mut diagnostic = match categorize(
|
||||
full_name,
|
||||
Some(level),
|
||||
&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()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
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():
|
||||
15 | import flask
|
||||
|
@ -9,5 +9,22 @@ exempt_modules.py:14:12: TCH002 Move third-party import `flask` into a type-chec
|
|||
16 |
|
||||
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
|
||||
---
|
||||
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.
|
||||
28 | import pkg
|
||||
|
@ -10,8 +10,27 @@ strict.py:27:21: TCH002 Move third-party import `pkg.A` into a type-checking blo
|
|||
30 |
|
||||
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():
|
||||
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 |
|
||||
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.
|
||||
55 | import pkg
|
||||
|
@ -30,8 +69,27 @@ strict.py:54:25: TCH002 Move third-party import `pkg.bar.A` into a type-checking
|
|||
57 |
|
||||
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():
|
||||
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
|
||||
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():
|
||||
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
|
||||
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():
|
||||
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
|
||||
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
|
||||
92 | # testing the implementation.
|
||||
|
@ -66,8 +181,27 @@ strict.py:91:12: TCH002 Move third-party import `pkg` into a type-checking block
|
|||
| ^^^ TCH002
|
||||
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.
|
||||
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 |
|
||||
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
|
||||
---
|
||||
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():
|
||||
21 | from . import TYP001
|
||||
|
@ -9,5 +9,26 @@ TCH001.py:20:19: TCH001 Move application import `.TYP001` into a type-checking b
|
|||
22 |
|
||||
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
|
||||
---
|
||||
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():
|
||||
9 | import os
|
||||
|
@ -9,5 +9,22 @@ TCH003.py:8:12: TCH003 Move standard library import `os` into a type-checking bl
|
|||
10 |
|
||||
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
|
||||
---
|
||||
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
|
||||
6 | import pathlib
|
||||
|
@ -10,5 +10,22 @@ runtime_evaluated_base_classes_3.py:5:18: TCH003 Move standard library import `u
|
|||
8 |
|
||||
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
|
||||
---
|
||||
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
|
||||
7 | from dataclasses import dataclass
|
||||
|
@ -10,5 +10,22 @@ runtime_evaluated_decorators_3.py:6:18: TCH003 Move standard library import `uui
|
|||
9 |
|
||||
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
|
||||
---
|
||||
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():
|
||||
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 |
|
||||
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():
|
||||
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 |
|
||||
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():
|
||||
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 |
|
||||
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():
|
||||
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 |
|
||||
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():
|
||||
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 |
|
||||
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():
|
||||
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 |
|
||||
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():
|
||||
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 |
|
||||
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():
|
||||
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 |
|
||||
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
|
||||
---
|
||||
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
|
||||
4 |
|
||||
|
@ -10,8 +10,26 @@ runtime_evaluated_base_classes_2.py:3:8: TCH002 Move third-party import `geopand
|
|||
6 | import pydantic
|
||||
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
|
||||
6 | import pydantic
|
||||
|
@ -19,5 +37,22 @@ runtime_evaluated_base_classes_2.py:5:8: TCH002 Move third-party import `pyproj`
|
|||
| ^^^^^^ TCH002
|
||||
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
|
||||
---
|
||||
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
|
||||
11 |
|
||||
12 | import numpy # 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
|
||||
---
|
||||
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.
|
||||
55 | import pkg
|
||||
|
@ -10,8 +10,27 @@ strict.py:54:25: TCH002 Move third-party import `pkg.bar.A` into a type-checking
|
|||
57 |
|
||||
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
|
||||
92 | # testing the implementation.
|
||||
|
@ -19,5 +38,24 @@ strict.py:91:12: TCH002 Move third-party import `pkg` into a type-checking block
|
|||
| ^^^ TCH002
|
||||
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…
Add table
Add a link
Reference in a new issue