mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-19 11:45:40 +00:00
[flake8-future-annotations] Add autofix (FA100) (#18903)
Summary -- This PR resolves the easiest part of https://github.com/astral-sh/ruff/issues/18502 by adding an autofix that just adds `from __future__ import annotations` at the top of the file, in the same way as FA102, which already has an identical unsafe fix. Test Plan -- Existing snapshots, updated to add the fixes.
This commit is contained in:
parent
c1fed55d51
commit
7783cea14f
6 changed files with 81 additions and 17 deletions
|
|
@ -1,9 +1,11 @@
|
||||||
|
use ruff_diagnostics::Fix;
|
||||||
use ruff_python_ast::Expr;
|
use ruff_python_ast::Expr;
|
||||||
|
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
use ruff_python_semantic::{MemberNameImport, NameImport};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::Violation;
|
use crate::AlwaysFixableViolation;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
|
@ -61,6 +63,10 @@ use crate::checkers::ast::Checker;
|
||||||
/// def func(obj: dict[str, int | None]) -> None: ...
|
/// def func(obj: dict[str, int | None]) -> None: ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// ## Fix safety
|
||||||
|
/// This rule's fix is marked as unsafe, as adding `from __future__ import annotations`
|
||||||
|
/// may change the semantics of the program.
|
||||||
|
///
|
||||||
/// ## Options
|
/// ## Options
|
||||||
/// - `target-version`
|
/// - `target-version`
|
||||||
#[derive(ViolationMetadata)]
|
#[derive(ViolationMetadata)]
|
||||||
|
|
@ -68,12 +74,16 @@ pub(crate) struct FutureRewritableTypeAnnotation {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for FutureRewritableTypeAnnotation {
|
impl AlwaysFixableViolation for FutureRewritableTypeAnnotation {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let FutureRewritableTypeAnnotation { name } = self;
|
let FutureRewritableTypeAnnotation { name } = self;
|
||||||
format!("Add `from __future__ import annotations` to simplify `{name}`")
|
format!("Add `from __future__ import annotations` to simplify `{name}`")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fix_title(&self) -> String {
|
||||||
|
"Add `from __future__ import annotations`".to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FA100
|
/// FA100
|
||||||
|
|
@ -83,7 +93,17 @@ pub(crate) fn future_rewritable_type_annotation(checker: &Checker, expr: &Expr)
|
||||||
.resolve_qualified_name(expr)
|
.resolve_qualified_name(expr)
|
||||||
.map(|binding| binding.to_string());
|
.map(|binding| binding.to_string());
|
||||||
|
|
||||||
if let Some(name) = name {
|
let Some(name) = name else { return };
|
||||||
checker.report_diagnostic(FutureRewritableTypeAnnotation { name }, expr.range());
|
|
||||||
}
|
let import = &NameImport::ImportFrom(MemberNameImport::member(
|
||||||
|
"__future__".to_string(),
|
||||||
|
"annotations".to_string(),
|
||||||
|
));
|
||||||
|
checker
|
||||||
|
.report_diagnostic(FutureRewritableTypeAnnotation { name }, expr.range())
|
||||||
|
.set_fix(Fix::unsafe_edit(
|
||||||
|
checker
|
||||||
|
.importer()
|
||||||
|
.add_import(import, ruff_text_size::TextSize::default()),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,32 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
edge_case.py:5:13: FA100 Add `from __future__ import annotations` to simplify `typing.List`
|
edge_case.py:5:13: FA100 [*] Add `from __future__ import annotations` to simplify `typing.List`
|
||||||
|
|
|
|
||||||
5 | def main(_: List[int]) -> None:
|
5 | def main(_: List[int]) -> None:
|
||||||
| ^^^^ FA100
|
| ^^^^ FA100
|
||||||
6 | a_list: t.List[str] = []
|
6 | a_list: t.List[str] = []
|
||||||
7 | a_list.append("hello")
|
7 | a_list.append("hello")
|
||||||
|
|
|
|
||||||
|
= help: Add `from __future__ import annotations`
|
||||||
|
|
||||||
edge_case.py:6:13: FA100 Add `from __future__ import annotations` to simplify `typing.List`
|
ℹ Unsafe fix
|
||||||
|
1 |+from __future__ import annotations
|
||||||
|
1 2 | from typing import List
|
||||||
|
2 3 | import typing as t
|
||||||
|
3 4 |
|
||||||
|
|
||||||
|
edge_case.py:6:13: FA100 [*] Add `from __future__ import annotations` to simplify `typing.List`
|
||||||
|
|
|
|
||||||
5 | def main(_: List[int]) -> None:
|
5 | def main(_: List[int]) -> None:
|
||||||
6 | a_list: t.List[str] = []
|
6 | a_list: t.List[str] = []
|
||||||
| ^^^^^^ FA100
|
| ^^^^^^ FA100
|
||||||
7 | a_list.append("hello")
|
7 | a_list.append("hello")
|
||||||
|
|
|
|
||||||
|
= help: Add `from __future__ import annotations`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
1 |+from __future__ import annotations
|
||||||
|
1 2 | from typing import List
|
||||||
|
2 3 | import typing as t
|
||||||
|
3 4 |
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
from_typing_import.py:5:13: FA100 Add `from __future__ import annotations` to simplify `typing.List`
|
from_typing_import.py:5:13: FA100 [*] Add `from __future__ import annotations` to simplify `typing.List`
|
||||||
|
|
|
|
||||||
4 | def main() -> None:
|
4 | def main() -> None:
|
||||||
5 | a_list: List[str] = []
|
5 | a_list: List[str] = []
|
||||||
| ^^^^ FA100
|
| ^^^^ FA100
|
||||||
6 | a_list.append("hello")
|
6 | a_list.append("hello")
|
||||||
|
|
|
|
||||||
|
= help: Add `from __future__ import annotations`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
1 |+from __future__ import annotations
|
||||||
|
1 2 | from typing import List
|
||||||
|
2 3 |
|
||||||
|
3 4 |
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
from_typing_import_many.py:5:13: FA100 Add `from __future__ import annotations` to simplify `typing.List`
|
from_typing_import_many.py:5:13: FA100 [*] Add `from __future__ import annotations` to simplify `typing.List`
|
||||||
|
|
|
|
||||||
4 | def main() -> None:
|
4 | def main() -> None:
|
||||||
5 | a_list: List[Optional[str]] = []
|
5 | a_list: List[Optional[str]] = []
|
||||||
|
|
@ -10,8 +9,15 @@ from_typing_import_many.py:5:13: FA100 Add `from __future__ import annotations`
|
||||||
6 | a_list.append("hello")
|
6 | a_list.append("hello")
|
||||||
7 | a_dict = cast(Dict[int | None, Union[int, Set[bool]]], {})
|
7 | a_dict = cast(Dict[int | None, Union[int, Set[bool]]], {})
|
||||||
|
|
|
|
||||||
|
= help: Add `from __future__ import annotations`
|
||||||
|
|
||||||
from_typing_import_many.py:5:18: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
|
ℹ Unsafe fix
|
||||||
|
1 |+from __future__ import annotations
|
||||||
|
1 2 | from typing import Dict, List, Optional, Set, Union, cast
|
||||||
|
2 3 |
|
||||||
|
3 4 |
|
||||||
|
|
||||||
|
from_typing_import_many.py:5:18: FA100 [*] Add `from __future__ import annotations` to simplify `typing.Optional`
|
||||||
|
|
|
|
||||||
4 | def main() -> None:
|
4 | def main() -> None:
|
||||||
5 | a_list: List[Optional[str]] = []
|
5 | a_list: List[Optional[str]] = []
|
||||||
|
|
@ -19,3 +25,10 @@ from_typing_import_many.py:5:18: FA100 Add `from __future__ import annotations`
|
||||||
6 | a_list.append("hello")
|
6 | a_list.append("hello")
|
||||||
7 | a_dict = cast(Dict[int | None, Union[int, Set[bool]]], {})
|
7 | a_dict = cast(Dict[int | None, Union[int, Set[bool]]], {})
|
||||||
|
|
|
|
||||||
|
= help: Add `from __future__ import annotations`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
1 |+from __future__ import annotations
|
||||||
|
1 2 | from typing import Dict, List, Optional, Set, Union, cast
|
||||||
|
2 3 |
|
||||||
|
3 4 |
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
import_typing.py:5:13: FA100 Add `from __future__ import annotations` to simplify `typing.List`
|
import_typing.py:5:13: FA100 [*] Add `from __future__ import annotations` to simplify `typing.List`
|
||||||
|
|
|
|
||||||
4 | def main() -> None:
|
4 | def main() -> None:
|
||||||
5 | a_list: typing.List[str] = []
|
5 | a_list: typing.List[str] = []
|
||||||
| ^^^^^^^^^^^ FA100
|
| ^^^^^^^^^^^ FA100
|
||||||
6 | a_list.append("hello")
|
6 | a_list.append("hello")
|
||||||
|
|
|
|
||||||
|
= help: Add `from __future__ import annotations`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
1 |+from __future__ import annotations
|
||||||
|
1 2 | import typing
|
||||||
|
2 3 |
|
||||||
|
3 4 |
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
source: crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
import_typing_as.py:5:13: FA100 Add `from __future__ import annotations` to simplify `typing.List`
|
import_typing_as.py:5:13: FA100 [*] Add `from __future__ import annotations` to simplify `typing.List`
|
||||||
|
|
|
|
||||||
4 | def main() -> None:
|
4 | def main() -> None:
|
||||||
5 | a_list: t.List[str] = []
|
5 | a_list: t.List[str] = []
|
||||||
| ^^^^^^ FA100
|
| ^^^^^^ FA100
|
||||||
6 | a_list.append("hello")
|
6 | a_list.append("hello")
|
||||||
|
|
|
|
||||||
|
= help: Add `from __future__ import annotations`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
1 |+from __future__ import annotations
|
||||||
|
1 2 | import typing as t
|
||||||
|
2 3 |
|
||||||
|
3 4 |
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue