flake8-type-checking: Always recognise relative imports as first-party (#12994)

This commit is contained in:
Alex Waygood 2024-08-19 19:06:56 +01:00 committed by GitHub
parent 358792f2c9
commit 049cda2ff3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 15 additions and 24 deletions

View file

@ -300,7 +300,7 @@ pub(crate) fn typing_only_runtime_import(
// Categorize the import, using coarse-grained categorization. // Categorize the import, using coarse-grained categorization.
let import_type = match categorize( let import_type = match categorize(
&qualified_name.to_string(), &qualified_name.to_string(),
0, qualified_name.is_unresolved_import(),
&checker.settings.src, &checker.settings.src,
checker.package(), checker.package(),
checker.settings.isort.detect_same_package, checker.settings.isort.detect_same_package,

View file

@ -91,7 +91,7 @@ enum Reason<'a> {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn categorize<'a>( pub(crate) fn categorize<'a>(
module_name: &str, module_name: &str,
level: u32, is_relative: bool,
src: &[PathBuf], src: &[PathBuf],
package: Option<&Path>, package: Option<&Path>,
detect_same_package: bool, detect_same_package: bool,
@ -103,14 +103,14 @@ pub(crate) fn categorize<'a>(
) -> &'a ImportSection { ) -> &'a ImportSection {
let module_base = module_name.split('.').next().unwrap(); let module_base = module_name.split('.').next().unwrap();
let (mut import_type, mut reason) = { let (mut import_type, mut reason) = {
if level == 0 && module_base == "__future__" { if !is_relative && module_base == "__future__" {
(&ImportSection::Known(ImportType::Future), Reason::Future) (&ImportSection::Known(ImportType::Future), Reason::Future)
} else if no_sections { } else if no_sections {
( (
&ImportSection::Known(ImportType::FirstParty), &ImportSection::Known(ImportType::FirstParty),
Reason::NoSections, Reason::NoSections,
) )
} else if level > 0 { } else if is_relative {
( (
&ImportSection::Known(ImportType::LocalFolder), &ImportSection::Known(ImportType::LocalFolder),
Reason::NonZeroLevel, Reason::NonZeroLevel,
@ -132,7 +132,7 @@ pub(crate) fn categorize<'a>(
&ImportSection::Known(ImportType::FirstParty), &ImportSection::Known(ImportType::FirstParty),
Reason::SourceMatch(src), Reason::SourceMatch(src),
) )
} else if level == 0 && module_name == "__main__" { } else if !is_relative && module_name == "__main__" {
( (
&ImportSection::Known(ImportType::FirstParty), &ImportSection::Known(ImportType::FirstParty),
Reason::KnownFirstParty, Reason::KnownFirstParty,
@ -190,7 +190,7 @@ pub(crate) fn categorize_imports<'a>(
for (alias, comments) in block.import { for (alias, comments) in block.import {
let import_type = categorize( let import_type = categorize(
&alias.module_name(), &alias.module_name(),
0, false,
src, src,
package, package,
detect_same_package, detect_same_package,
@ -210,7 +210,7 @@ pub(crate) fn categorize_imports<'a>(
for (import_from, aliases) in block.import_from { for (import_from, aliases) in block.import_from {
let classification = categorize( let classification = categorize(
&import_from.module_name(), &import_from.module_name(),
import_from.level, import_from.level > 0,
src, src,
package, package,
detect_same_package, detect_same_package,
@ -230,7 +230,7 @@ pub(crate) fn categorize_imports<'a>(
for ((import_from, alias), aliases) in block.import_from_as { for ((import_from, alias), aliases) in block.import_from_as {
let classification = categorize( let classification = categorize(
&import_from.module_name(), &import_from.module_name(),
import_from.level, import_from.level > 0,
src, src,
package, package,
detect_same_package, detect_same_package,
@ -250,7 +250,7 @@ pub(crate) fn categorize_imports<'a>(
for (import_from, comments) in block.import_from_star { for (import_from, comments) in block.import_from_star {
let classification = categorize( let classification = categorize(
&import_from.module_name(), &import_from.module_name(),
import_from.level, import_from.level > 0,
src, src,
package, package,
detect_same_package, detect_same_package,

View file

@ -6,8 +6,7 @@ use std::collections::BTreeMap;
use ruff_diagnostics::{Applicability, Diagnostic, Fix, FixAvailability, Violation}; use ruff_diagnostics::{Applicability, Diagnostic, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast as ast; use ruff_python_ast::{self as ast, Stmt};
use ruff_python_ast::{Stmt, StmtImportFrom};
use ruff_python_semantic::{ use ruff_python_semantic::{
AnyImport, BindingKind, Exceptions, Imported, NodeId, Scope, SemanticModel, SubmoduleImport, AnyImport, BindingKind, Exceptions, Imported, NodeId, Scope, SemanticModel, SubmoduleImport,
}; };
@ -218,10 +217,11 @@ enum UnusedImportContext {
Other, Other,
} }
fn is_first_party(qualified_name: &str, level: u32, checker: &Checker) -> bool { fn is_first_party(import: &AnyImport, checker: &Checker) -> bool {
let qualified_name = import.qualified_name();
let category = isort::categorize( let category = isort::categorize(
qualified_name, &qualified_name.to_string(),
level, qualified_name.is_unresolved_import(),
&checker.settings.src, &checker.settings.src,
checker.package(), checker.package(),
checker.settings.isort.detect_same_package, checker.settings.isort.detect_same_package,
@ -343,13 +343,6 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut
let in_except_handler = let in_except_handler =
exceptions.intersects(Exceptions::MODULE_NOT_FOUND_ERROR | Exceptions::IMPORT_ERROR); exceptions.intersects(Exceptions::MODULE_NOT_FOUND_ERROR | Exceptions::IMPORT_ERROR);
let multiple = bindings.len() > 1; let multiple = bindings.len() > 1;
let level = match checker.semantic().statement(import_statement) {
Stmt::Import(_) => 0,
Stmt::ImportFrom(StmtImportFrom { level, .. }) => *level,
_ => {
continue;
}
};
// pair each binding with context; divide them by how we want to fix them // pair each binding with context; divide them by how we want to fix them
let (to_reexport, to_remove): (Vec<_>, Vec<_>) = bindings let (to_reexport, to_remove): (Vec<_>, Vec<_>) = bindings
@ -357,9 +350,7 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut
.map(|binding| { .map(|binding| {
let context = if in_except_handler { let context = if in_except_handler {
UnusedImportContext::ExceptHandler UnusedImportContext::ExceptHandler
} else if in_init } else if in_init && is_first_party(&binding.import, checker) {
&& is_first_party(&binding.import.qualified_name().to_string(), level, checker)
{
UnusedImportContext::DunderInitFirstParty { UnusedImportContext::DunderInitFirstParty {
dunder_all_count: DunderAllCount::from(dunder_all_exprs.len()), dunder_all_count: DunderAllCount::from(dunder_all_exprs.len()),
submodule_import: binding.import.is_submodule_import(), submodule_import: binding.import.is_submodule_import(),