mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-24 19:12:44 +00:00
Support 'reason' argument to pytest.fail
(#5040)
## Summary Per the [API reference](https://docs.pytest.org/en/7.1.x/reference/reference.html#pytest.fail), `reason` was added in version 7, and is equivalent to `msg` (but preferred going forward). I also grepped for `msg` usages in `flake8_pytest_style`, but found no others (apart from those that reference `unittest` APIs.) Closes #3387.
This commit is contained in:
parent
e2130707f5
commit
cbd4c10fdd
4 changed files with 75 additions and 43 deletions
|
@ -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"")
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -206,9 +206,7 @@ impl UnittestAssert {
|
|||
keywords: &'a [Keyword],
|
||||
) -> Result<FxHashMap<&'a str, &'a Expr>> {
|
||||
// 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)
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue