Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement PYI047 #6134

Merged
merged 12 commits into from
Jul 29, 2023
12 changes: 12 additions & 0 deletions crates/ruff/resources/test/fixtures/flake8_pyi/PYI047.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import typing
from typing import TypeAlias


_UnusedPrivateTypeAlias: TypeAlias = int | None
_T: typing.TypeAlias = str

# OK
_UsedPrivateTypeAlias: TypeAlias = int | None

def func(arg: _UsedPrivateTypeAlias) -> _UsedPrivateTypeAlias:
...
12 changes: 12 additions & 0 deletions crates/ruff/resources/test/fixtures/flake8_pyi/PYI047.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import typing
from typing import TypeAlias


_UnusedPrivateTypeAlias: TypeAlias = int | None
_T: typing.TypeAlias = str

# OK
_UsedPrivateTypeAlias: TypeAlias = int | None

def func(arg: _UsedPrivateTypeAlias) -> _UsedPrivateTypeAlias:
...
8 changes: 8 additions & 0 deletions crates/ruff/src/checkers/ast/analyze/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub(crate) fn bindings(checker: &mut Checker) {
Rule::UnusedPrivateTypeVar,
Rule::UnusedVariable,
Rule::UnusedPrivateProtocol,
Rule::UnusedPrivateTypeAlias,
]) {
return;
}
Expand Down Expand Up @@ -79,6 +80,13 @@ pub(crate) fn bindings(checker: &mut Checker) {
checker.diagnostics.push(diagnostic);
}
}
if checker.enabled(Rule::UnusedPrivateTypeAlias) {
if let Some(diagnostic) =
flake8_pyi::rules::unused_private_type_alias(checker, binding)
{
checker.diagnostics.push(diagnostic);
}
}
}
}
}
1 change: 1 addition & 0 deletions crates/ruff/src/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Pyi, "044") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::FutureAnnotationsInStub),
(Flake8Pyi, "045") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::IterMethodReturnIterable),
(Flake8Pyi, "046") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::UnusedPrivateProtocol),
(Flake8Pyi, "047") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::UnusedPrivateTypeAlias),
(Flake8Pyi, "048") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::StubBodyMultipleStatements),
(Flake8Pyi, "050") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::NoReturnArgumentAnnotationInStub),
(Flake8Pyi, "052") => (RuleGroup::Unspecified, rules::flake8_pyi::rules::UnannotatedAssignmentInStub),
Expand Down
2 changes: 2 additions & 0 deletions crates/ruff/src/rules/flake8_pyi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ mod tests {
#[test_case(Rule::UnusedPrivateTypeVar, Path::new("PYI018.pyi"))]
#[test_case(Rule::UnusedPrivateProtocol, Path::new("PYI046.py"))]
#[test_case(Rule::UnusedPrivateProtocol, Path::new("PYI046.pyi"))]
#[test_case(Rule::UnusedPrivateTypeAlias, Path::new("PYI047.py"))]
#[test_case(Rule::UnusedPrivateTypeAlias, Path::new("PYI047.pyi"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,44 @@ impl Violation for UnusedPrivateProtocol {
}
}

/// ## What it does
/// Checks for the presence of unused private `typing.TypeAlias` definitions.
///
/// ## Why is this bad?
/// A private `typing.TypeAlias` that is defined but not used is likely a
/// mistake, and should either be used, made public, or removed to avoid
/// confusion.
///
/// ## Example
/// ```python
/// import typing
///
/// _UnusedTypeAlias: typing.TypeAlias = int
/// ```
///
/// Use instead:
/// ```python
/// import typing
///
/// _UsedTypeAlias: typing.TypeAlias = int
///
///
/// def func(arg: _UsedTypeAlias) -> _UsedTypeAlias:
/// ...
/// ```
#[violation]
pub struct UnusedPrivateTypeAlias {
name: String,
}

impl Violation for UnusedPrivateTypeAlias {
#[derive_message_formats]
fn message(&self) -> String {
let UnusedPrivateTypeAlias { name } = self;
format!("Private TypeAlias `{name}` is never used")
}
}

/// PYI018
pub(crate) fn unused_private_type_var(checker: &Checker, binding: &Binding) -> Option<Diagnostic> {
if !(binding.kind.is_assignment() && binding.is_private_declaration()) {
Expand Down Expand Up @@ -138,3 +176,41 @@ pub(crate) fn unused_private_protocol(checker: &Checker, binding: &Binding) -> O
binding.range,
))
}

/// PYI047
pub(crate) fn unused_private_type_alias(
checker: &Checker,
binding: &Binding,
) -> Option<Diagnostic> {
if !(binding.kind.is_assignment() && binding.is_private_declaration()) {
return None;
}
if binding.is_used() {
return None;
}

let Some(source) = binding.source else {
return None;
};
let Stmt::AnnAssign(ast::StmtAnnAssign { target, annotation, .. }) = checker.semantic().stmts[source]
else {
return None
};
let Some(ast::ExprName { id, .. }) = target.as_name_expr() else {
return None;
};

if !checker
.semantic()
.match_typing_expr(annotation, "TypeAlias")
{
return None;
}

Some(Diagnostic::new(
UnusedPrivateTypeAlias {
name: id.to_string(),
},
binding.range,
))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
source: crates/ruff/src/rules/flake8_pyi/mod.rs
---

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
source: crates/ruff/src/rules/flake8_pyi/mod.rs
---
PYI047.pyi:5:1: PYI047 Private TypeAlias `_UnusedPrivateTypeAlias` is never used
|
5 | _UnusedPrivateTypeAlias: TypeAlias = int | None
| ^^^^^^^^^^^^^^^^^^^^^^^ PYI047
6 | _T: typing.TypeAlias = str
|

PYI047.pyi:6:1: PYI047 Private TypeAlias `_T` is never used
|
5 | _UnusedPrivateTypeAlias: TypeAlias = int | None
6 | _T: typing.TypeAlias = str
| ^^ PYI047
7 |
8 | # OK
|


1 change: 1 addition & 0 deletions ruff.schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading