Skip to content

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

Merged
MichaReiser merged 7 commits intoastral-sh:mainfrom
danparizher:fix-19118
Aug 6, 2025
Merged

[flake8_import_conventions] Avoid false positives for NFKC-normalized __debug__ import aliases in ICN001#19411
MichaReiser merged 7 commits intoastral-sh:mainfrom
danparizher:fix-19118

Conversation

@danparizher
Copy link
Contributor

Summary

Fixes #19118

@github-actions
Copy link
Contributor

github-actions bot commented Jul 17, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

return;
};

let normalized_alias = expected_alias.nfkc().collect::<String>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to do this normalization when loading the settings. We otherwise pay the cost for every import statement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I've worked with settings before, how would it be implemented? Via these?

  • crates\ruff_workspace\src\options.rs
  • crates\ruff_linter\src\rules\flake8_import_conventions\settings.rs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we'd validate the settings when loading the configuration. The idea is to rename the into_settings method to try_into_settings and change its return type to Result, similar to

impl Flake8CopyrightOptions {
pub fn try_into_settings(self) -> anyhow::Result<flake8_copyright::settings::Settings> {
Ok(flake8_copyright::settings::Settings {
notice_rgx: self
.notice_rgx
.map(|pattern| Regex::new(&pattern))
.transpose()?
.unwrap_or_else(|| flake8_copyright::settings::COPYRIGHT.clone()),
author: self.author,
min_file_size: self.min_file_size.unwrap_or_default(),
})
}
}

@ntBre ntBre added bug Something isn't working fixes Related to suggested fixes for violations labels Jul 18, 2025
@ntBre ntBre self-requested a review July 24, 2025 13:08
@github-actions
Copy link
Contributor

github-actions bot commented Jul 28, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@github-actions
Copy link
Contributor

github-actions bot commented Jul 28, 2025

mypy_primer results

No ecosystem changes detected ✅
No memory usage changes detected ✅

Comment on lines +1672 to +1678
let normalized_aliases: FxHashMap<String, String> = aliases
.into_iter()
.map(|(module, alias)| {
let normalized_alias = alias.nfkc().collect::<String>();
(module, normalized_alias)
})
.collect();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. I don't think we need to use try_into_settings if we only do the normalization here.

What I had in mind is to error if the user provides an alias that normalizes to __debug__. Or are there cases where we use aliases where __debug__ should be allowed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think __debug__ is ever valid as an alias. Is this the right idea?

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);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that would be the ideal user experience (telling them that the configuration is invalid).

An alternative is to use warn_user_once to log a warning instead (and not adding the alias)

I think either's fine

@danparizher danparizher requested a review from MichaReiser July 31, 2025 22:24
Comment on lines +77 to +80
if expected_alias == "__debug__" {
return;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this check still required, given that we now error in Flake8ImportConventionsOptions

Comment on lines +208 to +231
#[test]
fn nfkc_debug_alias() -> Result<()> {
let mut aliases = default_aliases();
aliases.extend(FxHashMap::from_iter([
("collections".to_string(), "__debug__".to_string()),
("collections.abc".to_string(), "__debug__".to_string()),
]));
let diagnostics = test_path(
Path::new("flake8_import_conventions/nfkc_debug_alias.py"),
&LinterSettings {
flake8_import_conventions: super::settings::Settings {
aliases,
banned_aliases: FxHashMap::default(),
banned_from: FxHashSet::default(),
},
..LinterSettings::for_rule(Rule::UnconventionalImportAlias)
},
)?;
assert!(
diagnostics.is_empty(),
"No diagnostics should be emitted for NFKC '__debug__' aliases"
);
Ok(())
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's possible to implement a fix in the linter. We can implement this as a unit test next to Flake8ImportConventionsOptions or as a CLI test (see ruff/tests)

@danparizher danparizher requested a review from MichaReiser August 5, 2025 16:05
@MichaReiser MichaReiser enabled auto-merge (squash) August 6, 2025 06:39
@MichaReiser MichaReiser merged commit e917d30 into astral-sh:main Aug 6, 2025
37 checks passed
@danparizher danparizher deleted the fix-19118 branch August 6, 2025 12:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working fixes Related to suggested fixes for violations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ICN001 import aliases should be normalized before checking against __debug__

3 participants