refactor: move violations to linters (#2234)

This commit is contained in:
Simon Brugman 2023-01-26 23:28:14 +01:00 committed by GitHub
parent 8766e6a666
commit 9d3a5530af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 275 additions and 289 deletions

View file

@ -318,10 +318,10 @@ ruff_macros::define_rule_mapping!(
N817 => violations::CamelcaseImportedAsAcronym,
N818 => violations::ErrorSuffixOnExceptionName,
// isort
I001 => violations::UnsortedImports,
I002 => violations::MissingRequiredImport,
I001 => rules::isort::rules::UnsortedImports,
I002 => rules::isort::rules::MissingRequiredImport,
// eradicate
ERA001 => violations::CommentedOutCode,
ERA001 => rules::eradicate::rules::CommentedOutCode,
// flake8-bandit
S101 => violations::AssertUsed,
S102 => violations::ExecUsed,
@ -340,9 +340,9 @@ ruff_macros::define_rule_mapping!(
S612 => rules::flake8_bandit::rules::LoggingConfigInsecureListen,
S701 => violations::Jinja2AutoescapeFalse,
// flake8-boolean-trap
FBT001 => violations::BooleanPositionalArgInFunctionDefinition,
FBT002 => violations::BooleanDefaultValueInFunctionDefinition,
FBT003 => violations::BooleanPositionalValueInFunctionCall,
FBT001 => rules::flake8_boolean_trap::rules::BooleanPositionalArgInFunctionDefinition,
FBT002 => rules::flake8_boolean_trap::rules::BooleanDefaultValueInFunctionDefinition,
FBT003 => rules::flake8_boolean_trap::rules::BooleanPositionalValueInFunctionCall,
// flake8-unused-arguments
ARG001 => violations::UnusedFunctionArgument,
ARG002 => violations::UnusedMethodArgument,
@ -350,7 +350,7 @@ ruff_macros::define_rule_mapping!(
ARG004 => violations::UnusedStaticMethodArgument,
ARG005 => violations::UnusedLambdaArgument,
// flake8-import-conventions
ICN001 => violations::ImportAliasIsNotConventional,
ICN001 => rules::flake8_import_conventions::rules::ImportAliasIsNotConventional,
// flake8-datetimez
DTZ001 => violations::CallDatetimeWithoutTzinfo,
DTZ002 => violations::CallDatetimeToday,
@ -410,18 +410,18 @@ ruff_macros::define_rule_mapping!(
PT025 => violations::ErroneousUseFixturesOnFixture,
PT026 => violations::UseFixturesWithoutParameters,
// flake8-pie
PIE790 => violations::NoUnnecessaryPass,
PIE794 => violations::DupeClassFieldDefinitions,
PIE796 => violations::PreferUniqueEnums,
PIE800 => violations::NoUnnecessarySpread,
PIE804 => violations::NoUnnecessaryDictKwargs,
PIE807 => violations::PreferListBuiltin,
PIE790 => rules::flake8_pie::rules::NoUnnecessaryPass,
PIE794 => rules::flake8_pie::rules::DupeClassFieldDefinitions,
PIE796 => rules::flake8_pie::rules::PreferUniqueEnums,
PIE800 => rules::flake8_pie::rules::NoUnnecessarySpread,
PIE804 => rules::flake8_pie::rules::NoUnnecessaryDictKwargs,
PIE807 => rules::flake8_pie::rules::PreferListBuiltin,
// flake8-commas
COM812 => violations::TrailingCommaMissing,
COM818 => violations::TrailingCommaOnBareTupleProhibited,
COM819 => violations::TrailingCommaProhibited,
COM812 => rules::flake8_commas::rules::TrailingCommaMissing,
COM818 => rules::flake8_commas::rules::TrailingCommaOnBareTupleProhibited,
COM819 => rules::flake8_commas::rules::TrailingCommaProhibited,
// flake8-no-pep420
INP001 => violations::ImplicitNamespacePackage,
INP001 => rules::flake8_no_pep420::rules::ImplicitNamespacePackage,
// flake8-executable
EXE001 => rules::flake8_executable::rules::ShebangNotExecutable,
EXE002 => rules::flake8_executable::rules::ShebangMissingExecutableFile,

View file

@ -1,12 +1,28 @@
use ruff_macros::derive_message_formats;
use rustpython_ast::Location;
use super::detection::comment_contains_code;
use crate::ast::types::Range;
use crate::define_violation;
use crate::fix::Fix;
use crate::registry::{Diagnostic, Rule};
use crate::settings::{flags, Settings};
use crate::source_code::Locator;
use crate::violations;
use crate::violation::AlwaysAutofixableViolation;
define_violation!(
pub struct CommentedOutCode;
);
impl AlwaysAutofixableViolation for CommentedOutCode {
#[derive_message_formats]
fn message(&self) -> String {
format!("Found commented-out code")
}
fn autofix_title(&self) -> String {
"Remove commented-out code".to_string()
}
}
fn is_standalone_comment(line: &str) -> bool {
for char in line.chars() {
@ -33,7 +49,7 @@ pub fn commented_out_code(
// Verify that the comment is on its own line, and that it contains code.
if is_standalone_comment(line) && comment_contains_code(line, &settings.task_tags[..]) {
let mut diagnostic = Diagnostic::new(violations::CommentedOutCode, Range::new(start, end));
let mut diagnostic = Diagnostic::new(CommentedOutCode, Range::new(start, end));
if matches!(autofix, flags::Autofix::Enabled)
&& settings.rules.should_fix(&Rule::CommentedOutCode)
{

View file

@ -1,10 +1,42 @@
use ruff_macros::derive_message_formats;
use rustpython_ast::{Arguments, ExprKind};
use rustpython_parser::ast::{Constant, Expr};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::define_violation;
use crate::registry::{Diagnostic, DiagnosticKind};
use crate::violations;
use crate::violation::Violation;
define_violation!(
pub struct BooleanPositionalArgInFunctionDefinition;
);
impl Violation for BooleanPositionalArgInFunctionDefinition {
#[derive_message_formats]
fn message(&self) -> String {
format!("Boolean positional arg in function definition")
}
}
define_violation!(
pub struct BooleanDefaultValueInFunctionDefinition;
);
impl Violation for BooleanDefaultValueInFunctionDefinition {
#[derive_message_formats]
fn message(&self) -> String {
format!("Boolean default value in function definition")
}
}
define_violation!(
pub struct BooleanPositionalValueInFunctionCall;
);
impl Violation for BooleanPositionalValueInFunctionCall {
#[derive_message_formats]
fn message(&self) -> String {
format!("Boolean positional value in function call")
}
}
const FUNC_NAME_ALLOWLIST: &[&str] = &[
"assertEqual",
@ -77,7 +109,7 @@ pub fn check_positional_boolean_in_def(checker: &mut Checker, arguments: &Argume
continue;
}
checker.diagnostics.push(Diagnostic::new(
violations::BooleanPositionalArgInFunctionDefinition,
BooleanPositionalArgInFunctionDefinition,
Range::from_located(arg),
));
}
@ -88,11 +120,7 @@ pub fn check_boolean_default_value_in_function_definition(
arguments: &Arguments,
) {
for arg in &arguments.defaults {
add_if_boolean(
checker,
arg,
violations::BooleanDefaultValueInFunctionDefinition.into(),
);
add_if_boolean(checker, arg, BooleanDefaultValueInFunctionDefinition.into());
}
}
@ -105,10 +133,6 @@ pub fn check_boolean_positional_value_in_function_call(
if allow_boolean_trap(func) {
continue;
}
add_if_boolean(
checker,
arg,
violations::BooleanPositionalValueInFunctionCall.into(),
);
add_if_boolean(checker, arg, BooleanPositionalValueInFunctionCall.into());
}
}

View file

@ -1,12 +1,14 @@
use itertools::Itertools;
use ruff_macros::derive_message_formats;
use rustpython_parser::lexer::{LexResult, Spanned};
use rustpython_parser::token::Tok;
use crate::ast::types::Range;
use crate::define_violation;
use crate::fix::Fix;
use crate::registry::{Diagnostic, Rule};
use crate::settings::{flags, Settings};
use crate::violations;
use crate::violation::{AlwaysAutofixableViolation, Violation};
/// Simplified token type.
#[derive(Copy, Clone, PartialEq, Eq)]
@ -107,6 +109,44 @@ impl Context {
}
}
define_violation!(
pub struct TrailingCommaMissing;
);
impl AlwaysAutofixableViolation for TrailingCommaMissing {
#[derive_message_formats]
fn message(&self) -> String {
format!("Trailing comma missing")
}
fn autofix_title(&self) -> String {
"Add trailing comma".to_string()
}
}
define_violation!(
pub struct TrailingCommaOnBareTupleProhibited;
);
impl Violation for TrailingCommaOnBareTupleProhibited {
#[derive_message_formats]
fn message(&self) -> String {
format!("Trailing comma on bare tuple prohibited")
}
}
define_violation!(
pub struct TrailingCommaProhibited;
);
impl AlwaysAutofixableViolation for TrailingCommaProhibited {
#[derive_message_formats]
fn message(&self) -> String {
format!("Trailing comma prohibited")
}
fn autofix_title(&self) -> String {
"Remove trailing comma".to_string()
}
}
/// COM812, COM818, COM819
pub fn trailing_commas(
tokens: &[LexResult],
@ -212,7 +252,7 @@ pub fn trailing_commas(
if comma_prohibited {
let comma = prev.spanned.unwrap();
let mut diagnostic = Diagnostic::new(
violations::TrailingCommaProhibited,
TrailingCommaProhibited,
Range {
location: comma.0,
end_location: comma.2,
@ -233,7 +273,7 @@ pub fn trailing_commas(
if bare_comma_prohibited {
let comma = prev.spanned.unwrap();
diagnostics.push(Diagnostic::new(
violations::TrailingCommaOnBareTupleProhibited,
TrailingCommaOnBareTupleProhibited,
Range {
location: comma.0,
end_location: comma.2,
@ -258,7 +298,7 @@ pub fn trailing_commas(
if comma_required {
let missing_comma = prev_prev.spanned.unwrap();
let mut diagnostic = Diagnostic::new(
violations::TrailingCommaMissing,
TrailingCommaMissing,
Range {
location: missing_comma.2,
end_location: missing_comma.2,

View file

@ -1,9 +1,22 @@
use ruff_macros::derive_message_formats;
use rustc_hash::FxHashMap;
use rustpython_ast::Stmt;
use crate::ast::types::Range;
use crate::define_violation;
use crate::registry::Diagnostic;
use crate::violations;
use crate::violation::Violation;
define_violation!(
pub struct ImportAliasIsNotConventional(pub String, pub String);
);
impl Violation for ImportAliasIsNotConventional {
#[derive_message_formats]
fn message(&self) -> String {
let ImportAliasIsNotConventional(name, asname) = self;
format!("`{name}` should be imported as `{asname}`")
}
}
/// ICN001
pub fn check_conventional_import(
@ -25,10 +38,7 @@ pub fn check_conventional_import(
}
if !is_valid_import {
return Some(Diagnostic::new(
violations::ImportAliasIsNotConventional(
name.to_string(),
expected_alias.to_string(),
),
ImportAliasIsNotConventional(name.to_string(), expected_alias.to_string()),
Range::from_located(import_from),
));
}

View file

@ -1,14 +1,28 @@
use std::path::Path;
use ruff_macros::derive_message_formats;
use crate::ast::types::Range;
use crate::registry::Diagnostic;
use crate::{fs, violations};
use crate::violation::Violation;
use crate::{define_violation, fs};
define_violation!(
pub struct ImplicitNamespacePackage(pub String);
);
impl Violation for ImplicitNamespacePackage {
#[derive_message_formats]
fn message(&self) -> String {
let ImplicitNamespacePackage(filename) = self;
format!("File `{filename}` is part of an implicit namespace package. Add an `__init__.py`.")
}
}
/// INP001
pub fn implicit_namespace_package(path: &Path, package: Option<&Path>) -> Option<Diagnostic> {
if package.is_none() {
Some(Diagnostic::new(
violations::ImplicitNamespacePackage(fs::relativize_path(path)),
ImplicitNamespacePackage(fs::relativize_path(path)),
Range::default(),
))
} else {

View file

@ -1,4 +1,5 @@
use log::error;
use ruff_macros::derive_message_formats;
use rustc_hash::FxHashSet;
use rustpython_ast::{Constant, Expr, ExprKind, Keyword, Stmt, StmtKind};
@ -7,10 +8,88 @@ use crate::ast::helpers::unparse_expr;
use crate::ast::types::{Range, RefEquality};
use crate::autofix::helpers::delete_stmt;
use crate::checkers::ast::Checker;
use crate::define_violation;
use crate::fix::Fix;
use crate::python::identifiers::is_identifier;
use crate::registry::{Diagnostic, Rule};
use crate::violations;
use crate::violation::{AlwaysAutofixableViolation, Violation};
define_violation!(
pub struct NoUnnecessaryPass;
);
impl AlwaysAutofixableViolation for NoUnnecessaryPass {
#[derive_message_formats]
fn message(&self) -> String {
format!("Unnecessary `pass` statement")
}
fn autofix_title(&self) -> String {
"Remove unnecessary `pass`".to_string()
}
}
define_violation!(
pub struct DupeClassFieldDefinitions(pub String);
);
impl AlwaysAutofixableViolation for DupeClassFieldDefinitions {
#[derive_message_formats]
fn message(&self) -> String {
let DupeClassFieldDefinitions(name) = self;
format!("Class field `{name}` is defined multiple times")
}
fn autofix_title(&self) -> String {
let DupeClassFieldDefinitions(name) = self;
format!("Remove duplicate field definition for `{name}`")
}
}
define_violation!(
pub struct PreferUniqueEnums {
pub value: String,
}
);
impl Violation for PreferUniqueEnums {
#[derive_message_formats]
fn message(&self) -> String {
let PreferUniqueEnums { value } = self;
format!("Enum contains duplicate value: `{value}`")
}
}
define_violation!(
pub struct NoUnnecessarySpread;
);
impl Violation for NoUnnecessarySpread {
#[derive_message_formats]
fn message(&self) -> String {
format!("Unnecessary spread `**`")
}
}
define_violation!(
pub struct NoUnnecessaryDictKwargs;
);
impl Violation for NoUnnecessaryDictKwargs {
#[derive_message_formats]
fn message(&self) -> String {
format!("Unnecessary `dict` kwargs")
}
}
define_violation!(
pub struct PreferListBuiltin;
);
impl AlwaysAutofixableViolation for PreferListBuiltin {
#[derive_message_formats]
fn message(&self) -> String {
format!("Prefer `list` over useless lambda")
}
fn autofix_title(&self) -> String {
"Replace with `list`".to_string()
}
}
/// PIE790
pub fn no_unnecessary_pass(checker: &mut Checker, body: &[Stmt]) {
@ -30,10 +109,8 @@ pub fn no_unnecessary_pass(checker: &mut Checker, body: &[Stmt]) {
}
) {
if matches!(pass_stmt.node, StmtKind::Pass) {
let mut diagnostic = Diagnostic::new(
violations::NoUnnecessaryPass,
Range::from_located(pass_stmt),
);
let mut diagnostic =
Diagnostic::new(NoUnnecessaryPass, Range::from_located(pass_stmt));
if checker.patch(&Rule::NoUnnecessaryPass) {
match delete_stmt(
pass_stmt,
@ -91,7 +168,7 @@ pub fn dupe_class_field_definitions<'a, 'b>(
if !seen_targets.insert(target) {
let mut diagnostic = Diagnostic::new(
violations::DupeClassFieldDefinitions(target.to_string()),
DupeClassFieldDefinitions(target.to_string()),
Range::from_located(stmt),
);
if checker.patch(&Rule::DupeClassFieldDefinitions) {
@ -157,7 +234,7 @@ where
if !seen_targets.insert(ComparableExpr::from(value)) {
let diagnostic = Diagnostic::new(
violations::PreferUniqueEnums {
PreferUniqueEnums {
value: unparse_expr(value, checker.stylist),
},
Range::from_located(stmt),
@ -174,8 +251,7 @@ pub fn no_unnecessary_spread(checker: &mut Checker, keys: &[Option<Expr>], value
// We only care about when the key is None which indicates a spread `**`
// inside a dict.
if let ExprKind::Dict { .. } = value.node {
let diagnostic =
Diagnostic::new(violations::NoUnnecessarySpread, Range::from_located(value));
let diagnostic = Diagnostic::new(NoUnnecessarySpread, Range::from_located(value));
checker.diagnostics.push(diagnostic);
}
}
@ -206,10 +282,8 @@ pub fn no_unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs: &[
// handle case of foo(**{**bar})
(keys.len() == 1 && keys[0].is_none())
{
let diagnostic = Diagnostic::new(
violations::NoUnnecessaryDictKwargs,
Range::from_located(expr),
);
let diagnostic =
Diagnostic::new(NoUnnecessaryDictKwargs, Range::from_located(expr));
checker.diagnostics.push(diagnostic);
}
}
@ -225,8 +299,7 @@ pub fn prefer_list_builtin(checker: &mut Checker, expr: &Expr) {
if args.args.is_empty() {
if let ExprKind::List { elts, .. } = &body.node {
if elts.is_empty() {
let mut diagnostic =
Diagnostic::new(violations::PreferListBuiltin, Range::from_located(expr));
let mut diagnostic = Diagnostic::new(PreferListBuiltin, Range::from_located(expr));
if checker.patch(&Rule::PreferListBuiltin) {
diagnostic.amend(Fix::replacement(
"list".to_string(),

View file

@ -1,17 +1,35 @@
use std::fmt;
use log::error;
use ruff_macros::derive_message_formats;
use rustpython_ast::{Location, StmtKind, Suite};
use super::super::helpers;
use super::super::track::Block;
use crate::ast::helpers::is_docstring_stmt;
use crate::ast::types::Range;
use crate::define_violation;
use crate::fix::Fix;
use crate::registry::{Diagnostic, Rule};
use crate::settings::{flags, Settings};
use crate::source_code::{Locator, Stylist};
use crate::violations;
use crate::violation::AlwaysAutofixableViolation;
define_violation!(
pub struct MissingRequiredImport(pub String);
);
impl AlwaysAutofixableViolation for MissingRequiredImport {
#[derive_message_formats]
fn message(&self) -> String {
let MissingRequiredImport(name) = self;
format!("Missing required import: `{name}`")
}
fn autofix_title(&self) -> String {
let MissingRequiredImport(name) = self;
format!("Insert required import: `{name}`")
}
}
struct Alias<'a> {
name: &'a str,
@ -123,7 +141,7 @@ fn add_required_import(
// Always insert the diagnostic at top-of-file.
let required_import = required_import.to_string();
let mut diagnostic = Diagnostic::new(
violations::MissingRequiredImport(required_import.clone()),
MissingRequiredImport(required_import.clone()),
Range::new(Location::default(), Location::default()),
);
if matches!(autofix, flags::Autofix::Enabled)

View file

@ -1,5 +1,5 @@
pub use add_required_imports::add_required_imports;
pub use organize_imports::organize_imports;
pub use add_required_imports::{add_required_imports, MissingRequiredImport};
pub use organize_imports::{organize_imports, UnsortedImports};
pub mod add_required_imports;
pub mod organize_imports;

View file

@ -1,5 +1,6 @@
use std::path::Path;
use ruff_macros::derive_message_formats;
use rustpython_ast::{Location, Stmt};
use textwrap::{dedent, indent};
@ -10,11 +11,26 @@ use crate::ast::helpers::{
};
use crate::ast::types::Range;
use crate::ast::whitespace::leading_space;
use crate::define_violation;
use crate::fix::Fix;
use crate::registry::Diagnostic;
use crate::settings::{flags, Settings};
use crate::source_code::{Indexer, Locator, Stylist};
use crate::violations;
use crate::violation::AlwaysAutofixableViolation;
define_violation!(
pub struct UnsortedImports;
);
impl AlwaysAutofixableViolation for UnsortedImports {
#[derive_message_formats]
fn message(&self) -> String {
format!("Import block is un-sorted or un-formatted")
}
fn autofix_title(&self) -> String {
"Organize imports".to_string()
}
}
fn extract_range(body: &[&Stmt]) -> Range {
let location = body.first().unwrap().location;
@ -47,7 +63,7 @@ pub fn organize_imports(
if preceded_by_multi_statement_line(block.imports.first().unwrap(), locator, indexer)
|| followed_by_multi_statement_line(block.imports.last().unwrap(), locator)
{
return Some(Diagnostic::new(violations::UnsortedImports, range));
return Some(Diagnostic::new(UnsortedImports, range));
}
// Extract comments. Take care to grab any inline comments from the last line.
@ -100,7 +116,7 @@ pub fn organize_imports(
if actual == dedent(&expected) {
None
} else {
let mut diagnostic = Diagnostic::new(violations::UnsortedImports, range);
let mut diagnostic = Diagnostic::new(UnsortedImports, range);
if matches!(autofix, flags::Autofix::Enabled)
&& settings.rules.should_fix(diagnostic.kind.rule())
{

View file

@ -3781,54 +3781,6 @@ impl Violation for ErrorSuffixOnExceptionName {
}
}
// isort
define_violation!(
pub struct UnsortedImports;
);
impl AlwaysAutofixableViolation for UnsortedImports {
#[derive_message_formats]
fn message(&self) -> String {
format!("Import block is un-sorted or un-formatted")
}
fn autofix_title(&self) -> String {
"Organize imports".to_string()
}
}
define_violation!(
pub struct MissingRequiredImport(pub String);
);
impl AlwaysAutofixableViolation for MissingRequiredImport {
#[derive_message_formats]
fn message(&self) -> String {
let MissingRequiredImport(name) = self;
format!("Missing required import: `{name}`")
}
fn autofix_title(&self) -> String {
let MissingRequiredImport(name) = self;
format!("Insert required import: `{name}`")
}
}
// eradicate
define_violation!(
pub struct CommentedOutCode;
);
impl AlwaysAutofixableViolation for CommentedOutCode {
#[derive_message_formats]
fn message(&self) -> String {
format!("Found commented-out code")
}
fn autofix_title(&self) -> String {
"Remove commented-out code".to_string()
}
}
// flake8-bandit
define_violation!(
@ -4028,38 +3980,6 @@ impl Violation for SnmpWeakCryptography {
}
}
// flake8-boolean-trap
define_violation!(
pub struct BooleanPositionalArgInFunctionDefinition;
);
impl Violation for BooleanPositionalArgInFunctionDefinition {
#[derive_message_formats]
fn message(&self) -> String {
format!("Boolean positional arg in function definition")
}
}
define_violation!(
pub struct BooleanDefaultValueInFunctionDefinition;
);
impl Violation for BooleanDefaultValueInFunctionDefinition {
#[derive_message_formats]
fn message(&self) -> String {
format!("Boolean default value in function definition")
}
}
define_violation!(
pub struct BooleanPositionalValueInFunctionCall;
);
impl Violation for BooleanPositionalValueInFunctionCall {
#[derive_message_formats]
fn message(&self) -> String {
format!("Boolean positional value in function call")
}
}
// flake8-unused-arguments
define_violation!(
@ -4117,19 +4037,6 @@ impl Violation for UnusedLambdaArgument {
}
}
// flake8-import-conventions
define_violation!(
pub struct ImportAliasIsNotConventional(pub String, pub String);
);
impl Violation for ImportAliasIsNotConventional {
#[derive_message_formats]
fn message(&self) -> String {
let ImportAliasIsNotConventional(name, asname) = self;
format!("`{name}` should be imported as `{asname}`")
}
}
// flake8-datetimez
define_violation!(
@ -4737,138 +4644,6 @@ impl AlwaysAutofixableViolation for UseFixturesWithoutParameters {
}
}
// flake8-pie
define_violation!(
pub struct NoUnnecessaryPass;
);
impl AlwaysAutofixableViolation for NoUnnecessaryPass {
#[derive_message_formats]
fn message(&self) -> String {
format!("Unnecessary `pass` statement")
}
fn autofix_title(&self) -> String {
"Remove unnecessary `pass`".to_string()
}
}
define_violation!(
pub struct DupeClassFieldDefinitions(pub String);
);
impl AlwaysAutofixableViolation for DupeClassFieldDefinitions {
#[derive_message_formats]
fn message(&self) -> String {
let DupeClassFieldDefinitions(name) = self;
format!("Class field `{name}` is defined multiple times")
}
fn autofix_title(&self) -> String {
let DupeClassFieldDefinitions(name) = self;
format!("Remove duplicate field definition for `{name}`")
}
}
define_violation!(
pub struct PreferUniqueEnums {
pub value: String,
}
);
impl Violation for PreferUniqueEnums {
#[derive_message_formats]
fn message(&self) -> String {
let PreferUniqueEnums { value } = self;
format!("Enum contains duplicate value: `{value}`")
}
}
define_violation!(
pub struct NoUnnecessarySpread;
);
impl Violation for NoUnnecessarySpread {
#[derive_message_formats]
fn message(&self) -> String {
format!("Unnecessary spread `**`")
}
}
define_violation!(
pub struct NoUnnecessaryDictKwargs;
);
impl Violation for NoUnnecessaryDictKwargs {
#[derive_message_formats]
fn message(&self) -> String {
format!("Unnecessary `dict` kwargs")
}
}
define_violation!(
pub struct PreferListBuiltin;
);
impl AlwaysAutofixableViolation for PreferListBuiltin {
#[derive_message_formats]
fn message(&self) -> String {
format!("Prefer `list` over useless lambda")
}
fn autofix_title(&self) -> String {
"Replace with `list`".to_string()
}
}
// flake8-commas
define_violation!(
pub struct TrailingCommaMissing;
);
impl AlwaysAutofixableViolation for TrailingCommaMissing {
#[derive_message_formats]
fn message(&self) -> String {
format!("Trailing comma missing")
}
fn autofix_title(&self) -> String {
"Add trailing comma".to_string()
}
}
define_violation!(
pub struct TrailingCommaOnBareTupleProhibited;
);
impl Violation for TrailingCommaOnBareTupleProhibited {
#[derive_message_formats]
fn message(&self) -> String {
format!("Trailing comma on bare tuple prohibited")
}
}
define_violation!(
pub struct TrailingCommaProhibited;
);
impl AlwaysAutofixableViolation for TrailingCommaProhibited {
#[derive_message_formats]
fn message(&self) -> String {
format!("Trailing comma prohibited")
}
fn autofix_title(&self) -> String {
"Remove trailing comma".to_string()
}
}
// flake8-no-pep420
define_violation!(
pub struct ImplicitNamespacePackage(pub String);
);
impl Violation for ImplicitNamespacePackage {
#[derive_message_formats]
fn message(&self) -> String {
let ImplicitNamespacePackage(filename) = self;
format!("File `{filename}` is part of an implicit namespace package. Add an `__init__.py`.")
}
}
// ruff
define_violation!(