Autofix Automatic/Suggested fixes with --fix #5476
Replies: 4 comments 22 replies
-
|
Thanks @evanrittenhouse. Sounds all good to me. A follow up on
The way I understand |
Beta Was this translation helpful? Give feedback.
-
Where do you think it would be best to add the logic to filter out suggested fixes? |
Beta Was this translation helpful? Give feedback.
-
Fix Applicability API Changes
@evanrittenhouse is this summary accurate? I want to propose the change to the team and want to make sure I have all the facts right |
Beta Was this translation helpful? Give feedback.
-
|
I've been thinking about this as part of our overall CLI design, here's a relevant excerpt: Opt-in to applicability A
Adjusting fix applicability by rule Settings should be added to support adjusting the applicability of fixes for rules:
Rules can have fixes at different applicability levels depending on the context. Fixes will never be promoted from manual, if attempted a warning will be displayed (we cannot know until a violation is detected if a rule's fix will be manual — if we include the possible applicability values on the rule itself we can error earlier). Fixes can always be demoted. If the applicability for a rule is adjusted, all fixes from that rule will not exceed the adjusted applicability. These settings should not be exposed as command line options — they’re not particularly useful for one-off invocations.
cc @evanrittenhouse would love to hear your thoughts |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Discussion started from here.
Copy-pasting the write-up that I posted there:
CLI
--fix- changed to fix onlyAutomaticfixes and rules in thefixableset--fix-unsafe- new option, will fixAutomaticandSuggestedfixes. While it differs from the implementation's naming conventions, as a user "safe" and "unsafe" make more sense, IMO. From the fixer's perspective, an "automatic" or "suggested" fix makes sense. I think it's clearer for users to consider fixes as "this is safe to implement" or "this is unsafe".Manualchanges will never be fixed--diff- will output onlyAutomaticfixes and rules in thefixableset--fix-only- will only fixAutomaticfixes and rules in thefixablesetRules with a
Manualapplicability will never be fixed, nor will rules in theunfixableset.Configuration File
fixable/unfixableremain as normal, preserving backwards compatibility.Implementation
Consider the example where we're enforcing default rules (e.g.,
E,F) and F841 (unused variable).The
Fixgets generated here - assume that we're going with theoverridefield as well. TheFix::suggested()constructor would assign anoverride: None. The user then runs--fix. Ruff goes out and fixes allAutomaticfixes, leaving F841 untouched.Now assume that the user wants to fix all Automatic fixes, with F841 added. They F841 into the
fixableset in theirpyproject.tomlfile. Thefixable/unfixabletables would essentially operate as ways to say "I always want this fixed" or "I never want this fixed".We need to somehow tell F841 that its
Applicabilityhas to be overridden. This can be done in a few ways (and thanks for pushing back, I think the override field is worse):overridefield. We could add aset_override()method toFixwhich allows you to pass anApplicability, settingoverride: Some(new_applicability). The downside here is going through and addingset_override()calls everywhere, and it adds memory, like you said.Checkerhandles all fixing logic itself, now based on the CLI command and the contents offixable/unfixable. The upside here is no change is required on a per-rule basis -checker.patch(Rule::UnusedVariable)would remain true and generate the fix.If we go with the second option,
Checkerwould see that the "base applicability" (determined by seeing that the user ran--fixand not--fix-unsafe) isAutomatic, and thatfixablecontains F841. Regardless of applicability,patch()would therefore return true, and we'd generate the fix. All fix generation would be gated throughChecker.patch().What do you think?
@MichaReiser responded with 5 questions which I'll answer here.
1. --fix-unsafe: I think its good to have the option. We can align on the final naming later.
Cool. We could also call it
--fix-allor something to denote that it fixes allAutomaticandSuggestedrules. But yeah, semantic changes should occur at the end.2. --fix-only: Should --fix-unsafe enable fixing the suggested fixes too?
Yes. If you think of
Applicabilitylike a hierarchy, we should default to the highest level (i.e.Automatic- we don't want to do anything withSuggestedif the user hasn't specified it) but always use the lowest level that the user specifies. If the user specifies--fix-unsafe, then--fix-onlyand--diffshould includeSuggestedfixes.3. --diff: Should --fix-unsafe enable the suggested fixes? I think it should be aligned with --fix-only, considering that --diff implies --fix-only.
See above
4. --diff: We could show diffs for manual fixes. I'm not recommending that we should do this. We may decide to only show the fixes as part of the MessageEmitters in the future.
If we go with what I described in option 2, then I don't think
--diffshould show them. In my opinion,--fix-onlyand--diffshould always show the same rules, gated by what sort of "fix" command (e.g.,--fixvs.--fix-unsafe) the user provides.5. Configuration: How would I promote a single suggested rule?
The contents of the
fixable/unfixablesets inpyproject.tomlshould trump any fix level that we've applied, IMO.In the example above, the user wants to only promote F841, which we've marked as
Suggested. Since it'sSuggested,--fixwon't do anything to it. If the user adds it topyproject.toml#fixable, we will forcibly include it in the fixed set, even if the user calls--fix. Similarly, if a user wants to forcibly exclude a rule from the set, they can add it tounfixable. If a rule is in there, we will never fix it, even if it isAutomatic.Beta Was this translation helpful? Give feedback.
All reactions