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.
-
Discussion started from here.
Copy-pasting the write-up that I posted there:
CLI
--fix
- changed to fix onlyAutomatic
fixes and rules in thefixable
set--fix-unsafe
- new option, will fixAutomatic
andSuggested
fixes. 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".Manual
changes will never be fixed--diff
- will output onlyAutomatic
fixes and rules in thefixable
set--fix-only
- will only fixAutomatic
fixes and rules in thefixable
setRules with a
Manual
applicability will never be fixed, nor will rules in theunfixable
set.Configuration File
fixable
/unfixable
remain as normal, preserving backwards compatibility.Implementation
Consider the example where we're enforcing default rules (e.g.,
E
,F
) and F841 (unused variable).The
Fix
gets generated here - assume that we're going with theoverride
field as well. TheFix::suggested()
constructor would assign anoverride: None
. The user then runs--fix
. Ruff goes out and fixes allAutomatic
fixes, leaving F841 untouched.Now assume that the user wants to fix all Automatic fixes, with F841 added. They F841 into the
fixable
set in theirpyproject.toml
file. Thefixable
/unfixable
tables 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
Applicability
has to be overridden. This can be done in a few ways (and thanks for pushing back, I think the override field is worse):override
field. We could add aset_override()
method toFix
which 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.Checker
handles 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,
Checker
would see that the "base applicability" (determined by seeing that the user ran--fix
and not--fix-unsafe
) isAutomatic
, and thatfixable
contains 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-all
or something to denote that it fixes allAutomatic
andSuggested
rules. 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
Applicability
like a hierarchy, we should default to the highest level (i.e.Automatic
- we don't want to do anything withSuggested
if the user hasn't specified it) but always use the lowest level that the user specifies. If the user specifies--fix-unsafe
, then--fix-only
and--diff
should includeSuggested
fixes.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
--diff
should show them. In my opinion,--fix-only
and--diff
should always show the same rules, gated by what sort of "fix" command (e.g.,--fix
vs.--fix-unsafe
) the user provides.5. Configuration: How would I promote a single suggested rule?
The contents of the
fixable
/unfixable
sets inpyproject.toml
should 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
,--fix
won'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