Skip to content

Commit

Permalink
return an error on ICN001-I002 config conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
ntBre committed Jan 15, 2025
1 parent f56ac14 commit 8a0eb76
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ info:
snapshot_kind: text
---
success: false
exit_code: 1
exit_code: 2
----- stdout -----
import pandas
1

----- stderr -----
warning: (ICN001) requested alias (`pd`) for `pandas` conflicts with isort required import: `import pandas`
test.py:1:8: ICN001 `pandas` should be imported as `pd`
Found 2 errors (1 fixed, 1 remaining).
ruff failed
Cause: isort required import (I002) conflicts with unconventional import alias (ICN001):
- pandas -> pd
2 changes: 1 addition & 1 deletion crates/ruff_python_semantic/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl NameImport {
}

/// Returns the [`QualifiedName`] of the imported name (e.g., given `from foo import bar as baz`, returns `["foo", "bar"]`).
fn qualified_name(&self) -> QualifiedName {
pub fn qualified_name(&self) -> QualifiedName {
match self {
NameImport::Import(import) => QualifiedName::user_defined(&import.name.name),
NameImport::ImportFrom(import_from) => collect_import_from_member(
Expand Down
54 changes: 43 additions & 11 deletions crates/ruff_workspace/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use ruff_linter::line_width::{IndentWidth, LineLength};
use ruff_linter::registry::RuleNamespace;
use ruff_linter::registry::{Rule, RuleSet, INCOMPATIBLE_CODES};
use ruff_linter::rule_selector::{PreviewOptions, Specificity};
use ruff_linter::rules::pycodestyle;
use ruff_linter::rules::{flake8_import_conventions, isort, pycodestyle};
use ruff_linter::settings::fix_safety_table::FixSafetyTable;
use ruff_linter::settings::rule_table::RuleTable;
use ruff_linter::settings::types::{
Expand Down Expand Up @@ -232,6 +232,21 @@ impl Configuration {

let line_length = self.line_length.unwrap_or_default();

let rules = lint.as_rule_table(lint_preview)?;

// LinterSettings validation
let isort = lint
.isort
.map(IsortOptions::try_into_settings)
.transpose()?
.unwrap_or_default();
let flake8_import_conventions = lint
.flake8_import_conventions
.map(Flake8ImportConventionsOptions::into_settings)
.unwrap_or_default();

conflicting_import_settings(&isort, &flake8_import_conventions)?;

Ok(Settings {
cache_dir: self
.cache_dir
Expand Down Expand Up @@ -259,7 +274,7 @@ impl Configuration {

#[allow(deprecated)]
linter: LinterSettings {
rules: lint.as_rule_table(lint_preview)?,
rules,
exclude: FilePatternSet::try_from_iter(lint.exclude.unwrap_or_default())?,
extension: self.extension.unwrap_or_default(),
preview: lint_preview,
Expand Down Expand Up @@ -341,10 +356,7 @@ impl Configuration {
.flake8_implicit_str_concat
.map(Flake8ImplicitStrConcatOptions::into_settings)
.unwrap_or_default(),
flake8_import_conventions: lint
.flake8_import_conventions
.map(Flake8ImportConventionsOptions::into_settings)
.unwrap_or_default(),
flake8_import_conventions,
flake8_pytest_style: lint
.flake8_pytest_style
.map(Flake8PytestStyleOptions::try_into_settings)
Expand Down Expand Up @@ -374,11 +386,7 @@ impl Configuration {
.flake8_gettext
.map(Flake8GetTextOptions::into_settings)
.unwrap_or_default(),
isort: lint
.isort
.map(IsortOptions::try_into_settings)
.transpose()?
.unwrap_or_default(),
isort,
mccabe: lint
.mccabe
.map(McCabeOptions::into_settings)
Expand Down Expand Up @@ -1553,6 +1561,30 @@ fn warn_about_deprecated_top_level_lint_options(
);
}

/// Detect conflicts between I002 (missing-required-import) and ICN001 (unconventional-import-alias)
fn conflicting_import_settings(
isort: &isort::settings::Settings,
flake8_import_conventions: &flake8_import_conventions::settings::Settings,
) -> Result<()> {
use std::fmt::Write;
let mut err_body = String::new();
for required_import in &isort.required_imports {
let name = required_import.qualified_name().to_string();
if let Some(alias) = flake8_import_conventions.aliases.get(&name) {
writeln!(err_body, " - {name} -> {alias}").unwrap();
}
}

if !err_body.is_empty() {
return Err(anyhow!(
"isort required import (I002) conflicts with unconventional import alias (ICN001):\
\n{err_body}"
));
}

Ok(())
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down

0 comments on commit 8a0eb76

Please sign in to comment.