mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-21 19:05:09 +00:00
[flake8-pyi
] Check for kwarg and vararg NoReturn
type annotations (#8948)
## Summary Triggers `no-return-argument-annotation-in-stub` (`PYI050`) for vararg and kwarg `NoReturn` type annotations. Related to #8771. ## Test Plan `cargo test`
This commit is contained in:
parent
506be68782
commit
d66063bb33
3 changed files with 105 additions and 12 deletions
|
@ -10,3 +10,14 @@ def foo_no_return_typing_extensions(
|
||||||
def foo_no_return_kwarg(arg: int, *, arg2: 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_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050
|
||||||
def foo_never(arg: Never): ...
|
def foo_never(arg: Never): ...
|
||||||
|
def foo_args(*args: NoReturn): ... # Error: PYI050
|
||||||
|
def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
def foo_int_args(*args: int): ...
|
||||||
|
def foo_int_kwargs(**kwargs: int): ...
|
||||||
|
def foo_int_args_kwargs(*args: int, **kwargs: int): ...
|
||||||
|
def foo_int_args_no_return(*args: int, **kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
def foo_int_kwargs_no_return(*args: NoReturn, **kwargs: int): ... # Error: PYI050
|
||||||
|
def foo_args_never(*args: Never): ...
|
||||||
|
def foo_kwargs_never(**kwargs: Never): ...
|
||||||
|
def foo_args_kwargs_never(*args: Never, **kwargs: Never): ...
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::Parameters;
|
use ruff_python_ast::{Expr, Parameters};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
@ -51,6 +51,9 @@ impl Violation for NoReturnArgumentAnnotationInStub {
|
||||||
|
|
||||||
/// PYI050
|
/// PYI050
|
||||||
pub(crate) fn no_return_argument_annotation(checker: &mut Checker, parameters: &Parameters) {
|
pub(crate) fn no_return_argument_annotation(checker: &mut Checker, parameters: &Parameters) {
|
||||||
|
// Ex) def func(arg: NoReturn): ...
|
||||||
|
// Ex) def func(arg: NoReturn, /): ...
|
||||||
|
// Ex) def func(*, arg: NoReturn): ...
|
||||||
for annotation in parameters
|
for annotation in parameters
|
||||||
.posonlyargs
|
.posonlyargs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -58,6 +61,25 @@ pub(crate) fn no_return_argument_annotation(checker: &mut Checker, parameters: &
|
||||||
.chain(¶meters.kwonlyargs)
|
.chain(¶meters.kwonlyargs)
|
||||||
.filter_map(|arg| arg.parameter.annotation.as_ref())
|
.filter_map(|arg| arg.parameter.annotation.as_ref())
|
||||||
{
|
{
|
||||||
|
check_no_return_argument_annotation(checker, annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ex) def func(*args: NoReturn): ...
|
||||||
|
if let Some(arg) = ¶meters.vararg {
|
||||||
|
if let Some(annotation) = &arg.annotation {
|
||||||
|
check_no_return_argument_annotation(checker, annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ex) def func(**kwargs: NoReturn): ...
|
||||||
|
if let Some(arg) = ¶meters.kwarg {
|
||||||
|
if let Some(annotation) = &arg.annotation {
|
||||||
|
check_no_return_argument_annotation(checker, annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_no_return_argument_annotation(checker: &mut Checker, annotation: &Expr) {
|
||||||
if checker.semantic().match_typing_expr(annotation, "NoReturn") {
|
if checker.semantic().match_typing_expr(annotation, "NoReturn") {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
NoReturnArgumentAnnotationInStub {
|
NoReturnArgumentAnnotationInStub {
|
||||||
|
@ -70,7 +92,6 @@ pub(crate) fn no_return_argument_annotation(checker: &mut Checker, parameters: &
|
||||||
annotation.range(),
|
annotation.range(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
|
|
@ -28,6 +28,67 @@ PYI050.pyi:11:47: PYI050 Prefer `typing.Never` over `NoReturn` for argument anno
|
||||||
11 | def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050
|
11 | def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050
|
||||||
| ^^^^^^^^ PYI050
|
| ^^^^^^^^ PYI050
|
||||||
12 | def foo_never(arg: Never): ...
|
12 | def foo_never(arg: Never): ...
|
||||||
|
13 | def foo_args(*args: NoReturn): ... # Error: PYI050
|
||||||
|
|
|
||||||
|
|
||||||
|
PYI050.pyi:13:21: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations
|
||||||
|
|
|
||||||
|
11 | def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050
|
||||||
|
12 | def foo_never(arg: Never): ...
|
||||||
|
13 | def foo_args(*args: NoReturn): ... # Error: PYI050
|
||||||
|
| ^^^^^^^^ PYI050
|
||||||
|
14 | def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
15 | def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
|
|
||||||
|
|
||||||
|
PYI050.pyi:14:26: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations
|
||||||
|
|
|
||||||
|
12 | def foo_never(arg: Never): ...
|
||||||
|
13 | def foo_args(*args: NoReturn): ... # Error: PYI050
|
||||||
|
14 | def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
| ^^^^^^^^ PYI050
|
||||||
|
15 | def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
16 | def foo_int_args(*args: int): ...
|
||||||
|
|
|
||||||
|
|
||||||
|
PYI050.pyi:15:28: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations
|
||||||
|
|
|
||||||
|
13 | def foo_args(*args: NoReturn): ... # Error: PYI050
|
||||||
|
14 | def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
15 | def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
| ^^^^^^^^ PYI050
|
||||||
|
16 | def foo_int_args(*args: int): ...
|
||||||
|
17 | def foo_int_kwargs(**kwargs: int): ...
|
||||||
|
|
|
||||||
|
|
||||||
|
PYI050.pyi:15:48: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations
|
||||||
|
|
|
||||||
|
13 | def foo_args(*args: NoReturn): ... # Error: PYI050
|
||||||
|
14 | def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
15 | def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
| ^^^^^^^^ PYI050
|
||||||
|
16 | def foo_int_args(*args: int): ...
|
||||||
|
17 | def foo_int_kwargs(**kwargs: int): ...
|
||||||
|
|
|
||||||
|
|
||||||
|
PYI050.pyi:19:50: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations
|
||||||
|
|
|
||||||
|
17 | def foo_int_kwargs(**kwargs: int): ...
|
||||||
|
18 | def foo_int_args_kwargs(*args: int, **kwargs: int): ...
|
||||||
|
19 | def foo_int_args_no_return(*args: int, **kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
| ^^^^^^^^ PYI050
|
||||||
|
20 | def foo_int_kwargs_no_return(*args: NoReturn, **kwargs: int): ... # Error: PYI050
|
||||||
|
21 | def foo_args_never(*args: Never): ...
|
||||||
|
|
|
||||||
|
|
||||||
|
PYI050.pyi:20:37: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations
|
||||||
|
|
|
||||||
|
18 | def foo_int_args_kwargs(*args: int, **kwargs: int): ...
|
||||||
|
19 | def foo_int_args_no_return(*args: int, **kwargs: NoReturn): ... # Error: PYI050
|
||||||
|
20 | def foo_int_kwargs_no_return(*args: NoReturn, **kwargs: int): ... # Error: PYI050
|
||||||
|
| ^^^^^^^^ PYI050
|
||||||
|
21 | def foo_args_never(*args: Never): ...
|
||||||
|
22 | def foo_kwargs_never(**kwargs: Never): ...
|
||||||
|
|
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue