[`flake8_import_conventions`] Avoid false positives for NFKC-normalized `__debug__` import aliases in ICN001 (#19411)

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
Dan Parizher 2025-08-06 02:42:51 -04:00 committed by GitHub
parent 18ad2848e3
commit e917d309f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 53 additions and 5 deletions

1
Cargo.lock generated
View File

@ -3389,6 +3389,7 @@ dependencies = [
"strum",
"tempfile",
"toml 0.9.4",
"unicode-normalization",
]
[[package]]

View File

@ -4996,6 +4996,37 @@ fn flake8_import_convention_invalid_aliases_config_module_name() -> Result<()> {
Ok(())
}
#[test]
fn flake8_import_convention_nfkc_normalization() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
[lint.flake8-import-conventions.aliases]
"test.module" = "_𝘥𝘦𝘣𝘶𝘨"
"#,
)?;
insta::with_settings!({
filters => vec![(tempdir_filter(&tempdir).as_str(), "[TMP]/")]
}, {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.arg("--config")
.arg(&ruff_toml)
, @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
ruff failed
Cause: Invalid alias for module 'test.module': alias normalizes to '__debug__', which is not allowed.
");});
Ok(())
}
#[test]
fn flake8_import_convention_unused_aliased_import() {
assert_cmd_snapshot!(

View File

@ -45,6 +45,7 @@ serde = { workspace = true }
shellexpand = { workspace = true }
strum = { workspace = true }
toml = { workspace = true }
unicode-normalization = { workspace = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
etcetera = { workspace = true }

View File

@ -250,7 +250,8 @@ impl Configuration {
.unwrap_or_default();
let flake8_import_conventions = lint
.flake8_import_conventions
.map(Flake8ImportConventionsOptions::into_settings)
.map(Flake8ImportConventionsOptions::try_into_settings)
.transpose()?
.unwrap_or_default();
conflicting_import_settings(&isort, &flake8_import_conventions)?;

View File

@ -5,6 +5,7 @@ use serde::{Deserialize, Deserializer, Serialize};
use std::collections::{BTreeMap, BTreeSet};
use std::path::PathBuf;
use strum::IntoEnumIterator;
use unicode_normalization::UnicodeNormalization;
use crate::settings::LineEnding;
use ruff_formatter::IndentStyle;
@ -1650,7 +1651,9 @@ impl<'de> Deserialize<'de> for Alias {
}
impl Flake8ImportConventionsOptions {
pub fn into_settings(self) -> flake8_import_conventions::settings::Settings {
pub fn try_into_settings(
self,
) -> anyhow::Result<flake8_import_conventions::settings::Settings> {
let mut aliases: FxHashMap<String, String> = match self.aliases {
Some(options_aliases) => options_aliases
.into_iter()
@ -1666,11 +1669,22 @@ impl Flake8ImportConventionsOptions {
);
}
flake8_import_conventions::settings::Settings {
aliases,
let mut normalized_aliases: FxHashMap<String, String> = FxHashMap::default();
for (module, alias) in aliases {
let normalized_alias = alias.nfkc().collect::<String>();
if normalized_alias == "__debug__" {
anyhow::bail!(
"Invalid alias for module '{module}': alias normalizes to '__debug__', which is not allowed."
);
}
normalized_aliases.insert(module, normalized_alias);
}
Ok(flake8_import_conventions::settings::Settings {
aliases: normalized_aliases,
banned_aliases: self.banned_aliases.unwrap_or_default(),
banned_from: self.banned_from.unwrap_or_default(),
}
})
}
}