diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT011.py b/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT011.py index fb152beea67f5..368cea6af67d9 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT011.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT011.py @@ -14,6 +14,13 @@ def test_ok_different_error_from_config(): raise ZeroDivisionError("Can't divide by 0") +def test_ok_legacy_form(): + def func(): + raise ValueError("Can't divide by 0") + + pytest.raises(ValueError, func).match("Can't divide by 0") + + def test_error_no_argument_given(): with pytest.raises(ValueError): raise ValueError("Can't divide 1 by 0") diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/raises.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/raises.rs index 08428d3284d65..8cd0ea6335b55 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/raises.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/raises.rs @@ -173,7 +173,11 @@ const fn is_non_trivial_with_body(body: &[Stmt]) -> bool { pub(crate) fn raises_call(checker: &Checker, call: &ast::ExprCall) { if is_pytest_raises(&call.func, checker.semantic()) { if checker.enabled(Rule::PytestRaisesWithoutException) { - if call.arguments.is_empty() { + if call + .arguments + .find_argument("expected_exception", 0) + .is_none() + { checker.report_diagnostic(Diagnostic::new( PytestRaisesWithoutException, call.func.range(), @@ -182,13 +186,22 @@ pub(crate) fn raises_call(checker: &Checker, call: &ast::ExprCall) { } if checker.enabled(Rule::PytestRaisesTooBroad) { - if let Some(exception) = call.arguments.find_argument_value("expected_exception", 0) { - if call - .arguments - .find_keyword("match") - .is_none_or(|k| is_empty_or_null_string(&k.value)) + // Pytest.raises has two overloads + // ```py + // with raises(expected_exception: type[E] | tuple[type[E], ...], *, match: str | Pattern[str] | None = ...) → RaisesContext[E] as excinfo + // with raises(expected_exception: type[E] | tuple[type[E], ...], func: Callable[[...], Any], *args: Any, **kwargs: Any) → ExceptionInfo[E] as excinfo + // ``` + // Don't raise this diagnostic if the call matches the second overload (has a second positional argument or an argument named `func`) + if call.arguments.find_argument("func", 1).is_none() { + if let Some(exception) = call.arguments.find_argument_value("expected_exception", 0) { - exception_needs_match(checker, exception); + if call + .arguments + .find_keyword("match") + .is_none_or(|k| is_empty_or_null_string(&k.value)) + { + exception_needs_match(checker, exception); + } } } } diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_default.snap b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_default.snap index 57b6b6f3933ce..7a4757d7ebeb3 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_default.snap +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_default.snap @@ -1,54 +1,54 @@ --- source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs --- -PT011.py:18:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:25:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -17 | def test_error_no_argument_given(): -18 | with pytest.raises(ValueError): +24 | def test_error_no_argument_given(): +25 | with pytest.raises(ValueError): | ^^^^^^^^^^ PT011 -19 | raise ValueError("Can't divide 1 by 0") +26 | raise ValueError("Can't divide 1 by 0") | -PT011.py:21:43: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:28:43: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -19 | raise ValueError("Can't divide 1 by 0") -20 | -21 | with pytest.raises(expected_exception=ValueError): +26 | raise ValueError("Can't divide 1 by 0") +27 | +28 | with pytest.raises(expected_exception=ValueError): | ^^^^^^^^^^ PT011 -22 | raise ValueError("Can't divide 1 by 0") +29 | raise ValueError("Can't divide 1 by 0") | -PT011.py:24:24: PT011 `pytest.raises(socket.error)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:31:24: PT011 `pytest.raises(socket.error)` is too broad, set the `match` parameter or use a more specific exception | -22 | raise ValueError("Can't divide 1 by 0") -23 | -24 | with pytest.raises(socket.error): +29 | raise ValueError("Can't divide 1 by 0") +30 | +31 | with pytest.raises(socket.error): | ^^^^^^^^^^^^ PT011 -25 | raise ValueError("Can't divide 1 by 0") +32 | raise ValueError("Can't divide 1 by 0") | -PT011.py:35:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:42:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -34 | def test_error_match_is_empty(): -35 | with pytest.raises(ValueError, match=None): +41 | def test_error_match_is_empty(): +42 | with pytest.raises(ValueError, match=None): | ^^^^^^^^^^ PT011 -36 | raise ValueError("Can't divide 1 by 0") +43 | raise ValueError("Can't divide 1 by 0") | -PT011.py:38:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:45:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -36 | raise ValueError("Can't divide 1 by 0") -37 | -38 | with pytest.raises(ValueError, match=""): +43 | raise ValueError("Can't divide 1 by 0") +44 | +45 | with pytest.raises(ValueError, match=""): | ^^^^^^^^^^ PT011 -39 | raise ValueError("Can't divide 1 by 0") +46 | raise ValueError("Can't divide 1 by 0") | -PT011.py:41:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:48:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -39 | raise ValueError("Can't divide 1 by 0") -40 | -41 | with pytest.raises(ValueError, match=f""): +46 | raise ValueError("Can't divide 1 by 0") +47 | +48 | with pytest.raises(ValueError, match=f""): | ^^^^^^^^^^ PT011 -42 | raise ValueError("Can't divide 1 by 0") +49 | raise ValueError("Can't divide 1 by 0") | diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_extend_broad_exceptions.snap b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_extend_broad_exceptions.snap index a256d353535d2..9e8020a9d7def 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_extend_broad_exceptions.snap +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_extend_broad_exceptions.snap @@ -9,54 +9,54 @@ PT011.py:13:24: PT011 `pytest.raises(ZeroDivisionError)` is too broad, set the ` 14 | raise ZeroDivisionError("Can't divide by 0") | -PT011.py:18:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:25:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -17 | def test_error_no_argument_given(): -18 | with pytest.raises(ValueError): +24 | def test_error_no_argument_given(): +25 | with pytest.raises(ValueError): | ^^^^^^^^^^ PT011 -19 | raise ValueError("Can't divide 1 by 0") +26 | raise ValueError("Can't divide 1 by 0") | -PT011.py:21:43: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:28:43: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -19 | raise ValueError("Can't divide 1 by 0") -20 | -21 | with pytest.raises(expected_exception=ValueError): +26 | raise ValueError("Can't divide 1 by 0") +27 | +28 | with pytest.raises(expected_exception=ValueError): | ^^^^^^^^^^ PT011 -22 | raise ValueError("Can't divide 1 by 0") +29 | raise ValueError("Can't divide 1 by 0") | -PT011.py:24:24: PT011 `pytest.raises(socket.error)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:31:24: PT011 `pytest.raises(socket.error)` is too broad, set the `match` parameter or use a more specific exception | -22 | raise ValueError("Can't divide 1 by 0") -23 | -24 | with pytest.raises(socket.error): +29 | raise ValueError("Can't divide 1 by 0") +30 | +31 | with pytest.raises(socket.error): | ^^^^^^^^^^^^ PT011 -25 | raise ValueError("Can't divide 1 by 0") +32 | raise ValueError("Can't divide 1 by 0") | -PT011.py:35:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:42:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -34 | def test_error_match_is_empty(): -35 | with pytest.raises(ValueError, match=None): +41 | def test_error_match_is_empty(): +42 | with pytest.raises(ValueError, match=None): | ^^^^^^^^^^ PT011 -36 | raise ValueError("Can't divide 1 by 0") +43 | raise ValueError("Can't divide 1 by 0") | -PT011.py:38:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:45:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -36 | raise ValueError("Can't divide 1 by 0") -37 | -38 | with pytest.raises(ValueError, match=""): +43 | raise ValueError("Can't divide 1 by 0") +44 | +45 | with pytest.raises(ValueError, match=""): | ^^^^^^^^^^ PT011 -39 | raise ValueError("Can't divide 1 by 0") +46 | raise ValueError("Can't divide 1 by 0") | -PT011.py:41:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:48:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -39 | raise ValueError("Can't divide 1 by 0") -40 | -41 | with pytest.raises(ValueError, match=f""): +46 | raise ValueError("Can't divide 1 by 0") +47 | +48 | with pytest.raises(ValueError, match=f""): | ^^^^^^^^^^ PT011 -42 | raise ValueError("Can't divide 1 by 0") +49 | raise ValueError("Can't divide 1 by 0") | diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_glob_all.snap b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_glob_all.snap index eb32dce4b14b8..d7d61cfe5117c 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_glob_all.snap +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_glob_all.snap @@ -9,72 +9,72 @@ PT011.py:13:24: PT011 `pytest.raises(ZeroDivisionError)` is too broad, set the ` 14 | raise ZeroDivisionError("Can't divide by 0") | -PT011.py:18:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:25:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -17 | def test_error_no_argument_given(): -18 | with pytest.raises(ValueError): +24 | def test_error_no_argument_given(): +25 | with pytest.raises(ValueError): | ^^^^^^^^^^ PT011 -19 | raise ValueError("Can't divide 1 by 0") +26 | raise ValueError("Can't divide 1 by 0") | -PT011.py:21:43: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:28:43: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -19 | raise ValueError("Can't divide 1 by 0") -20 | -21 | with pytest.raises(expected_exception=ValueError): +26 | raise ValueError("Can't divide 1 by 0") +27 | +28 | with pytest.raises(expected_exception=ValueError): | ^^^^^^^^^^ PT011 -22 | raise ValueError("Can't divide 1 by 0") +29 | raise ValueError("Can't divide 1 by 0") | -PT011.py:24:24: PT011 `pytest.raises(socket.error)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:31:24: PT011 `pytest.raises(socket.error)` is too broad, set the `match` parameter or use a more specific exception | -22 | raise ValueError("Can't divide 1 by 0") -23 | -24 | with pytest.raises(socket.error): +29 | raise ValueError("Can't divide 1 by 0") +30 | +31 | with pytest.raises(socket.error): | ^^^^^^^^^^^^ PT011 -25 | raise ValueError("Can't divide 1 by 0") +32 | raise ValueError("Can't divide 1 by 0") | -PT011.py:27:24: PT011 `pytest.raises(pickle.PicklingError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:34:24: PT011 `pytest.raises(pickle.PicklingError)` is too broad, set the `match` parameter or use a more specific exception | -25 | raise ValueError("Can't divide 1 by 0") -26 | -27 | with pytest.raises(PicklingError): +32 | raise ValueError("Can't divide 1 by 0") +33 | +34 | with pytest.raises(PicklingError): | ^^^^^^^^^^^^^ PT011 -28 | raise PicklingError("Can't pickle") +35 | raise PicklingError("Can't pickle") | -PT011.py:30:24: PT011 `pytest.raises(pickle.UnpicklingError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:37:24: PT011 `pytest.raises(pickle.UnpicklingError)` is too broad, set the `match` parameter or use a more specific exception | -28 | raise PicklingError("Can't pickle") -29 | -30 | with pytest.raises(UnpicklingError): +35 | raise PicklingError("Can't pickle") +36 | +37 | with pytest.raises(UnpicklingError): | ^^^^^^^^^^^^^^^ PT011 -31 | raise UnpicklingError("Can't unpickle") +38 | raise UnpicklingError("Can't unpickle") | -PT011.py:35:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:42:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -34 | def test_error_match_is_empty(): -35 | with pytest.raises(ValueError, match=None): +41 | def test_error_match_is_empty(): +42 | with pytest.raises(ValueError, match=None): | ^^^^^^^^^^ PT011 -36 | raise ValueError("Can't divide 1 by 0") +43 | raise ValueError("Can't divide 1 by 0") | -PT011.py:38:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:45:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -36 | raise ValueError("Can't divide 1 by 0") -37 | -38 | with pytest.raises(ValueError, match=""): +43 | raise ValueError("Can't divide 1 by 0") +44 | +45 | with pytest.raises(ValueError, match=""): | ^^^^^^^^^^ PT011 -39 | raise ValueError("Can't divide 1 by 0") +46 | raise ValueError("Can't divide 1 by 0") | -PT011.py:41:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:48:24: PT011 `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception | -39 | raise ValueError("Can't divide 1 by 0") -40 | -41 | with pytest.raises(ValueError, match=f""): +46 | raise ValueError("Can't divide 1 by 0") +47 | +48 | with pytest.raises(ValueError, match=f""): | ^^^^^^^^^^ PT011 -42 | raise ValueError("Can't divide 1 by 0") +49 | raise ValueError("Can't divide 1 by 0") | diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_glob_prefix.snap b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_glob_prefix.snap index 418c5d5193671..21162e38df968 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_glob_prefix.snap +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT011_glob_prefix.snap @@ -1,20 +1,20 @@ --- source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs --- -PT011.py:27:24: PT011 `pytest.raises(pickle.PicklingError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:34:24: PT011 `pytest.raises(pickle.PicklingError)` is too broad, set the `match` parameter or use a more specific exception | -25 | raise ValueError("Can't divide 1 by 0") -26 | -27 | with pytest.raises(PicklingError): +32 | raise ValueError("Can't divide 1 by 0") +33 | +34 | with pytest.raises(PicklingError): | ^^^^^^^^^^^^^ PT011 -28 | raise PicklingError("Can't pickle") +35 | raise PicklingError("Can't pickle") | -PT011.py:30:24: PT011 `pytest.raises(pickle.UnpicklingError)` is too broad, set the `match` parameter or use a more specific exception +PT011.py:37:24: PT011 `pytest.raises(pickle.UnpicklingError)` is too broad, set the `match` parameter or use a more specific exception | -28 | raise PicklingError("Can't pickle") -29 | -30 | with pytest.raises(UnpicklingError): +35 | raise PicklingError("Can't pickle") +36 | +37 | with pytest.raises(UnpicklingError): | ^^^^^^^^^^^^^^^ PT011 -31 | raise UnpicklingError("Can't unpickle") +38 | raise UnpicklingError("Can't unpickle") |