[pyupgrade] Add from __future__ import annotations automatically (UP006)#23260
[pyupgrade] Add from __future__ import annotations automatically (UP006)#23260ntBre merged 18 commits intoastral-sh:mainfrom
pyupgrade] Add from __future__ import annotations automatically (UP006)#23260Conversation
|
ntBre
left a comment
There was a problem hiding this comment.
We need to be a bit more careful here to preserve the existing behavior of both FA100 and UP006 on stable and isolate the change to preview mode. We also need to check whether or not the from __future__ import annotations fix has been enabled in the user's configuration.
crates/ruff/tests/cli/lint.rs
Outdated
| success: false | ||
| exit_code: 1 | ||
| ----- stdout ----- | ||
| All checks passed! | ||
| test.py:1:31: UP006 Use `list` instead of `List` for type annotation | ||
| Found 1 error. | ||
| No fixes available (1 hidden fix can be enabled with the `--unsafe-fixes` option). |
There was a problem hiding this comment.
I don't think this is testing what it's meant to test now, but I think I'm going to have another comment farther down about why that is.
| if checker.is_rule_enabled(Rule::FutureRewritableTypeAnnotation) { | ||
| if !checker.semantic.future_annotations_or_stub() | ||
| && checker.target_version() < PythonVersion::PY39 | ||
| && checker.target_version() >= PythonVersion::PY37 | ||
| if checker.source_type.is_stub() | ||
| || checker.target_version() >= PythonVersion::PY39 | ||
| || (checker.target_version() >= PythonVersion::PY37 | ||
| && checker.semantic.in_annotation() | ||
| && !checker.settings().pyupgrade.keep_runtime_typing | ||
| { | ||
| flake8_future_annotations::rules::future_rewritable_type_annotation(checker, expr); | ||
| } | ||
| } |
There was a problem hiding this comment.
We need to preserve the existing FA100 behavior for now and only make this a preview change, so we can't just delete the FutureRewritableTypeAnnotation check.
We also need to check if the future-annotations setting is enabled, otherwise UP006 shouldn't apply this fix.
There was a problem hiding this comment.
What happens if FA100 is also enabled in preview? I don't think we needed to revert all changes to this code, we needed to make FA100 only fire when preview is disabled.
Signed-off-by: Bhuminjay <bhuminjaysoni@gmail.com>
Signed-off-by: Bhuminjay <bhuminjaysoni@gmail.com>
Signed-off-by: Bhuminjay <bhuminjaysoni@gmail.com>
Signed-off-by: Bhuminjay <bhuminjaysoni@gmail.com>
Signed-off-by: Bhuminjay <bhuminjaysoni@gmail.com>
b1a99c8 to
b5b53eb
Compare
|
Done, I have adressed the feedback & currently converted it to preview. Thank you for having patience with this PR. |
Signed-off-by: Bhuminjay <bhuminjaysoni@gmail.com>
…rules__pyupgrade__tests__UP006_future.py.snap
Signed-off-by: Bhuminjay <bhuminjaysoni@gmail.com>
…or_UP006' into import_annotation_for_UP006
|
Could you double-check the preview gate again? The ecosystem report is still showing a ton of stable changes. |
Signed-off-by: Bhuminjay <bhuminjaysoni@gmail.com>
Signed-off-by: Bhuminjay <bhuminjaysoni@gmail.com>
ntBre
left a comment
There was a problem hiding this comment.
Thanks for your continued work on this, but I still don't think we've gotten the preview checks exactly right. We need to handle both of these cases:
- preserve the behavior of both FA100 and UP006 on stable
- disable FA100 in preview when the preview fix for UP006 will add the
__future__import (this includes checkingfuture-annotations)- the FA100 diagnostic is otherwise redundant
Along these lines, I think we should make sure that we have preview and non-preview tests covering the case where both rules are enabled.
There was a problem hiding this comment.
Do we need a new test file, or could we just run one or more of the existing UP006 test fixtures with future-annotations enabled?
There was a problem hiding this comment.
oh sure, I use previous one.
| || is_up006_future_annotations_fix_enabled( | ||
| checker.settings(), | ||
| )) |
There was a problem hiding this comment.
Should we also check whether future-annotations is enabled here? I think we have to check it again in the rule itself, but if the setting is disabled, I don't think the preview check matters, i.e.:
| || is_up006_future_annotations_fix_enabled( | |
| checker.settings(), | |
| )) | |
| || (is_up006_future_annotations_fix_enabled( | |
| checker.settings(), | |
| ) && checker.settings().future_annotations)) |
| } | ||
|
|
||
| fn fix_applicability(checker: &Checker) -> (Applicability, Option<Edit>) { | ||
| if checker.target_version() >= PythonVersion::PY39 { |
There was a problem hiding this comment.
The two call sites this was factored out of used 3.10, not 3.9. Is that right?
There was a problem hiding this comment.
I have it simplified, however this wrt the original change totally removing the FA100 hence used 39
| if checker.target_version() >= PythonVersion::PY39 { | ||
| return (Applicability::Safe, None); | ||
| } | ||
| if checker.settings().pyupgrade.keep_runtime_typing { |
There was a problem hiding this comment.
What is this check for? I don't see this in the original code. We've already checked this when deciding whether or not to apply the rule in crates/ruff_linter/src/checkers/ast/analyze/expression.rs.
There was a problem hiding this comment.
I had when I removed the FA100 totaly,
| let (applicability, future_import) = fix_applicability(checker); | ||
| let mut secondary_edit = Vec::new(); | ||
| secondary_edit.push(import_edit); | ||
| if let Some(future) = future_import { | ||
| secondary_edit.push(future); | ||
| } |
There was a problem hiding this comment.
We could probably use some iterator tricks here like:
std::iter::once(import_edit).chain(future_import)| if checker.settings().future_annotations | ||
| && is_up006_future_annotations_fix_enabled(checker.settings()) | ||
| { | ||
| if checker.future_annotations_or_stub() { | ||
| (Applicability::Safe, None) | ||
| } else { | ||
| let future_import = checker.importer().add_future_import(); | ||
| (Applicability::Safe, Some(future_import)) |
There was a problem hiding this comment.
I'm honestly a bit confused by this whole helper function. This doesn't seem like a natural boundary to factor out and couple the applicability and fix. This is also the only case that returns Some(fix), and I don't think the future import fix is supposed to be safe anyway because it changes the behavior of all annotations in the file.
There was a problem hiding this comment.
Yes I agree, I have simplified it. & added the tests
| if checker.is_rule_enabled(Rule::FutureRewritableTypeAnnotation) { | ||
| if !checker.semantic.future_annotations_or_stub() | ||
| && checker.target_version() < PythonVersion::PY39 | ||
| && checker.target_version() >= PythonVersion::PY37 | ||
| if checker.source_type.is_stub() | ||
| || checker.target_version() >= PythonVersion::PY39 | ||
| || (checker.target_version() >= PythonVersion::PY37 | ||
| && checker.semantic.in_annotation() | ||
| && !checker.settings().pyupgrade.keep_runtime_typing | ||
| { | ||
| flake8_future_annotations::rules::future_rewritable_type_annotation(checker, expr); | ||
| } | ||
| } |
There was a problem hiding this comment.
What happens if FA100 is also enabled in preview? I don't think we needed to revert all changes to this code, we needed to make FA100 only fire when preview is disabled.
…rules__pyupgrade__tests__UP006_future.py__preview.snap
Thank you for the detailed feedback , I have addressed both the cases added tests accordingly & also the stable ecosystem changes are reflected as when future import is already there marking the fix safe. |
|
Thank you! I pushed a couple of commits addressing my remaining concerns. I'm hoping that clears up the stable ecosystem report, and then I'll take another quick look over the whole diff tomorrow. |
this should fully preserve the stable behavior of a safe fix for Python versions after 3.10
|
Well that's an interesting quirk of the ecosystem check. I guess we don't get any changes even in preview since the |
pyupgrade] Add from __future__ import annotations automatically (UP006)
|
The message for FA100 is super vague, but I know that's not what you're trying to fix here. 😅 |
|
I guess it is kind of what we're trying to fix. This is a step toward getting rid of FA100 entirely! Thanks for taking a look! |
Summary
part of #19359
Test Plan
added tests & snapshots