-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[
flake8-pyi
] Implement PYI050 (#4884)
- Loading branch information
Showing
10 changed files
with
182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from typing import NoReturn, Never | ||
import typing_extensions | ||
|
||
|
||
def foo(arg): | ||
... | ||
|
||
|
||
def foo_int(arg: int): | ||
... | ||
|
||
|
||
def foo_no_return(arg: NoReturn): | ||
... | ||
|
||
|
||
def foo_no_return_typing_extensions( | ||
arg: typing_extensions.NoReturn, | ||
): | ||
... | ||
|
||
|
||
def foo_no_return_kwarg(arg: int, *, arg2: NoReturn): | ||
... | ||
|
||
|
||
def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): | ||
... | ||
|
||
|
||
def foo_never(arg: Never): | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from typing import NoReturn, Never | ||
import typing_extensions | ||
|
||
def foo(arg): ... | ||
def foo_int(arg: int): ... | ||
def foo_no_return(arg: NoReturn): ... # Error: PYI050 | ||
def foo_no_return_typing_extensions( | ||
arg: typing_extensions.NoReturn, | ||
): ... # Error: PYI050 | ||
def foo_no_return_kwarg(arg: int, *, arg2: NoReturn): ... # Error: PYI050 | ||
def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050 | ||
def foo_never(arg: Never): ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
crates/ruff/src/rules/flake8_pyi/rules/no_return_argument_annotation.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
use std::fmt; | ||
|
||
use itertools::chain; | ||
use rustpython_parser::ast::Ranged; | ||
|
||
use ruff_diagnostics::{Diagnostic, Violation}; | ||
use ruff_macros::{derive_message_formats, violation}; | ||
use ruff_python_ast::prelude::Arguments; | ||
|
||
use crate::checkers::ast::Checker; | ||
use crate::settings::types::PythonVersion::Py311; | ||
|
||
#[violation] | ||
pub struct NoReturnArgumentAnnotationInStub { | ||
module: TypingModule, | ||
} | ||
|
||
/// ## What it does | ||
/// Checks for uses of `typing.NoReturn` (and `typing_extensions.NoReturn`) in | ||
/// stubs. | ||
/// | ||
/// ## Why is this bad? | ||
/// Prefer `typing.Never` (or `typing_extensions.Never`) over `typing.NoReturn`, | ||
/// as the former is more explicit about the intent of the annotation. This is | ||
/// a purely stylistic choice, as the two are semantically equivalent. | ||
/// | ||
/// ## Example | ||
/// ```python | ||
/// from typing import NoReturn | ||
/// | ||
/// | ||
/// def foo(x: NoReturn): ... | ||
/// ``` | ||
/// | ||
/// Use instead: | ||
/// ```python | ||
/// from typing import Never | ||
/// | ||
/// | ||
/// def foo(x: Never): ... | ||
/// ``` | ||
impl Violation for NoReturnArgumentAnnotationInStub { | ||
#[derive_message_formats] | ||
fn message(&self) -> String { | ||
let NoReturnArgumentAnnotationInStub { module } = self; | ||
format!("Prefer `{module}.Never` over `NoReturn` for argument annotations") | ||
} | ||
} | ||
|
||
/// PYI050 | ||
pub(crate) fn no_return_argument_annotation(checker: &mut Checker, args: &Arguments) { | ||
for annotation in chain!( | ||
args.args.iter(), | ||
args.posonlyargs.iter(), | ||
args.kwonlyargs.iter() | ||
) | ||
.filter_map(|arg| arg.annotation.as_ref()) | ||
{ | ||
if checker | ||
.semantic_model() | ||
.match_typing_expr(annotation, "NoReturn") | ||
{ | ||
checker.diagnostics.push(Diagnostic::new( | ||
NoReturnArgumentAnnotationInStub { | ||
module: if checker.settings.target_version >= Py311 { | ||
TypingModule::Typing | ||
} else { | ||
TypingModule::TypingExtensions | ||
}, | ||
}, | ||
annotation.range(), | ||
)); | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq)] | ||
enum TypingModule { | ||
Typing, | ||
TypingExtensions, | ||
} | ||
|
||
impl fmt::Display for TypingModule { | ||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
match self { | ||
TypingModule::Typing => fmt.write_str("typing"), | ||
TypingModule::TypingExtensions => fmt.write_str("typing_extensions"), | ||
} | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
...ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI050_PYI050.py.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
source: crates/ruff/src/rules/flake8_pyi/mod.rs | ||
--- | ||
|
33 changes: 33 additions & 0 deletions
33
...uff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI050_PYI050.pyi.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
--- | ||
source: crates/ruff/src/rules/flake8_pyi/mod.rs | ||
--- | ||
PYI050.pyi:6:24: PYI050 Prefer `typing_extensions.Never` over `NoReturn` for argument annotations | ||
| | ||
6 | def foo(arg): ... | ||
7 | def foo_int(arg: int): ... | ||
8 | def foo_no_return(arg: NoReturn): ... # Error: PYI050 | ||
| ^^^^^^^^ PYI050 | ||
9 | def foo_no_return_typing_extensions( | ||
10 | arg: typing_extensions.NoReturn, | ||
| | ||
|
||
PYI050.pyi:10:44: PYI050 Prefer `typing_extensions.Never` over `NoReturn` for argument annotations | ||
| | ||
10 | arg: typing_extensions.NoReturn, | ||
11 | ): ... # Error: PYI050 | ||
12 | def foo_no_return_kwarg(arg: int, *, arg2: NoReturn): ... # Error: PYI050 | ||
| ^^^^^^^^ PYI050 | ||
13 | def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050 | ||
14 | def foo_never(arg: Never): ... | ||
| | ||
|
||
PYI050.pyi:11:47: PYI050 Prefer `typing_extensions.Never` over `NoReturn` for argument annotations | ||
| | ||
11 | ): ... # Error: PYI050 | ||
12 | def foo_no_return_kwarg(arg: int, *, arg2: NoReturn): ... # Error: PYI050 | ||
13 | def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050 | ||
| ^^^^^^^^ PYI050 | ||
14 | def foo_never(arg: Never): ... | ||
| | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.