diff --git a/crates/ruff/resources/test/fixtures/flake8_pytest_style/PT016.py b/crates/ruff/resources/test/fixtures/flake8_pytest_style/PT016.py index 4f06451450..288d5d9be6 100644 --- a/crates/ruff/resources/test/fixtures/flake8_pytest_style/PT016.py +++ b/crates/ruff/resources/test/fixtures/flake8_pytest_style/PT016.py @@ -1,17 +1,25 @@ import pytest -def test_xxx(): - pytest.fail("this is a failure") # Test OK arg +# OK +def f(): + pytest.fail("this is a failure") -def test_xxx(): - pytest.fail(msg="this is a failure") # Test OK kwarg +def f(): + pytest.fail(msg="this is a failure") -def test_xxx(): # Error +def f(): + pytest.fail(reason="this is a failure") + + +# Errors +def f(): pytest.fail() pytest.fail("") pytest.fail(f"") pytest.fail(msg="") pytest.fail(msg=f"") + pytest.fail(reason="") + pytest.fail(reason=f"") diff --git a/crates/ruff/src/rules/flake8_pytest_style/rules/fail.rs b/crates/ruff/src/rules/flake8_pytest_style/rules/fail.rs index 6faa0915f4..5f11d6f2f6 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/fail.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/fail.rs @@ -21,7 +21,12 @@ impl Violation for PytestFailWithoutMessage { pub(crate) fn fail_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) { if is_pytest_fail(checker.semantic_model(), func) { let call_args = SimpleCallArgs::new(args, keywords); - let msg = call_args.argument("msg", 0); + + // Allow either `pytest.fail(reason="...")` (introduced in pytest 7.0) or + // `pytest.fail(msg="...")` (deprecated in pytest 7.0) + let msg = call_args + .argument("reason", 0) + .or_else(|| call_args.argument("msg", 0)); if let Some(msg) = msg { if is_empty_or_null_string(msg) { diff --git a/crates/ruff/src/rules/flake8_pytest_style/rules/unittest_assert.rs b/crates/ruff/src/rules/flake8_pytest_style/rules/unittest_assert.rs index 81b07d166a..8c70114e67 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/rules/unittest_assert.rs +++ b/crates/ruff/src/rules/flake8_pytest_style/rules/unittest_assert.rs @@ -206,9 +206,7 @@ impl UnittestAssert { keywords: &'a [Keyword], ) -> Result> { // If we have variable-length arguments, abort. - if args.iter().any(|arg| matches!(arg, Expr::Starred(_))) - || keywords.iter().any(|kw| kw.arg.is_none()) - { + if args.iter().any(Expr::is_starred_expr) || keywords.iter().any(|kw| kw.arg.is_none()) { bail!("Variable-length arguments are not supported"); } @@ -263,14 +261,14 @@ impl UnittestAssert { .ok_or_else(|| anyhow!("Missing argument `expr`"))?; let msg = args.get("msg").copied(); Ok(if matches!(self, UnittestAssert::False) { - let node = expr.clone(); - let node1 = Expr::UnaryOp(ast::ExprUnaryOp { - op: Unaryop::Not, - operand: Box::new(node), - range: TextRange::default(), - }); - let unary_expr = node1; - assert(&unary_expr, msg) + assert( + &Expr::UnaryOp(ast::ExprUnaryOp { + op: Unaryop::Not, + operand: Box::new(expr.clone()), + range: TextRange::default(), + }), + msg, + ) } else { assert(expr, msg) }) diff --git a/crates/ruff/src/rules/flake8_pytest_style/snapshots/ruff__rules__flake8_pytest_style__tests__PT016.snap b/crates/ruff/src/rules/flake8_pytest_style/snapshots/ruff__rules__flake8_pytest_style__tests__PT016.snap index 5223b12eed..945f989567 100644 --- a/crates/ruff/src/rules/flake8_pytest_style/snapshots/ruff__rules__flake8_pytest_style__tests__PT016.snap +++ b/crates/ruff/src/rules/flake8_pytest_style/snapshots/ruff__rules__flake8_pytest_style__tests__PT016.snap @@ -1,49 +1,70 @@ --- source: crates/ruff/src/rules/flake8_pytest_style/mod.rs --- -PT016.py:13:5: PT016 No message passed to `pytest.fail()` +PT016.py:19:5: PT016 No message passed to `pytest.fail()` | -12 | def test_xxx(): # Error -13 | pytest.fail() +17 | # Errors +18 | def f(): +19 | pytest.fail() | ^^^^^^^^^^^ PT016 -14 | pytest.fail("") -15 | pytest.fail(f"") +20 | pytest.fail("") +21 | pytest.fail(f"") | -PT016.py:14:5: PT016 No message passed to `pytest.fail()` +PT016.py:20:5: PT016 No message passed to `pytest.fail()` | -12 | def test_xxx(): # Error -13 | pytest.fail() -14 | pytest.fail("") +18 | def f(): +19 | pytest.fail() +20 | pytest.fail("") | ^^^^^^^^^^^ PT016 -15 | pytest.fail(f"") -16 | pytest.fail(msg="") +21 | pytest.fail(f"") +22 | pytest.fail(msg="") | -PT016.py:15:5: PT016 No message passed to `pytest.fail()` +PT016.py:21:5: PT016 No message passed to `pytest.fail()` | -13 | pytest.fail() -14 | pytest.fail("") -15 | pytest.fail(f"") +19 | pytest.fail() +20 | pytest.fail("") +21 | pytest.fail(f"") | ^^^^^^^^^^^ PT016 -16 | pytest.fail(msg="") -17 | pytest.fail(msg=f"") +22 | pytest.fail(msg="") +23 | pytest.fail(msg=f"") | -PT016.py:16:5: PT016 No message passed to `pytest.fail()` +PT016.py:22:5: PT016 No message passed to `pytest.fail()` | -14 | pytest.fail("") -15 | pytest.fail(f"") -16 | pytest.fail(msg="") +20 | pytest.fail("") +21 | pytest.fail(f"") +22 | pytest.fail(msg="") | ^^^^^^^^^^^ PT016 -17 | pytest.fail(msg=f"") +23 | pytest.fail(msg=f"") +24 | pytest.fail(reason="") | -PT016.py:17:5: PT016 No message passed to `pytest.fail()` +PT016.py:23:5: PT016 No message passed to `pytest.fail()` | -15 | pytest.fail(f"") -16 | pytest.fail(msg="") -17 | pytest.fail(msg=f"") +21 | pytest.fail(f"") +22 | pytest.fail(msg="") +23 | pytest.fail(msg=f"") + | ^^^^^^^^^^^ PT016 +24 | pytest.fail(reason="") +25 | pytest.fail(reason=f"") + | + +PT016.py:24:5: PT016 No message passed to `pytest.fail()` + | +22 | pytest.fail(msg="") +23 | pytest.fail(msg=f"") +24 | pytest.fail(reason="") + | ^^^^^^^^^^^ PT016 +25 | pytest.fail(reason=f"") + | + +PT016.py:25:5: PT016 No message passed to `pytest.fail()` + | +23 | pytest.fail(msg=f"") +24 | pytest.fail(reason="") +25 | pytest.fail(reason=f"") | ^^^^^^^^^^^ PT016 |