Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flake8-import-conventions] Syntax check aliases supplied in configuration for unconventional-import-alias (ICN001) #14477

Merged
merged 9 commits into from
Nov 21, 2024

Conversation

dylwil3
Copy link
Collaborator

@dylwil3 dylwil3 commented Nov 20, 2024

This PR introduces a validation step to the deserialization of the configuration for unconventional-import-alias (ICN001). We verify that the import module and alias supplied have valid syntax in order to avoid a panic if these aliases are added in during a fix.

Closes #14439

@dylwil3
Copy link
Collaborator Author

dylwil3 commented Nov 20, 2024

Two notes:

  • Sorry for bloating the workspace crate with serde and especially with serde_json (since I only use the latter for a test)... let me know if you'd like me to work around that
  • I don't add a deserialization check for "banned aliases" or "banned from" since a fix would never add those to the source code

Copy link
Contributor

github-actions bot commented Nov 20, 2024

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.

@MichaReiser MichaReiser added the configuration Related to settings and configuration label Nov 20, 2024
@@ -42,6 +43,7 @@ serde = { workspace = true }
shellexpand = { workspace = true }
strum = { workspace = true }
toml = { workspace = true }
serde_json.workspace = true
Copy link
Member

Choose a reason for hiding this comment

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

This should be a dev-dependency if it is only used in tests

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No longer used (test moved to integration test)

@MichaReiser MichaReiser added bug Something isn't working and removed configuration Related to settings and configuration labels Nov 20, 2024
Comment on lines 3443 to 3449
#[test]
fn flake8_import_conventions_validate_aliases() {
let json_options = r#"{"aliases": {"a.b":"a.b"}}"#;
let result: Result<Flake8ImportConventionsOptions, _> = serde_json::from_str(json_options);
assert!(result.unwrap_err().to_string().contains("Module must be valid identifier separated by single periods and alias must be valid identifier"));
}

Copy link
Member

Choose a reason for hiding this comment

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

I'm leaning towards making this a ruff cli integration test. It then also demonstrates how the error message is displayed to the users.

See

fn top_level_options() -> Result<()> {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done!

Comment on lines 1387 to 1394
if module.is_empty()
|| module.split('.').any(|part| !is_identifier(part))
|| !is_identifier(alias)
{
return Err(de::Error::custom(
"Module must be valid identifier separated by single periods and alias must be valid identifier",
));
}
Copy link
Member

Choose a reason for hiding this comment

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

I suggest that we use two dedicated errors: One for alias and one for module.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done!

@AlexWaygood
Copy link
Member

Let's try to get this into ruff 0.8 if we can — while it is a bugfix, it might still be breaking for some users who are currently "using the rule incorrectly"

@AlexWaygood AlexWaygood added this to the v0.8 milestone Nov 20, 2024
@AlexWaygood AlexWaygood changed the base branch from main to ruff-0.8 November 20, 2024 08:49
@AlexWaygood AlexWaygood changed the base branch from ruff-0.8 to main November 20, 2024 08:49
@AlexWaygood
Copy link
Member

AlexWaygood commented Nov 20, 2024

Sorry — I optimistically tried to change the target branch, but it messed up the diff, so I swiftly reverted that back 😅

It's probably fine if this goes straight into main, though, as long as we merge it before the 0.8 release goes out. I highly doubt we'll be cutting another patch release before 0.8, since everything is roughly on schedule for the minor release

@AlexWaygood AlexWaygood added the breaking Breaking API change label Nov 20, 2024
@MichaReiser
Copy link
Member

I also don't consider this breaking. It doesn't change the intent of the rule.

@AlexWaygood
Copy link
Member

I also don't consider this breaking. It doesn't change the intent of the rule.

I agree that it doesn't change the intent of the rule, but clearly some users are not using the rule as it was intended: #14439 (comment). We will break those users; this is a case of Hyrum's law.

I strongly agree with the change, I'd just prefer to have it go into Ruff 0.8 and to list it in BREAKING_CHANGES.md, out of an abundance of caution.

@dylwil3
Copy link
Collaborator Author

dylwil3 commented Nov 20, 2024

I agree that it doesn't change the intent of the rule, but clearly some users are not using the rule as it was intended: #14439 (comment). We will break those users; this is a case of Hyrum's law.

Relevant xkcd

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

Thanks for adding the integration tests. They show that the error messages aren't great. We should either:

  • minimal: Include the alias and module name in the error message
  • better: Use newtype wrappers for Module and Alias (FxHashMap<ModuleName, Alias>) and implement Deserialize on the newtype wrappers. That should allow serde to highlight the relevant line and column in the error message.

Cause: Failed to parse [TMP]/ruff.toml
Cause: TOML parse error at line 2, column 2
|
2 | [lint.flake8-import-conventions.aliases]
Copy link
Member

Choose a reason for hiding this comment

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

Hmm. The errors aren't great. Let's at least include the alias in the error message to help users figure out what's going on. The same for the module name.

@@ -1327,6 +1329,7 @@ pub struct Flake8ImportConventionsOptions {
scipy = "sp"
"#
)]
#[serde(deserialize_with = "deserialize_and_validate_aliases")]
pub aliases: Option<FxHashMap<String, String>>,
Copy link
Member

Choose a reason for hiding this comment

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

We would probably get better error messages if you create a newtype for ModuleName and Alias and implement Deserialize for them. I would expect that serde can then narrow the error message to the specific line rather than the entire table

Copy link
Member

@AlexWaygood AlexWaygood Nov 21, 2024

Choose a reason for hiding this comment

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

This PR does actually already seem to be a small improvement on the status quo when it comes to line numbers. Currently if I make this change to typeshed's pyproject.toml file:

diff --git a/pyproject.toml b/pyproject.toml
index 46014bcd2..927da6162 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -111,6 +111,9 @@ ignore = [
     "E501", # Line too long
 ]
 
+[tool.ruff.lint.flake8-import-conventions.aliases]
+"pandas" = 42
+

Then Ruff v0.7.1 gives me this error message:

ruff failed
  Cause: Failed to parse /Users/alexw/dev/typeshed/pyproject.toml
  Cause: TOML parse error at line 27, column 1
   |
27 | [tool.ruff.lint]
   | ^^^^^^^^^^^^^^^^
invalid type: integer `42`, expected a string

@AlexWaygood AlexWaygood removed this from the v0.8 milestone Nov 21, 2024
@MichaReiser
Copy link
Member

I pushed a change that implements Deserialize for the key and value. I'm surprised that serde isn't better at handling this.

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

@AlexWaygood should we merge?

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Thanks @dylwil3!

@MichaReiser MichaReiser added configuration Related to settings and configuration and removed bug Something isn't working labels Nov 21, 2024
@dylwil3
Copy link
Collaborator Author

dylwil3 commented Nov 21, 2024

@MichaReiser you beat me to it! Much improved error message, thanks!

@MichaReiser MichaReiser enabled auto-merge (squash) November 21, 2024 15:51
@MichaReiser MichaReiser removed the breaking Breaking API change label Nov 21, 2024
@MichaReiser MichaReiser merged commit 2efa3fb into astral-sh:main Nov 21, 2024
19 checks passed
@AlexWaygood AlexWaygood added this to the v0.8 milestone Nov 21, 2024
MichaReiser added a commit that referenced this pull request Nov 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
configuration Related to settings and configuration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Possible error when trying to fix with ICN001
3 participants