mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 18:28:24 +00:00
[flake8-pyi] Implement PYI044 (#5021)
## Summary This implements PYI044. This rule checks if `from __future__ import annotations` is used in stub files as it has no effect in stub files, since type checkers automatically treat stubs as having those semantics. Updates https://github.com/astral-sh/ruff/issues/848 ## Test Plan Added a test case and snapshots.
This commit is contained in:
parent
6a5f317362
commit
8161757229
10 changed files with 73 additions and 0 deletions
7
crates/ruff/resources/test/fixtures/flake8_pyi/PYI044.py
vendored
Normal file
7
crates/ruff/resources/test/fixtures/flake8_pyi/PYI044.py
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Bad import.
|
||||
from __future__ import annotations # Not PYI044 (not a stubfile).
|
||||
|
||||
# Good imports.
|
||||
from __future__ import Something
|
||||
import sys
|
||||
from socket import AF_INET
|
7
crates/ruff/resources/test/fixtures/flake8_pyi/PYI044.pyi
vendored
Normal file
7
crates/ruff/resources/test/fixtures/flake8_pyi/PYI044.pyi
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Bad import.
|
||||
from __future__ import annotations # PYI044.
|
||||
|
||||
# Good imports.
|
||||
from __future__ import Something
|
||||
import sys
|
||||
from socket import AF_INET
|
|
@ -1121,6 +1121,9 @@ where
|
|||
if self.enabled(Rule::UnaliasedCollectionsAbcSetImport) {
|
||||
flake8_pyi::rules::unaliased_collections_abc_set_import(self, import_from);
|
||||
}
|
||||
if self.enabled(Rule::FutureAnnotationsInStub) {
|
||||
flake8_pyi::rules::from_future_import(self, import_from);
|
||||
}
|
||||
}
|
||||
for alias in names {
|
||||
if let Some("__future__") = module {
|
||||
|
|
|
@ -616,6 +616,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||
(Flake8Pyi, "035") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::UnassignedSpecialVariableInStub),
|
||||
(Flake8Pyi, "042") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::SnakeCaseTypeAlias),
|
||||
(Flake8Pyi, "043") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::TSuffixedTypeAlias),
|
||||
(Flake8Pyi, "044") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::FutureAnnotationsInStub),
|
||||
(Flake8Pyi, "045") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::IterMethodReturnIterable),
|
||||
(Flake8Pyi, "048") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::StubBodyMultipleStatements),
|
||||
(Flake8Pyi, "050") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::NoReturnArgumentAnnotationInStub),
|
||||
|
|
|
@ -54,6 +54,8 @@ mod tests {
|
|||
#[test_case(Rule::StubBodyMultipleStatements, Path::new("PYI048.pyi"))]
|
||||
#[test_case(Rule::TSuffixedTypeAlias, Path::new("PYI043.py"))]
|
||||
#[test_case(Rule::TSuffixedTypeAlias, Path::new("PYI043.pyi"))]
|
||||
#[test_case(Rule::FutureAnnotationsInStub, Path::new("PYI044.py"))]
|
||||
#[test_case(Rule::FutureAnnotationsInStub, Path::new("PYI044.pyi"))]
|
||||
#[test_case(Rule::TypeCommentInStub, Path::new("PYI033.py"))]
|
||||
#[test_case(Rule::TypeCommentInStub, Path::new("PYI033.pyi"))]
|
||||
#[test_case(Rule::TypedArgumentDefaultInStub, Path::new("PYI011.py"))]
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
use rustpython_parser::ast::StmtImportFrom;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
#[violation]
|
||||
pub struct FutureAnnotationsInStub;
|
||||
|
||||
impl Violation for FutureAnnotationsInStub {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`from __future__ import annotations` has no effect in stub files, since type checkers automatically treat stubs as having those semantics")
|
||||
}
|
||||
}
|
||||
|
||||
/// PYI044
|
||||
pub(crate) fn from_future_import(checker: &mut Checker, target: &StmtImportFrom) {
|
||||
if let StmtImportFrom {
|
||||
range,
|
||||
module: Some(name),
|
||||
names,
|
||||
..
|
||||
} = target
|
||||
{
|
||||
if name == "__future__" && names.iter().any(|alias| &*alias.name == "annotations") {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(FutureAnnotationsInStub, *range));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ pub(crate) use collections_named_tuple::*;
|
|||
pub(crate) use docstring_in_stubs::*;
|
||||
pub(crate) use duplicate_union_member::*;
|
||||
pub(crate) use ellipsis_in_non_empty_class_body::*;
|
||||
pub(crate) use future_annotations_in_stub::*;
|
||||
pub(crate) use iter_method_return_iterable::*;
|
||||
pub(crate) use no_return_argument_annotation::*;
|
||||
pub(crate) use non_empty_stub_body::*;
|
||||
|
@ -28,6 +29,7 @@ mod collections_named_tuple;
|
|||
mod docstring_in_stubs;
|
||||
mod duplicate_union_member;
|
||||
mod ellipsis_in_non_empty_class_body;
|
||||
mod future_annotations_in_stub;
|
||||
mod iter_method_return_iterable;
|
||||
mod no_return_argument_annotation;
|
||||
mod non_empty_stub_body;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pyi/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pyi/mod.rs
|
||||
---
|
||||
PYI044.pyi:2:1: PYI044 `from __future__ import annotations` has no effect in stub files, since type checkers automatically treat stubs as having those semantics
|
||||
|
|
||||
1 | # Bad import.
|
||||
2 | from __future__ import annotations # PYI044.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI044
|
||||
3 |
|
||||
4 | # Good imports.
|
||||
|
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue