[flake8-pyi] Significantly improve accuracy of PYI019 if preview mode is enabled#15888
[flake8-pyi] Significantly improve accuracy of PYI019 if preview mode is enabled#15888AlexWaygood merged 1 commit intomainfrom
PYI019 if preview mode is enabled#15888Conversation
|
| code | total | + violation | - violation | + fix | - fix |
|---|---|---|---|---|---|
| PYI019 | 30 | 30 | 0 | 0 | 0 |
These all look like true positives from what I can see 🥳 |
This comment was marked as outdated.
This comment was marked as outdated.
e82e76b to
4e2dc61
Compare
This comment was marked as resolved.
This comment was marked as resolved.
|
This is another case where diagnsotics with multiple ranges were really nice CC: @BurntSushi |
4e2dc61 to
a73295b
Compare
MichaReiser
left a comment
There was a problem hiding this comment.
This is excellent. Thank you
| .unwrap_or_else(|| parameters.end()); | ||
|
|
||
| let (method, diagnostic_range) = | ||
| match (function_kind, checker.settings.preview, returns.as_deref()) { |
There was a problem hiding this comment.
This one will be hard to find because it won't show up when searching for preview.is_enabled or preview.is_disabled (which I normally use).
It makes me wonder if we should start doing something similar to the formatter where we have a preview.rs file and each preview feature defines a is_feature_name_enabled(&settings). It makes it very easy to see all current preview behaviors and promoting it is as easy as removing the function -> Rust will tell you exactly where you have to make changes.
However, this will likely mean that you'd have to change this match to inline the preview check into the match arms. Although I'd kind of prefer this anyway because it reduces the number of lines that need changing when promoting the feature (the match header remains unchanged).
match (function_kind, returns.as_deref() {
(FunctionType::Function | FunctionType::StaticMethod, _) => return None,
(FunctionType::ClassMethod, returns) => {
if is_more_precise_custom_type_var_for_self_enabled(settings) {
...
} else if let Some(returns) = returns {
...
}There was a problem hiding this comment.
I've switched to use preview.is_enabled(). It's not pretty... but I'm consoling myself that we'll be able to get rid of it soonish 😆
There was a problem hiding this comment.
Oh no, I hoped you start using the preview feature functions... I'll think of you when I have to promote the behavior change 🤣
There was a problem hiding this comment.
Ohh sorry lol. You can give this one to me when the time comes 🤣
crates/ruff_linter/src/rules/flake8_pyi/rules/custom_type_var_for_self.rs
Outdated
Show resolved
Hide resolved
a73295b to
0e243a3
Compare
…tom-type-var-for-self`(`PYI019`) (#16607) ## Summary This PR stabilizes several preview-only behaviours for `custom-typevar-for-self` (`PYI019`). Namely: - A new, more accurate technique is now employed for detecting custom TypeVars that are replaceable with `Self`. See #15888 for details. - The range of the diagnostic is now the full function header rather than just the return annotation. (Previously, the rule only applied to methods with return annotations, but this is no longer true due to the changes in the first bullet point.) - The fix is now available even when preview mode is not enabled. ## Test Plan - Existing snapshots that do not have preview mode enabled are updated - Preview-specific snapshots are removed - I'll check the ecosystem report on this PR to verify everything's as expected
…tom-type-var-for-self`(`PYI019`) (#16607) ## Summary This PR stabilizes several preview-only behaviours for `custom-typevar-for-self` (`PYI019`). Namely: - A new, more accurate technique is now employed for detecting custom TypeVars that are replaceable with `Self`. See #15888 for details. - The range of the diagnostic is now the full function header rather than just the return annotation. (Previously, the rule only applied to methods with return annotations, but this is no longer true due to the changes in the first bullet point.) - The fix is now available even when preview mode is not enabled. ## Test Plan - Existing snapshots that do not have preview mode enabled are updated - Preview-specific snapshots are removed - I'll check the ecosystem report on this PR to verify everything's as expected
…tom-type-var-for-self`(`PYI019`) (#16607) ## Summary This PR stabilizes several preview-only behaviours for `custom-typevar-for-self` (`PYI019`). Namely: - A new, more accurate technique is now employed for detecting custom TypeVars that are replaceable with `Self`. See #15888 for details. - The range of the diagnostic is now the full function header rather than just the return annotation. (Previously, the rule only applied to methods with return annotations, but this is no longer true due to the changes in the first bullet point.) - The fix is now available even when preview mode is not enabled. ## Test Plan - Existing snapshots that do not have preview mode enabled are updated - Preview-specific snapshots are removed - I'll check the ecosystem report on this PR to verify everything's as expected
(This PR is stacked on top of #15885; review that first.)
Summary
The logic
PYI019uses to detect TypeVars that could be replaced withSelfis flawed in several significant ways:The rule only looks at methods that have return-type annotations, but there are lots of methods that don't have return-type annotations that could still have their custom TypeVars replaced with
Self.The rule assumes that if the first parameter has the same annotation as the return-type annotation in an instance method, the method will be using a TypeVar in its annotations. This heuristic is surprisingly accurate, but it's still a somewhat unprincipled heuristic. It means that the rule flags code like this as "using TypeVars that could be replaced with
Self, when that's not true at all:Following @InSyncWithFoo's excellent work in [
flake8-pyi] Fix more complex cases (PYI019) #15821 to move this rule to be a bindings-based rule, there's now no longer any need to use heuristics like this; we can do much better.Unfortunately, fixing these issues expands the scope of the rule (it will start flagging methods that it did not previously flag). This PR therefore applies these fixes only if preview mode is enabled. Otherwise, we continue to use the old heuristics that we always have.
Because the rule in preview mode can now apply to methods that do not have return-type annotations, we can no longer use the range of the return-type annotation as the range of the diagnostic. This PR therefore also changes the behaviour in preview mode so that we use the range of the "function header" for the diagnostic range (starting from the end of the function name, and ending either at the return-type annotation end (if there is a return-type annotation) or at the end of the function's parameters.
Test Plan
.pyfiles with preview mode enabled. (We already have a snapshot for.pyifiles with stable mode,.pyfiles with stable mode, and.pyifiles with preview mode.)