Move remaining flake8-pytest-style violations to rule modules (#2482)

This commit is contained in:
Aarni Koskela 2023-02-02 19:10:49 +02:00 committed by GitHub
parent 8e53a4d1d3
commit b4b8782243
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 264 additions and 258 deletions

View file

@ -394,26 +394,26 @@ ruff_macros::define_rule_mapping!(
PT003 => rules::flake8_pytest_style::rules::ExtraneousScopeFunction,
PT004 => rules::flake8_pytest_style::rules::MissingFixtureNameUnderscore,
PT005 => rules::flake8_pytest_style::rules::IncorrectFixtureNameUnderscore,
PT006 => violations::ParametrizeNamesWrongType,
PT007 => violations::ParametrizeValuesWrongType,
PT008 => violations::PatchWithLambda,
PT009 => violations::UnittestAssertion,
PT010 => violations::RaisesWithoutException,
PT011 => violations::RaisesTooBroad,
PT012 => violations::RaisesWithMultipleStatements,
PT013 => violations::IncorrectPytestImport,
PT015 => violations::AssertAlwaysFalse,
PT016 => violations::FailWithoutMessage,
PT017 => violations::AssertInExcept,
PT018 => violations::CompositeAssertion,
PT006 => rules::flake8_pytest_style::rules::ParametrizeNamesWrongType,
PT007 => rules::flake8_pytest_style::rules::ParametrizeValuesWrongType,
PT008 => rules::flake8_pytest_style::rules::PatchWithLambda,
PT009 => rules::flake8_pytest_style::rules::UnittestAssertion,
PT010 => rules::flake8_pytest_style::rules::RaisesWithoutException,
PT011 => rules::flake8_pytest_style::rules::RaisesTooBroad,
PT012 => rules::flake8_pytest_style::rules::RaisesWithMultipleStatements,
PT013 => rules::flake8_pytest_style::rules::IncorrectPytestImport,
PT015 => rules::flake8_pytest_style::rules::AssertAlwaysFalse,
PT016 => rules::flake8_pytest_style::rules::FailWithoutMessage,
PT017 => rules::flake8_pytest_style::rules::AssertInExcept,
PT018 => rules::flake8_pytest_style::rules::CompositeAssertion,
PT019 => rules::flake8_pytest_style::rules::FixtureParamWithoutValue,
PT020 => rules::flake8_pytest_style::rules::DeprecatedYieldFixture,
PT021 => rules::flake8_pytest_style::rules::FixtureFinalizerCallback,
PT022 => rules::flake8_pytest_style::rules::UselessYieldFixture,
PT023 => violations::IncorrectMarkParenthesesStyle,
PT023 => rules::flake8_pytest_style::rules::IncorrectMarkParenthesesStyle,
PT024 => rules::flake8_pytest_style::rules::UnnecessaryAsyncioMarkOnFixture,
PT025 => rules::flake8_pytest_style::rules::ErroneousUseFixturesOnFixture,
PT026 => violations::UseFixturesWithoutParameters,
PT026 => rules::flake8_pytest_style::rules::UseFixturesWithoutParameters,
// flake8-pie
PIE790 => rules::flake8_pie::rules::NoUnnecessaryPass,
PIE794 => rules::flake8_pie::rules::DupeClassFieldDefinitions,

View file

@ -9,9 +9,64 @@ use crate::ast::types::Range;
use crate::ast::visitor;
use crate::ast::visitor::Visitor;
use crate::checkers::ast::Checker;
use crate::define_violation;
use crate::fix::Fix;
use crate::registry::Diagnostic;
use crate::violations;
use crate::violation::{AlwaysAutofixableViolation, Violation};
use ruff_macros::derive_message_formats;
define_violation!(
pub struct CompositeAssertion;
);
impl Violation for CompositeAssertion {
#[derive_message_formats]
fn message(&self) -> String {
format!("Assertion should be broken down into multiple parts")
}
}
define_violation!(
pub struct AssertInExcept {
pub name: String,
}
);
impl Violation for AssertInExcept {
#[derive_message_formats]
fn message(&self) -> String {
let AssertInExcept { name } = self;
format!(
"Found assertion on exception `{name}` in except block, use `pytest.raises()` instead"
)
}
}
define_violation!(
pub struct AssertAlwaysFalse;
);
impl Violation for AssertAlwaysFalse {
#[derive_message_formats]
fn message(&self) -> String {
format!("Assertion always fails, replace with `pytest.fail()`")
}
}
define_violation!(
pub struct UnittestAssertion {
pub assertion: String,
}
);
impl AlwaysAutofixableViolation for UnittestAssertion {
#[derive_message_formats]
fn message(&self) -> String {
let UnittestAssertion { assertion } = self;
format!("Use a regular `assert` instead of unittest-style `{assertion}`")
}
fn autofix_title(&self) -> String {
let UnittestAssertion { assertion } = self;
format!("Replace `{assertion}(...)` with `assert ...`")
}
}
/// Visitor that tracks assert statements and checks if they reference
/// the exception name.
@ -52,7 +107,7 @@ where
if let Some(current_assert) = self.current_assert {
if id.as_str() == self.exception_name {
self.errors.push(Diagnostic::new(
violations::AssertInExcept {
AssertInExcept {
name: id.to_string(),
},
Range::from_located(current_assert),
@ -102,7 +157,7 @@ pub fn unittest_assertion(
ExprKind::Attribute { attr, .. } => {
if let Ok(unittest_assert) = UnittestAssert::try_from(attr.as_str()) {
let mut diagnostic = Diagnostic::new(
violations::UnittestAssertion {
UnittestAssertion {
assertion: unittest_assert.to_string(),
},
Range::from_located(func),
@ -129,7 +184,7 @@ pub fn unittest_assertion(
pub fn assert_falsy(assert_stmt: &Stmt, test_expr: &Expr) -> Option<Diagnostic> {
if is_falsy_constant(test_expr) {
Some(Diagnostic::new(
violations::AssertAlwaysFalse,
AssertAlwaysFalse,
Range::from_located(assert_stmt),
))
} else {
@ -157,7 +212,7 @@ pub fn assert_in_exception_handler(handlers: &[Excepthandler]) -> Vec<Diagnostic
pub fn composite_condition(assert_stmt: &Stmt, test_expr: &Expr) -> Option<Diagnostic> {
if is_composite_condition(test_expr) {
Some(Diagnostic::new(
violations::CompositeAssertion,
CompositeAssertion,
Range::from_located(assert_stmt),
))
} else {

View file

@ -4,8 +4,20 @@ use super::helpers::{is_empty_or_null_string, is_pytest_fail};
use crate::ast::helpers::SimpleCallArgs;
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::define_violation;
use crate::registry::Diagnostic;
use crate::violations;
use crate::violation::Violation;
use ruff_macros::derive_message_formats;
define_violation!(
pub struct FailWithoutMessage;
);
impl Violation for FailWithoutMessage {
#[derive_message_formats]
fn message(&self) -> String {
format!("No message passed to `pytest.fail()`")
}
}
pub fn fail_call(checker: &mut Checker, call: &Expr, args: &[Expr], keywords: &[Keyword]) {
if is_pytest_fail(call, checker) {
@ -15,13 +27,13 @@ pub fn fail_call(checker: &mut Checker, call: &Expr, args: &[Expr], keywords: &[
if let Some(msg) = msg {
if is_empty_or_null_string(msg) {
checker.diagnostics.push(Diagnostic::new(
violations::FailWithoutMessage,
FailWithoutMessage,
Range::from_located(call),
));
}
} else {
checker.diagnostics.push(Diagnostic::new(
violations::FailWithoutMessage,
FailWithoutMessage,
Range::from_located(call),
));
}

View file

@ -1,8 +1,20 @@
use rustpython_ast::Stmt;
use crate::ast::types::Range;
use crate::define_violation;
use crate::registry::Diagnostic;
use crate::violations;
use crate::violation::Violation;
use ruff_macros::derive_message_formats;
define_violation!(
pub struct IncorrectPytestImport;
);
impl Violation for IncorrectPytestImport {
#[derive_message_formats]
fn message(&self) -> String {
format!("Found incorrect import of pytest, use simple `import pytest` instead")
}
}
fn is_pytest_or_subpackage(imported_name: &str) -> bool {
imported_name == "pytest" || imported_name.starts_with("pytest.")
@ -14,7 +26,7 @@ pub fn import(import_from: &Stmt, name: &str, asname: Option<&str>) -> Option<Di
if let Some(alias) = asname {
if alias != name {
return Some(Diagnostic::new(
violations::IncorrectPytestImport,
IncorrectPytestImport,
Range::from_located(import_from),
));
}
@ -39,7 +51,7 @@ pub fn import_from(
if let Some(module) = module {
if is_pytest_or_subpackage(module) {
return Some(Diagnostic::new(
violations::IncorrectPytestImport,
IncorrectPytestImport,
Range::from_located(import_from),
));
}

View file

@ -1,11 +1,52 @@
use rustpython_ast::{Expr, ExprKind, Location};
use super::helpers::{get_mark_decorators, get_mark_name};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::define_violation;
use crate::fix::Fix;
use crate::registry::{Diagnostic, Rule};
use crate::violations;
use crate::violation::AlwaysAutofixableViolation;
use ruff_macros::derive_message_formats;
use rustpython_ast::{Expr, ExprKind, Location};
define_violation!(
pub struct IncorrectMarkParenthesesStyle {
pub mark_name: String,
pub expected_parens: String,
pub actual_parens: String,
}
);
impl AlwaysAutofixableViolation for IncorrectMarkParenthesesStyle {
#[derive_message_formats]
fn message(&self) -> String {
let IncorrectMarkParenthesesStyle {
mark_name,
expected_parens,
actual_parens,
} = self;
format!(
"Use `@pytest.mark.{mark_name}{expected_parens}` over \
`@pytest.mark.{mark_name}{actual_parens}`"
)
}
fn autofix_title(&self) -> String {
"Add/remove parentheses".to_string()
}
}
define_violation!(
pub struct UseFixturesWithoutParameters;
);
impl AlwaysAutofixableViolation for UseFixturesWithoutParameters {
#[derive_message_formats]
fn message(&self) -> String {
format!("Useless `pytest.mark.usefixtures` without parameters")
}
fn autofix_title(&self) -> String {
"Remove `usefixtures` decorator or pass parameters".to_string()
}
}
fn pytest_mark_parentheses(
checker: &mut Checker,
@ -15,7 +56,7 @@ fn pytest_mark_parentheses(
actual: &str,
) {
let mut diagnostic = Diagnostic::new(
violations::IncorrectMarkParenthesesStyle {
IncorrectMarkParenthesesStyle {
mark_name: get_mark_name(decorator).to_string(),
expected_parens: preferred.to_string(),
actual_parens: actual.to_string(),
@ -68,10 +109,8 @@ fn check_useless_usefixtures(checker: &mut Checker, decorator: &Expr) {
}
if !has_parameters {
let mut diagnostic = Diagnostic::new(
violations::UseFixturesWithoutParameters,
Range::from_located(decorator),
);
let mut diagnostic =
Diagnostic::new(UseFixturesWithoutParameters, Range::from_located(decorator));
if checker.patch(diagnostic.kind.rule()) {
let at_start = Location::new(decorator.location.row(), decorator.location.column() - 1);
diagnostic.amend(Fix::deletion(at_start, decorator.end_location.unwrap()));

View file

@ -1,18 +1,22 @@
pub use assertion::{
assert_falsy, assert_in_exception_handler, composite_condition, unittest_assertion,
AssertAlwaysFalse, AssertInExcept, CompositeAssertion, UnittestAssertion,
};
pub use fail::fail_call;
pub use fail::{fail_call, FailWithoutMessage};
pub use fixture::{
fixture, DeprecatedYieldFixture, ErroneousUseFixturesOnFixture, ExtraneousScopeFunction,
FixtureFinalizerCallback, FixtureParamWithoutValue, FixturePositionalArgs,
IncorrectFixtureNameUnderscore, IncorrectFixtureParenthesesStyle, MissingFixtureNameUnderscore,
UnnecessaryAsyncioMarkOnFixture, UselessYieldFixture,
};
pub use imports::{import, import_from};
pub use marks::marks;
pub use parametrize::parametrize;
pub use patch::patch_with_lambda;
pub use raises::{complex_raises, raises_call};
pub use imports::{import, import_from, IncorrectPytestImport};
pub use marks::{marks, IncorrectMarkParenthesesStyle, UseFixturesWithoutParameters};
pub use parametrize::{parametrize, ParametrizeNamesWrongType, ParametrizeValuesWrongType};
pub use patch::{patch_with_lambda, PatchWithLambda};
pub use raises::{
complex_raises, raises_call, RaisesTooBroad, RaisesWithMultipleStatements,
RaisesWithoutException,
};
mod assertion;
mod fail;

View file

@ -1,14 +1,47 @@
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind};
use super::super::types;
use super::helpers::{is_pytest_parametrize, split_names};
use crate::ast::helpers::{create_expr, unparse_expr};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::define_violation;
use crate::fix::Fix;
use crate::registry::{Diagnostic, Rule};
use crate::source_code::Generator;
use crate::violations;
use crate::violation::{AlwaysAutofixableViolation, Violation};
use ruff_macros::derive_message_formats;
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind};
define_violation!(
pub struct ParametrizeNamesWrongType {
pub expected: types::ParametrizeNameType,
}
);
impl AlwaysAutofixableViolation for ParametrizeNamesWrongType {
#[derive_message_formats]
fn message(&self) -> String {
let ParametrizeNamesWrongType { expected } = self;
format!("Wrong name(s) type in `@pytest.mark.parametrize`, expected `{expected}`")
}
fn autofix_title(&self) -> String {
let ParametrizeNamesWrongType { expected } = self;
format!("Use a `{expected}` for parameter names")
}
}
define_violation!(
pub struct ParametrizeValuesWrongType {
pub values: types::ParametrizeValuesType,
pub row: types::ParametrizeValuesRowType,
}
);
impl Violation for ParametrizeValuesWrongType {
#[derive_message_formats]
fn message(&self) -> String {
let ParametrizeValuesWrongType { values, row } = self;
format!("Wrong values type in `@pytest.mark.parametrize` expected `{values}` of `{row}`")
}
}
fn get_parametrize_decorator<'a>(checker: &Checker, decorators: &'a [Expr]) -> Option<&'a Expr> {
decorators
@ -66,7 +99,7 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
match names_type {
types::ParametrizeNameType::Tuple => {
let mut diagnostic = Diagnostic::new(
violations::ParametrizeNamesWrongType {
ParametrizeNamesWrongType {
expected: names_type,
},
Range::from_located(expr),
@ -98,7 +131,7 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
}
types::ParametrizeNameType::List => {
let mut diagnostic = Diagnostic::new(
violations::ParametrizeNamesWrongType {
ParametrizeNamesWrongType {
expected: names_type,
},
Range::from_located(expr),
@ -140,7 +173,7 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
types::ParametrizeNameType::Tuple => {}
types::ParametrizeNameType::List => {
let mut diagnostic = Diagnostic::new(
violations::ParametrizeNamesWrongType {
ParametrizeNamesWrongType {
expected: names_type,
},
Range::from_located(expr),
@ -162,7 +195,7 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
}
types::ParametrizeNameType::Csv => {
let mut diagnostic = Diagnostic::new(
violations::ParametrizeNamesWrongType {
ParametrizeNamesWrongType {
expected: names_type,
},
Range::from_located(expr),
@ -191,7 +224,7 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
types::ParametrizeNameType::List => {}
types::ParametrizeNameType::Tuple => {
let mut diagnostic = Diagnostic::new(
violations::ParametrizeNamesWrongType {
ParametrizeNamesWrongType {
expected: names_type,
},
Range::from_located(expr),
@ -215,7 +248,7 @@ fn check_names(checker: &mut Checker, expr: &Expr) {
}
types::ParametrizeNameType::Csv => {
let mut diagnostic = Diagnostic::new(
violations::ParametrizeNamesWrongType {
ParametrizeNamesWrongType {
expected: names_type,
},
Range::from_located(expr),
@ -261,7 +294,7 @@ fn check_values(checker: &mut Checker, names: &Expr, values: &Expr) {
ExprKind::List { elts, .. } => {
if values_type != types::ParametrizeValuesType::List {
checker.diagnostics.push(Diagnostic::new(
violations::ParametrizeValuesWrongType {
ParametrizeValuesWrongType {
values: values_type,
row: values_row_type,
},
@ -275,7 +308,7 @@ fn check_values(checker: &mut Checker, names: &Expr, values: &Expr) {
ExprKind::Tuple { elts, .. } => {
if values_type != types::ParametrizeValuesType::Tuple {
checker.diagnostics.push(Diagnostic::new(
violations::ParametrizeValuesWrongType {
ParametrizeValuesWrongType {
values: values_type,
row: values_row_type,
},
@ -292,7 +325,7 @@ fn check_values(checker: &mut Checker, names: &Expr, values: &Expr) {
fn handle_single_name(checker: &mut Checker, expr: &Expr, value: &Expr) {
let mut diagnostic = Diagnostic::new(
violations::ParametrizeNamesWrongType {
ParametrizeNamesWrongType {
expected: types::ParametrizeNameType::Csv,
},
Range::from_located(expr),
@ -319,7 +352,7 @@ fn handle_value_rows(
ExprKind::Tuple { .. } => {
if values_row_type != types::ParametrizeValuesRowType::Tuple {
checker.diagnostics.push(Diagnostic::new(
violations::ParametrizeValuesWrongType {
ParametrizeValuesWrongType {
values: values_type,
row: values_row_type,
},
@ -330,7 +363,7 @@ fn handle_value_rows(
ExprKind::List { .. } => {
if values_row_type != types::ParametrizeValuesRowType::List {
checker.diagnostics.push(Diagnostic::new(
violations::ParametrizeValuesWrongType {
ParametrizeValuesWrongType {
values: values_type,
row: values_row_type,
},

View file

@ -5,8 +5,20 @@ use crate::ast::helpers::{collect_arg_names, compose_call_path, SimpleCallArgs};
use crate::ast::types::Range;
use crate::ast::visitor;
use crate::ast::visitor::Visitor;
use crate::define_violation;
use crate::registry::Diagnostic;
use crate::violations;
use crate::violation::Violation;
use ruff_macros::derive_message_formats;
define_violation!(
pub struct PatchWithLambda;
);
impl Violation for PatchWithLambda {
#[derive_message_formats]
fn message(&self) -> String {
format!("Use `return_value=` instead of patching with `lambda`")
}
}
const PATCH_NAMES: &[&str] = &[
"mocker.patch",
@ -72,10 +84,7 @@ fn check_patch_call(
visitor.visit_expr(body);
if !visitor.uses_args {
return Some(Diagnostic::new(
violations::PatchWithLambda,
Range::from_located(call),
));
return Some(Diagnostic::new(PatchWithLambda, Range::from_located(call)));
}
}
}

View file

@ -4,8 +4,46 @@ use super::helpers::is_empty_or_null_string;
use crate::ast::helpers::{format_call_path, to_call_path};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::define_violation;
use crate::registry::{Diagnostic, Rule};
use crate::violations;
use crate::violation::Violation;
use ruff_macros::derive_message_formats;
define_violation!(
pub struct RaisesWithMultipleStatements;
);
impl Violation for RaisesWithMultipleStatements {
#[derive_message_formats]
fn message(&self) -> String {
format!("`pytest.raises()` block should contain a single simple statement")
}
}
define_violation!(
pub struct RaisesTooBroad {
pub exception: String,
}
);
impl Violation for RaisesTooBroad {
#[derive_message_formats]
fn message(&self) -> String {
let RaisesTooBroad { exception } = self;
format!(
"`pytest.raises({exception})` is too broad, set the `match` parameter or use a more \
specific exception"
)
}
}
define_violation!(
pub struct RaisesWithoutException;
);
impl Violation for RaisesWithoutException {
#[derive_message_formats]
fn message(&self) -> String {
format!("set the expected exception in `pytest.raises()`")
}
}
fn is_pytest_raises(checker: &Checker, func: &Expr) -> bool {
checker.resolve_call_path(func).map_or(false, |call_path| {
@ -32,7 +70,7 @@ pub fn raises_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
{
if args.is_empty() && keywords.is_empty() {
checker.diagnostics.push(Diagnostic::new(
violations::RaisesWithoutException,
RaisesWithoutException,
Range::from_located(func),
));
}
@ -88,7 +126,7 @@ pub fn complex_raises(checker: &mut Checker, stmt: &Stmt, items: &[Withitem], bo
if is_too_complex {
checker.diagnostics.push(Diagnostic::new(
violations::RaisesWithMultipleStatements,
RaisesWithMultipleStatements,
Range::from_located(stmt),
));
}
@ -117,7 +155,7 @@ fn exception_needs_match(checker: &mut Checker, exception: &Expr) {
}
}) {
checker.diagnostics.push(Diagnostic::new(
violations::RaisesTooBroad {
RaisesTooBroad {
exception: call_path,
},
Range::from_located(exception),

View file

@ -8,9 +8,6 @@ use serde::{Deserialize, Serialize};
use crate::define_violation;
use crate::rules::flake8_debugger::types::DebuggerUsingType;
use crate::rules::flake8_pytest_style::types::{
ParametrizeNameType, ParametrizeValuesRowType, ParametrizeValuesType,
};
use crate::rules::pyupgrade::types::Primitive;
use crate::violation::{AlwaysAutofixableViolation, AutofixKind, Availability, Violation};
@ -3761,199 +3758,6 @@ impl Violation for DotFormatInException {
}
}
// flake8-pytest-style
define_violation!(
pub struct ParametrizeNamesWrongType {
pub expected: ParametrizeNameType,
}
);
impl AlwaysAutofixableViolation for ParametrizeNamesWrongType {
#[derive_message_formats]
fn message(&self) -> String {
let ParametrizeNamesWrongType { expected } = self;
format!("Wrong name(s) type in `@pytest.mark.parametrize`, expected `{expected}`")
}
fn autofix_title(&self) -> String {
let ParametrizeNamesWrongType { expected } = self;
format!("Use a `{expected}` for parameter names")
}
}
define_violation!(
pub struct ParametrizeValuesWrongType {
pub values: ParametrizeValuesType,
pub row: ParametrizeValuesRowType,
}
);
impl Violation for ParametrizeValuesWrongType {
#[derive_message_formats]
fn message(&self) -> String {
let ParametrizeValuesWrongType { values, row } = self;
format!("Wrong values type in `@pytest.mark.parametrize` expected `{values}` of `{row}`")
}
}
define_violation!(
pub struct PatchWithLambda;
);
impl Violation for PatchWithLambda {
#[derive_message_formats]
fn message(&self) -> String {
format!("Use `return_value=` instead of patching with `lambda`")
}
}
define_violation!(
pub struct UnittestAssertion {
pub assertion: String,
}
);
impl AlwaysAutofixableViolation for UnittestAssertion {
#[derive_message_formats]
fn message(&self) -> String {
let UnittestAssertion { assertion } = self;
format!("Use a regular `assert` instead of unittest-style `{assertion}`")
}
fn autofix_title(&self) -> String {
let UnittestAssertion { assertion } = self;
format!("Replace `{assertion}(...)` with `assert ...`")
}
}
define_violation!(
pub struct RaisesWithoutException;
);
impl Violation for RaisesWithoutException {
#[derive_message_formats]
fn message(&self) -> String {
format!("set the expected exception in `pytest.raises()`")
}
}
define_violation!(
pub struct RaisesTooBroad {
pub exception: String,
}
);
impl Violation for RaisesTooBroad {
#[derive_message_formats]
fn message(&self) -> String {
let RaisesTooBroad { exception } = self;
format!(
"`pytest.raises({exception})` is too broad, set the `match` parameter or use a more \
specific exception"
)
}
}
define_violation!(
pub struct RaisesWithMultipleStatements;
);
impl Violation for RaisesWithMultipleStatements {
#[derive_message_formats]
fn message(&self) -> String {
format!("`pytest.raises()` block should contain a single simple statement")
}
}
define_violation!(
pub struct IncorrectPytestImport;
);
impl Violation for IncorrectPytestImport {
#[derive_message_formats]
fn message(&self) -> String {
format!("Found incorrect import of pytest, use simple `import pytest` instead")
}
}
define_violation!(
pub struct AssertAlwaysFalse;
);
impl Violation for AssertAlwaysFalse {
#[derive_message_formats]
fn message(&self) -> String {
format!("Assertion always fails, replace with `pytest.fail()`")
}
}
define_violation!(
pub struct FailWithoutMessage;
);
impl Violation for FailWithoutMessage {
#[derive_message_formats]
fn message(&self) -> String {
format!("No message passed to `pytest.fail()`")
}
}
define_violation!(
pub struct AssertInExcept {
pub name: String,
}
);
impl Violation for AssertInExcept {
#[derive_message_formats]
fn message(&self) -> String {
let AssertInExcept { name } = self;
format!(
"Found assertion on exception `{name}` in except block, use `pytest.raises()` instead"
)
}
}
define_violation!(
pub struct CompositeAssertion;
);
impl Violation for CompositeAssertion {
#[derive_message_formats]
fn message(&self) -> String {
format!("Assertion should be broken down into multiple parts")
}
}
define_violation!(
pub struct IncorrectMarkParenthesesStyle {
pub mark_name: String,
pub expected_parens: String,
pub actual_parens: String,
}
);
impl AlwaysAutofixableViolation for IncorrectMarkParenthesesStyle {
#[derive_message_formats]
fn message(&self) -> String {
let IncorrectMarkParenthesesStyle {
mark_name,
expected_parens,
actual_parens,
} = self;
format!(
"Use `@pytest.mark.{mark_name}{expected_parens}` over \
`@pytest.mark.{mark_name}{actual_parens}`"
)
}
fn autofix_title(&self) -> String {
"Add/remove parentheses".to_string()
}
}
define_violation!(
pub struct UseFixturesWithoutParameters;
);
impl AlwaysAutofixableViolation for UseFixturesWithoutParameters {
#[derive_message_formats]
fn message(&self) -> String {
format!("Useless `pytest.mark.usefixtures` without parameters")
}
fn autofix_title(&self) -> String {
"Remove `usefixtures` decorator or pass parameters".to_string()
}
}
// ruff
define_violation!(