feat(B032): add b032 flake8_bugbear (#3085)

This commit is contained in:
Carlos Gonçalves
2023-02-21 19:53:29 +00:00
committed by GitHub
parent d9fd78d907
commit 6eb014b3b2
9 changed files with 205 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
"""
Should emit:
B032 - on lines 9, 10, 12, 13, 16-19
"""
# Flag these
dct = {"a": 1}
dct["b"]: 2
dct.b: 2
dct["b"]: "test"
dct.b: "test"
test = "test"
dct["b"]: test
dct["b"]: test.lower()
dct.b: test
dct.b: test.lower()
# Do not flag below
typed_dct: dict[str, int] = {"a": 1}
typed_dct["b"] = 2
typed_dct.b = 2
class TestClass:
def test_self(self):
self.test: int

View File

@@ -1842,6 +1842,18 @@ where
pycodestyle::rules::lambda_assignment(self, target, value, stmt);
}
}
if self
.settings
.rules
.enabled(&Rule::UnintentionalTypeAnnotation)
{
flake8_bugbear::rules::unintentional_type_annotation(
self,
target,
value.as_deref(),
stmt,
);
}
}
StmtKind::Delete { .. } => {}
StmtKind::Expr { value, .. } => {

View File

@@ -180,6 +180,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
(Flake8Bugbear, "026") => Rule::StarArgUnpackingAfterKeywordArg,
(Flake8Bugbear, "027") => Rule::EmptyMethodWithoutAbstractDecorator,
(Flake8Bugbear, "029") => Rule::ExceptWithEmptyTuple,
(Flake8Bugbear, "032") => Rule::UnintentionalTypeAnnotation,
(Flake8Bugbear, "904") => Rule::RaiseWithoutFromInsideExcept,
(Flake8Bugbear, "905") => Rule::ZipWithoutExplicitStrict,

View File

@@ -183,6 +183,7 @@ ruff_macros::register_rules!(
rules::flake8_bugbear::rules::RaiseWithoutFromInsideExcept,
rules::flake8_bugbear::rules::ZipWithoutExplicitStrict,
rules::flake8_bugbear::rules::ExceptWithEmptyTuple,
rules::flake8_bugbear::rules::UnintentionalTypeAnnotation,
// flake8-blind-except
rules::flake8_blind_except::rules::BlindExcept,
// flake8-comprehensions

View File

@@ -42,6 +42,7 @@ mod tests {
#[test_case(Rule::EmptyMethodWithoutAbstractDecorator, Path::new("B027.py"); "B027")]
#[test_case(Rule::EmptyMethodWithoutAbstractDecorator, Path::new("B027.pyi"); "B027_pyi")]
#[test_case(Rule::ExceptWithEmptyTuple, Path::new("B029.py"); "B029")]
#[test_case(Rule::UnintentionalTypeAnnotation, Path::new("B032.py"); "B032")]
#[test_case(Rule::RaiseWithoutFromInsideExcept, Path::new("B904.py"); "B904")]
#[test_case(Rule::ZipWithoutExplicitStrict, Path::new("B905.py"); "B905")]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {

View File

@@ -41,6 +41,10 @@ pub use useless_contextlib_suppress::{useless_contextlib_suppress, UselessContex
pub use useless_expression::{useless_expression, UselessExpression};
pub use zip_without_explicit_strict::{zip_without_explicit_strict, ZipWithoutExplicitStrict};
pub use unintentional_type_annotation::{
unintentional_type_annotation, UnintentionalTypeAnnotation,
};
mod abstract_base_class;
mod assert_false;
mod assert_raises_exception;
@@ -62,6 +66,7 @@ mod setattr_with_constant;
mod star_arg_unpacking_after_keyword_arg;
mod strip_with_multi_characters;
mod unary_prefix_increment;
mod unintentional_type_annotation;
mod unreliable_callable_check;
mod unused_loop_control_variable;
mod useless_comparison;

View File

@@ -0,0 +1,69 @@
use rustpython_parser::ast::{Expr, ExprKind, Stmt};
use ruff_macros::{define_violation, derive_message_formats};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::Diagnostic;
use crate::violation::Violation;
define_violation!(
/// ## What it does
/// Checks for the unintentional use of type annotations.
///
/// ## Why is this bad?
/// The use of a colon (`:`) in lieu of an assignment (`=`) can be syntactically valid, but
/// is almost certainly a mistake when used in a subscript or attribute assignment.
///
/// ## Example
/// ```python
/// a["b"]: 1
/// ```
///
/// Use instead:
/// ```python
/// a["b"] = 1
/// ```
pub struct UnintentionalTypeAnnotation;
);
impl Violation for UnintentionalTypeAnnotation {
#[derive_message_formats]
fn message(&self) -> String {
format!(
"Possible unintentional type annotation (using `:`). Did you mean to assign (using `=`)?"
)
}
}
/// B032
pub fn unintentional_type_annotation(
checker: &mut Checker,
target: &Expr,
value: Option<&Expr>,
stmt: &Stmt,
) {
if value.is_some() {
return;
}
match &target.node {
ExprKind::Subscript { value, .. } => {
if matches!(&value.node, ExprKind::Name { .. }) {
checker.diagnostics.push(Diagnostic::new(
UnintentionalTypeAnnotation,
Range::from_located(stmt),
));
}
}
ExprKind::Attribute { value, .. } => {
if let ExprKind::Name { id, .. } = &value.node {
if id != "self" {
checker.diagnostics.push(Diagnostic::new(
UnintentionalTypeAnnotation,
Range::from_located(stmt),
));
}
}
}
_ => {}
};
}

View File

@@ -0,0 +1,85 @@
---
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
expression: diagnostics
---
- kind:
UnintentionalTypeAnnotation: ~
location:
row: 9
column: 0
end_location:
row: 9
column: 11
fix: ~
parent: ~
- kind:
UnintentionalTypeAnnotation: ~
location:
row: 10
column: 0
end_location:
row: 10
column: 8
fix: ~
parent: ~
- kind:
UnintentionalTypeAnnotation: ~
location:
row: 12
column: 0
end_location:
row: 12
column: 16
fix: ~
parent: ~
- kind:
UnintentionalTypeAnnotation: ~
location:
row: 13
column: 0
end_location:
row: 13
column: 13
fix: ~
parent: ~
- kind:
UnintentionalTypeAnnotation: ~
location:
row: 16
column: 0
end_location:
row: 16
column: 14
fix: ~
parent: ~
- kind:
UnintentionalTypeAnnotation: ~
location:
row: 17
column: 0
end_location:
row: 17
column: 22
fix: ~
parent: ~
- kind:
UnintentionalTypeAnnotation: ~
location:
row: 18
column: 0
end_location:
row: 18
column: 11
fix: ~
parent: ~
- kind:
UnintentionalTypeAnnotation: ~
location:
row: 19
column: 0
end_location:
row: 19
column: 19
fix: ~
parent: ~

2
ruff.schema.json generated
View File

@@ -1430,6 +1430,8 @@
"B026",
"B027",
"B029",
"B03",
"B032",
"B9",
"B90",
"B904",