mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
Add PYI024 for flake8-pyi
plugin (#4756)
This commit is contained in:
parent
9d0ffd33ca
commit
2b2812c4f2
11 changed files with 142 additions and 0 deletions
9
crates/ruff/resources/test/fixtures/flake8_pyi/PYI024.py
vendored
Normal file
9
crates/ruff/resources/test/fixtures/flake8_pyi/PYI024.py
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
import collections
|
||||
|
||||
person: collections.namedtuple # OK
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
person: namedtuple # OK
|
||||
|
||||
person = namedtuple("Person", ["name", "age"]) # OK
|
11
crates/ruff/resources/test/fixtures/flake8_pyi/PYI024.pyi
vendored
Normal file
11
crates/ruff/resources/test/fixtures/flake8_pyi/PYI024.pyi
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
import collections
|
||||
|
||||
person: collections.namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple"
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
person: namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple"
|
||||
|
||||
person = namedtuple(
|
||||
"Person", ["name", "age"]
|
||||
) # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple"
|
|
@ -2292,6 +2292,11 @@ where
|
|||
if self.enabled(Rule::NumpyDeprecatedTypeAlias) {
|
||||
numpy::rules::deprecated_type_alias(self, expr);
|
||||
}
|
||||
if self.is_stub {
|
||||
if self.enabled(Rule::CollectionsNamedTuple) {
|
||||
flake8_pyi::rules::collections_named_tuple(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
// Ex) List[...]
|
||||
if self.any_enabled(&[
|
||||
|
@ -2424,6 +2429,11 @@ where
|
|||
if self.enabled(Rule::PrivateMemberAccess) {
|
||||
flake8_self::rules::private_member_access(self, expr);
|
||||
}
|
||||
if self.is_stub {
|
||||
if self.enabled(Rule::CollectionsNamedTuple) {
|
||||
flake8_pyi::rules::collections_named_tuple(self, expr);
|
||||
}
|
||||
}
|
||||
pandas_vet::rules::attr(self, attr, value, expr);
|
||||
}
|
||||
Expr::Call(ast::ExprCall {
|
||||
|
|
|
@ -591,6 +591,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||
(Flake8Pyi, "016") => (RuleGroup::Unspecified, Rule::DuplicateUnionMember),
|
||||
(Flake8Pyi, "020") => (RuleGroup::Unspecified, Rule::QuotedAnnotationInStub),
|
||||
(Flake8Pyi, "021") => (RuleGroup::Unspecified, Rule::DocstringInStub),
|
||||
(Flake8Pyi, "024") => (RuleGroup::Unspecified, Rule::CollectionsNamedTuple),
|
||||
(Flake8Pyi, "032") => (RuleGroup::Unspecified, Rule::AnyEqNeAnnotation),
|
||||
(Flake8Pyi, "033") => (RuleGroup::Unspecified, Rule::TypeCommentInStub),
|
||||
(Flake8Pyi, "042") => (RuleGroup::Unspecified, Rule::SnakeCaseTypeAlias),
|
||||
|
|
|
@ -518,6 +518,7 @@ ruff_macros::register_rules!(
|
|||
rules::flake8_pyi::rules::IterMethodReturnIterable,
|
||||
rules::flake8_pyi::rules::DuplicateUnionMember,
|
||||
rules::flake8_pyi::rules::EllipsisInNonEmptyClassBody,
|
||||
rules::flake8_pyi::rules::CollectionsNamedTuple,
|
||||
rules::flake8_pyi::rules::NonEmptyStubBody,
|
||||
rules::flake8_pyi::rules::PassInClassBody,
|
||||
rules::flake8_pyi::rules::PassStatementStubBody,
|
||||
|
|
|
@ -26,6 +26,8 @@ mod tests {
|
|||
#[test_case(Rule::DuplicateUnionMember, Path::new("PYI016.pyi"))]
|
||||
#[test_case(Rule::EllipsisInNonEmptyClassBody, Path::new("PYI013.py"))]
|
||||
#[test_case(Rule::EllipsisInNonEmptyClassBody, Path::new("PYI013.pyi"))]
|
||||
#[test_case(Rule::CollectionsNamedTuple, Path::new("PYI024.py"))]
|
||||
#[test_case(Rule::CollectionsNamedTuple, Path::new("PYI024.pyi"))]
|
||||
#[test_case(Rule::IterMethodReturnIterable, Path::new("PYI045.py"))]
|
||||
#[test_case(Rule::IterMethodReturnIterable, Path::new("PYI045.pyi"))]
|
||||
#[test_case(Rule::NonEmptyStubBody, Path::new("PYI010.py"))]
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::prelude::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for uses of `collections.namedtuple` in stub files.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// `typing.NamedTuple` is the "typed version" of `collections.namedtuple`.
|
||||
///
|
||||
/// The class generated by subclassing `typing.NamedTuple` is equivalent to
|
||||
/// `collections.namedtuple`, with the exception that `typing.NamedTuple`
|
||||
/// includes an `__annotations__` attribute, which allows type checkers to
|
||||
/// infer the types of the fields.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// from collections import namedtuple
|
||||
///
|
||||
///
|
||||
/// person = namedtuple("Person", ["name", "age"])
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// from typing import NamedTuple
|
||||
///
|
||||
///
|
||||
/// class Person(NamedTuple):
|
||||
/// name: str
|
||||
/// age: int
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct CollectionsNamedTuple;
|
||||
|
||||
impl Violation for CollectionsNamedTuple {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use `typing.NamedTuple` instead of `collections.namedtuple`")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> Option<String> {
|
||||
Some(format!("Replace with `typing.NamedTuple`"))
|
||||
}
|
||||
}
|
||||
|
||||
/// PYI024
|
||||
pub(crate) fn collections_named_tuple(checker: &mut Checker, expr: &Expr) {
|
||||
if checker
|
||||
.semantic_model()
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| {
|
||||
matches!(call_path.as_slice(), ["collections", "namedtuple"])
|
||||
})
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(CollectionsNamedTuple, expr.range()));
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ pub(crate) use any_eq_ne_annotation::{any_eq_ne_annotation, AnyEqNeAnnotation};
|
|||
pub(crate) use bad_version_info_comparison::{
|
||||
bad_version_info_comparison, BadVersionInfoComparison,
|
||||
};
|
||||
pub(crate) use collections_named_tuple::{collections_named_tuple, CollectionsNamedTuple};
|
||||
pub(crate) use docstring_in_stubs::{docstring_in_stubs, DocstringInStub};
|
||||
pub(crate) use duplicate_union_member::{duplicate_union_member, DuplicateUnionMember};
|
||||
pub(crate) use ellipsis_in_non_empty_class_body::{
|
||||
|
@ -33,6 +34,7 @@ pub(crate) use unrecognized_platform::{
|
|||
|
||||
mod any_eq_ne_annotation;
|
||||
mod bad_version_info_comparison;
|
||||
mod collections_named_tuple;
|
||||
mod docstring_in_stubs;
|
||||
mod duplicate_union_member;
|
||||
mod ellipsis_in_non_empty_class_body;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pyi/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pyi/mod.rs
|
||||
---
|
||||
PYI024.pyi:3:9: PYI024 Use `typing.NamedTuple` instead of `collections.namedtuple`
|
||||
|
|
||||
3 | import collections
|
||||
4 |
|
||||
5 | person: collections.namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple"
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ PYI024
|
||||
6 |
|
||||
7 | from collections import namedtuple
|
||||
|
|
||||
= help: Replace with `typing.NamedTuple`
|
||||
|
||||
PYI024.pyi:7:9: PYI024 Use `typing.NamedTuple` instead of `collections.namedtuple`
|
||||
|
|
||||
7 | from collections import namedtuple
|
||||
8 |
|
||||
9 | person: namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple"
|
||||
| ^^^^^^^^^^ PYI024
|
||||
10 |
|
||||
11 | person = namedtuple(
|
||||
|
|
||||
= help: Replace with `typing.NamedTuple`
|
||||
|
||||
PYI024.pyi:9:10: PYI024 Use `typing.NamedTuple` instead of `collections.namedtuple`
|
||||
|
|
||||
9 | person: namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple"
|
||||
10 |
|
||||
11 | person = namedtuple(
|
||||
| ^^^^^^^^^^ PYI024
|
||||
12 | "Person", ["name", "age"]
|
||||
13 | ) # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple"
|
||||
|
|
||||
= help: Replace with `typing.NamedTuple`
|
||||
|
||||
|
1
ruff.schema.json
generated
1
ruff.schema.json
generated
|
@ -2209,6 +2209,7 @@
|
|||
"PYI02",
|
||||
"PYI020",
|
||||
"PYI021",
|
||||
"PYI024",
|
||||
"PYI03",
|
||||
"PYI032",
|
||||
"PYI033",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue