mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:04 +00:00
[flake8-pytest-style
] Implement pytest.warns diagnostics (PT029
, PT030
, PT031
) (#15444)
## Summary Implements upstream diagnostics `PT029`, `PT030`, `PT031` that function as pytest.warns corollaries of `PT010`, `PT011`, `PT012` respectively. Most of the implementation and documentation is designed to mirror those existing diagnostics. Closes #14239 ## Test Plan Tests for `PT029`, `PT030`, `PT031` largely copied from `PT010`, `PT011`, `PT012` respectively. `cargo nextest run` --------- Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
parent
fa11b08766
commit
347ab5b47a
20 changed files with 823 additions and 0 deletions
11
crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT029.py
vendored
Normal file
11
crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT029.py
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
import pytest
|
||||
|
||||
|
||||
def test_ok():
|
||||
with pytest.warns():
|
||||
pass
|
||||
|
||||
|
||||
def test_error():
|
||||
with pytest.warns(UserWarning):
|
||||
pass
|
34
crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT030.py
vendored
Normal file
34
crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT030.py
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
import pytest
|
||||
from foo import FooWarning
|
||||
|
||||
|
||||
def test_ok():
|
||||
with pytest.warns(UserWarning, match="Can't divide by 0"):
|
||||
pass
|
||||
|
||||
|
||||
def test_ok_different_error_from_config():
|
||||
with pytest.warns(EncodingWarning):
|
||||
pass
|
||||
|
||||
|
||||
def test_error_no_argument_given():
|
||||
with pytest.warns(UserWarning):
|
||||
pass
|
||||
|
||||
with pytest.warns(expected_warning=UserWarning):
|
||||
pass
|
||||
|
||||
with pytest.warns(FooWarning):
|
||||
pass
|
||||
|
||||
|
||||
def test_error_match_is_empty():
|
||||
with pytest.warns(UserWarning, match=None):
|
||||
pass
|
||||
|
||||
with pytest.warns(UserWarning, match=""):
|
||||
pass
|
||||
|
||||
with pytest.warns(UserWarning, match=f""):
|
||||
pass
|
75
crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT031.py
vendored
Normal file
75
crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT031.py
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
import pytest
|
||||
|
||||
|
||||
def test_ok():
|
||||
with pytest.warns(UserWarning):
|
||||
...
|
||||
|
||||
|
||||
async def test_ok_trivial_with():
|
||||
with pytest.warns(UserWarning):
|
||||
with context_manager_under_test():
|
||||
pass
|
||||
|
||||
with pytest.warns(UserWarning):
|
||||
with context_manager_under_test():
|
||||
foo()
|
||||
|
||||
with pytest.warns(UserWarning):
|
||||
async with context_manager_under_test():
|
||||
pass
|
||||
|
||||
|
||||
def test_ok_complex_single_call():
|
||||
with pytest.warns(UserWarning):
|
||||
foo(
|
||||
"",
|
||||
0,
|
||||
)
|
||||
|
||||
|
||||
def test_ok_func_and_class():
|
||||
with pytest.warns(UserWarning):
|
||||
class Foo:
|
||||
pass
|
||||
|
||||
with pytest.warns(UserWarning):
|
||||
def foo():
|
||||
pass
|
||||
|
||||
|
||||
def test_error_multiple_statements():
|
||||
with pytest.warns(UserWarning):
|
||||
foo()
|
||||
bar()
|
||||
|
||||
|
||||
async def test_error_complex_statement():
|
||||
with pytest.warns(UserWarning):
|
||||
if True:
|
||||
foo()
|
||||
|
||||
with pytest.warns(UserWarning):
|
||||
for i in []:
|
||||
foo()
|
||||
|
||||
with pytest.warns(UserWarning):
|
||||
async for i in []:
|
||||
foo()
|
||||
|
||||
with pytest.warns(UserWarning):
|
||||
while True:
|
||||
foo()
|
||||
|
||||
with pytest.warns(UserWarning):
|
||||
async with context_manager_under_test():
|
||||
if True:
|
||||
foo()
|
||||
|
||||
|
||||
def test_error_try():
|
||||
with pytest.warns(UserWarning):
|
||||
try:
|
||||
foo()
|
||||
except:
|
||||
raise
|
|
@ -915,6 +915,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
]) {
|
||||
flake8_pytest_style::rules::raises_call(checker, call);
|
||||
}
|
||||
if checker.any_enabled(&[Rule::PytestWarnsWithoutWarning, Rule::PytestWarnsTooBroad]) {
|
||||
flake8_pytest_style::rules::warns_call(checker, call);
|
||||
}
|
||||
if checker.enabled(Rule::PytestFailWithoutMessage) {
|
||||
flake8_pytest_style::rules::fail_call(checker, call);
|
||||
}
|
||||
|
|
|
@ -1296,6 +1296,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||
if checker.enabled(Rule::PytestRaisesWithMultipleStatements) {
|
||||
flake8_pytest_style::rules::complex_raises(checker, stmt, items, body);
|
||||
}
|
||||
if checker.enabled(Rule::PytestWarnsWithMultipleStatements) {
|
||||
flake8_pytest_style::rules::complex_warns(checker, stmt, items, body);
|
||||
}
|
||||
if checker.enabled(Rule::MultipleWithStatements) {
|
||||
flake8_simplify::rules::multiple_with_statements(
|
||||
checker,
|
||||
|
|
|
@ -830,6 +830,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||
(Flake8PytestStyle, "025") => (RuleGroup::Stable, rules::flake8_pytest_style::rules::PytestErroneousUseFixturesOnFixture),
|
||||
(Flake8PytestStyle, "026") => (RuleGroup::Stable, rules::flake8_pytest_style::rules::PytestUseFixturesWithoutParameters),
|
||||
(Flake8PytestStyle, "027") => (RuleGroup::Stable, rules::flake8_pytest_style::rules::PytestUnittestRaisesAssertion),
|
||||
(Flake8PytestStyle, "029") => (RuleGroup::Preview, rules::flake8_pytest_style::rules::PytestWarnsWithoutWarning),
|
||||
(Flake8PytestStyle, "030") => (RuleGroup::Preview, rules::flake8_pytest_style::rules::PytestWarnsTooBroad),
|
||||
(Flake8PytestStyle, "031") => (RuleGroup::Preview, rules::flake8_pytest_style::rules::PytestWarnsWithMultipleStatements),
|
||||
|
||||
// flake8-pie
|
||||
(Flake8Pie, "790") => (RuleGroup::Stable, rules::flake8_pie::rules::UnnecessaryPlaceholder),
|
||||
|
|
|
@ -275,6 +275,60 @@ mod tests {
|
|||
Settings::default(),
|
||||
"PT027_1"
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::PytestWarnsWithoutWarning,
|
||||
Path::new("PT029.py"),
|
||||
Settings::default(),
|
||||
"PT029"
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::PytestWarnsTooBroad,
|
||||
Path::new("PT030.py"),
|
||||
Settings::default(),
|
||||
"PT030_default"
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::PytestWarnsTooBroad,
|
||||
Path::new("PT030.py"),
|
||||
Settings {
|
||||
warns_extend_require_match_for: vec![IdentifierPattern::new("EncodingWarning").unwrap()],
|
||||
..Settings::default()
|
||||
},
|
||||
"PT030_extend_broad_exceptions"
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::PytestWarnsTooBroad,
|
||||
Path::new("PT030.py"),
|
||||
Settings {
|
||||
warns_require_match_for: vec![IdentifierPattern::new("EncodingWarning").unwrap()],
|
||||
..Settings::default()
|
||||
},
|
||||
"PT030_replace_broad_exceptions"
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::PytestWarnsTooBroad,
|
||||
Path::new("PT030.py"),
|
||||
Settings {
|
||||
warns_require_match_for: vec![IdentifierPattern::new("*").unwrap()],
|
||||
..Settings::default()
|
||||
},
|
||||
"PT030_glob_all"
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::PytestWarnsTooBroad,
|
||||
Path::new("PT030.py"),
|
||||
Settings {
|
||||
warns_require_match_for: vec![IdentifierPattern::new("foo.*").unwrap()],
|
||||
..Settings::default()
|
||||
},
|
||||
"PT030_glob_prefix"
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::PytestWarnsWithMultipleStatements,
|
||||
Path::new("PT031.py"),
|
||||
Settings::default(),
|
||||
"PT031"
|
||||
)]
|
||||
fn test_pytest_style(
|
||||
rule_code: Rule,
|
||||
path: &Path,
|
||||
|
|
|
@ -6,6 +6,7 @@ pub(crate) use marks::*;
|
|||
pub(crate) use parametrize::*;
|
||||
pub(crate) use patch::*;
|
||||
pub(crate) use raises::*;
|
||||
pub(crate) use warns::*;
|
||||
|
||||
mod assertion;
|
||||
mod fail;
|
||||
|
@ -17,3 +18,4 @@ mod parametrize;
|
|||
mod patch;
|
||||
mod raises;
|
||||
mod unittest_assert;
|
||||
mod warns;
|
||||
|
|
254
crates/ruff_linter/src/rules/flake8_pytest_style/rules/warns.rs
Normal file
254
crates/ruff_linter/src/rules/flake8_pytest_style/rules/warns.rs
Normal file
|
@ -0,0 +1,254 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
use ruff_python_ast::helpers::is_compound_statement;
|
||||
use ruff_python_ast::{self as ast, Expr, Stmt, WithItem};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
||||
use super::helpers::is_empty_or_null_string;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for `pytest.warns` context managers with multiple statements.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// When `pytest.warns` is used as a context manager and contains multiple
|
||||
/// statements, it can lead to the test passing when it should instead fail.
|
||||
///
|
||||
/// A `pytest.warns` context manager should only contain a single
|
||||
/// simple statement that triggers the expected warning.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// import pytest
|
||||
///
|
||||
///
|
||||
/// def test_foo():
|
||||
/// with pytest.warns(MyWarning):
|
||||
/// setup()
|
||||
/// func_to_test() # not executed if `setup()` triggers `MyWarning`
|
||||
/// assert foo() # not executed
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// import pytest
|
||||
///
|
||||
///
|
||||
/// def test_foo():
|
||||
/// setup()
|
||||
/// with pytest.warning(MyWarning):
|
||||
/// func_to_test()
|
||||
/// assert foo()
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [`pytest` documentation: `pytest.warns`](https://docs.pytest.org/en/latest/reference/reference.html#pytest-warns)
|
||||
#[derive(ViolationMetadata)]
|
||||
pub(crate) struct PytestWarnsWithMultipleStatements;
|
||||
|
||||
impl Violation for PytestWarnsWithMultipleStatements {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
"`pytest.warns()` block should contain a single simple statement".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for `pytest.warns` calls without a `match` parameter.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// `pytest.warns(Warning)` will catch any `Warning` and may catch warnings that
|
||||
/// are unrelated to the code under test. To avoid this, `pytest.warns` should
|
||||
/// be called with a `match` parameter. The warning names that require a `match`
|
||||
/// parameter can be configured via the
|
||||
/// [`lint.flake8-pytest-style.warns-require-match-for`] and
|
||||
/// [`lint.flake8-pytest-style.warns-extend-require-match-for`] settings.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// import pytest
|
||||
///
|
||||
///
|
||||
/// def test_foo():
|
||||
/// with pytest.warns(RuntimeWarning):
|
||||
/// ...
|
||||
///
|
||||
/// # empty string is also an error
|
||||
/// with pytest.warns(RuntimeWarning, match=""):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// import pytest
|
||||
///
|
||||
///
|
||||
/// def test_foo():
|
||||
/// with pytest.warns(RuntimeWarning, match="expected message"):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `lint.flake8-pytest-style.warns-require-match-for`
|
||||
/// - `lint.flake8-pytest-style.warns-extend-require-match-for`
|
||||
///
|
||||
/// ## References
|
||||
/// - [`pytest` documentation: `pytest.warns`](https://docs.pytest.org/en/latest/reference/reference.html#pytest-warns)
|
||||
#[derive(ViolationMetadata)]
|
||||
pub(crate) struct PytestWarnsTooBroad {
|
||||
warning: String,
|
||||
}
|
||||
|
||||
impl Violation for PytestWarnsTooBroad {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let PytestWarnsTooBroad { warning } = self;
|
||||
format!(
|
||||
"`pytest.warns({warning})` is too broad, set the `match` parameter or use a more \
|
||||
specific warning"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for `pytest.warns` calls without an expected warning.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// `pytest.warns` expects to receive an expected warning as its first
|
||||
/// argument. If omitted, the `pytest.warns` call will fail at runtime.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// import pytest
|
||||
///
|
||||
///
|
||||
/// def test_foo():
|
||||
/// with pytest.warns():
|
||||
/// do_something()
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// import pytest
|
||||
///
|
||||
///
|
||||
/// def test_foo():
|
||||
/// with pytest.warns(SomeWarning):
|
||||
/// do_something()
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [`pytest` documentation: `pytest.warns`](https://docs.pytest.org/en/latest/reference/reference.html#pytest-warns)
|
||||
#[derive(ViolationMetadata)]
|
||||
pub(crate) struct PytestWarnsWithoutWarning;
|
||||
|
||||
impl Violation for PytestWarnsWithoutWarning {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
"Set the expected warning in `pytest.warns()`".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_pytest_warns(func: &Expr, semantic: &SemanticModel) -> bool {
|
||||
semantic
|
||||
.resolve_qualified_name(func)
|
||||
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["pytest", "warns"]))
|
||||
}
|
||||
|
||||
const fn is_non_trivial_with_body(body: &[Stmt]) -> bool {
|
||||
if let [stmt] = body {
|
||||
is_compound_statement(stmt)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// PT029, PT030
|
||||
pub(crate) fn warns_call(checker: &mut Checker, call: &ast::ExprCall) {
|
||||
if is_pytest_warns(&call.func, checker.semantic()) {
|
||||
if checker.enabled(Rule::PytestWarnsWithoutWarning) {
|
||||
if call.arguments.is_empty() {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PytestWarnsWithoutWarning,
|
||||
call.func.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::PytestWarnsTooBroad) {
|
||||
if let Some(warning) = call.arguments.find_argument_value("expected_warning", 0) {
|
||||
if call
|
||||
.arguments
|
||||
.find_keyword("match")
|
||||
.map_or(true, |k| is_empty_or_null_string(&k.value))
|
||||
{
|
||||
warning_needs_match(checker, warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// PT031
|
||||
pub(crate) fn complex_warns(checker: &mut Checker, stmt: &Stmt, items: &[WithItem], body: &[Stmt]) {
|
||||
let warns_called = items.iter().any(|item| match &item.context_expr {
|
||||
Expr::Call(ast::ExprCall { func, .. }) => is_pytest_warns(func, checker.semantic()),
|
||||
_ => false,
|
||||
});
|
||||
|
||||
// Check body for `pytest.warns` context manager
|
||||
if warns_called {
|
||||
let is_too_complex = if let [stmt] = body {
|
||||
match stmt {
|
||||
Stmt::With(ast::StmtWith { body, .. }) => is_non_trivial_with_body(body),
|
||||
// Allow function and class definitions to test decorators
|
||||
Stmt::ClassDef(_) | Stmt::FunctionDef(_) => false,
|
||||
stmt => is_compound_statement(stmt),
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if is_too_complex {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PytestWarnsWithMultipleStatements,
|
||||
stmt.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// PT030
|
||||
fn warning_needs_match(checker: &mut Checker, warning: &Expr) {
|
||||
if let Some(qualified_name) =
|
||||
checker
|
||||
.semantic()
|
||||
.resolve_qualified_name(warning)
|
||||
.and_then(|qualified_name| {
|
||||
let qualified_name = qualified_name.to_string();
|
||||
checker
|
||||
.settings
|
||||
.flake8_pytest_style
|
||||
.warns_require_match_for
|
||||
.iter()
|
||||
.chain(
|
||||
&checker
|
||||
.settings
|
||||
.flake8_pytest_style
|
||||
.warns_extend_require_match_for,
|
||||
)
|
||||
.any(|pattern| pattern.matches(&qualified_name))
|
||||
.then_some(qualified_name)
|
||||
})
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PytestWarnsTooBroad {
|
||||
warning: qualified_name,
|
||||
},
|
||||
warning.range(),
|
||||
));
|
||||
}
|
||||
}
|
|
@ -24,6 +24,12 @@ pub fn default_broad_exceptions() -> Vec<IdentifierPattern> {
|
|||
.to_vec()
|
||||
}
|
||||
|
||||
pub fn default_broad_warnings() -> Vec<IdentifierPattern> {
|
||||
["Warning", "UserWarning", "DeprecationWarning"]
|
||||
.map(|pattern| IdentifierPattern::new(pattern).expect("invalid default warning pattern"))
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub fixture_parentheses: bool,
|
||||
|
@ -33,6 +39,8 @@ pub struct Settings {
|
|||
pub raises_require_match_for: Vec<IdentifierPattern>,
|
||||
pub raises_extend_require_match_for: Vec<IdentifierPattern>,
|
||||
pub mark_parentheses: bool,
|
||||
pub warns_require_match_for: Vec<IdentifierPattern>,
|
||||
pub warns_extend_require_match_for: Vec<IdentifierPattern>,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
|
@ -45,6 +53,8 @@ impl Default for Settings {
|
|||
raises_require_match_for: default_broad_exceptions(),
|
||||
raises_extend_require_match_for: vec![],
|
||||
mark_parentheses: false,
|
||||
warns_require_match_for: default_broad_warnings(),
|
||||
warns_extend_require_match_for: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +83,8 @@ impl fmt::Display for Settings {
|
|||
pub enum SettingsError {
|
||||
InvalidRaisesRequireMatchFor(glob::PatternError),
|
||||
InvalidRaisesExtendRequireMatchFor(glob::PatternError),
|
||||
InvalidWarnsRequireMatchFor(glob::PatternError),
|
||||
InvalidWarnsExtendRequireMatchFor(glob::PatternError),
|
||||
}
|
||||
|
||||
impl fmt::Display for SettingsError {
|
||||
|
@ -84,6 +96,12 @@ impl fmt::Display for SettingsError {
|
|||
SettingsError::InvalidRaisesExtendRequireMatchFor(err) => {
|
||||
write!(f, "invalid raises-extend-require-match-for pattern: {err}")
|
||||
}
|
||||
SettingsError::InvalidWarnsRequireMatchFor(err) => {
|
||||
write!(f, "invalid warns-require-match-for pattern: {err}")
|
||||
}
|
||||
SettingsError::InvalidWarnsExtendRequireMatchFor(err) => {
|
||||
write!(f, "invalid warns-extend-require-match-for pattern: {err}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +111,8 @@ impl Error for SettingsError {
|
|||
match self {
|
||||
SettingsError::InvalidRaisesRequireMatchFor(err) => Some(err),
|
||||
SettingsError::InvalidRaisesExtendRequireMatchFor(err) => Some(err),
|
||||
SettingsError::InvalidWarnsRequireMatchFor(err) => Some(err),
|
||||
SettingsError::InvalidWarnsExtendRequireMatchFor(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT029.py:5:10: PT029 Set the expected warning in `pytest.warns()`
|
||||
|
|
||||
4 | def test_ok():
|
||||
5 | with pytest.warns():
|
||||
| ^^^^^^^^^^^^ PT029
|
||||
6 | pass
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
PT030.py:16:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
15 | def test_error_no_argument_given():
|
||||
16 | with pytest.warns(UserWarning):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
17 | pass
|
||||
|
|
||||
|
||||
PT030.py:19:40: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
17 | pass
|
||||
18 |
|
||||
19 | with pytest.warns(expected_warning=UserWarning):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
20 | pass
|
||||
|
|
||||
|
||||
PT030.py:27:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
26 | def test_error_match_is_empty():
|
||||
27 | with pytest.warns(UserWarning, match=None):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
28 | pass
|
||||
|
|
||||
|
||||
PT030.py:30:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
28 | pass
|
||||
29 |
|
||||
30 | with pytest.warns(UserWarning, match=""):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
31 | pass
|
||||
|
|
||||
|
||||
PT030.py:33:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
31 | pass
|
||||
32 |
|
||||
33 | with pytest.warns(UserWarning, match=f""):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
34 | pass
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
PT030.py:11:23: PT030 `pytest.warns(EncodingWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
10 | def test_ok_different_error_from_config():
|
||||
11 | with pytest.warns(EncodingWarning):
|
||||
| ^^^^^^^^^^^^^^^ PT030
|
||||
12 | pass
|
||||
|
|
||||
|
||||
PT030.py:16:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
15 | def test_error_no_argument_given():
|
||||
16 | with pytest.warns(UserWarning):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
17 | pass
|
||||
|
|
||||
|
||||
PT030.py:19:40: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
17 | pass
|
||||
18 |
|
||||
19 | with pytest.warns(expected_warning=UserWarning):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
20 | pass
|
||||
|
|
||||
|
||||
PT030.py:27:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
26 | def test_error_match_is_empty():
|
||||
27 | with pytest.warns(UserWarning, match=None):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
28 | pass
|
||||
|
|
||||
|
||||
PT030.py:30:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
28 | pass
|
||||
29 |
|
||||
30 | with pytest.warns(UserWarning, match=""):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
31 | pass
|
||||
|
|
||||
|
||||
PT030.py:33:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
31 | pass
|
||||
32 |
|
||||
33 | with pytest.warns(UserWarning, match=f""):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
34 | pass
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
PT030.py:11:23: PT030 `pytest.warns(EncodingWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
10 | def test_ok_different_error_from_config():
|
||||
11 | with pytest.warns(EncodingWarning):
|
||||
| ^^^^^^^^^^^^^^^ PT030
|
||||
12 | pass
|
||||
|
|
||||
|
||||
PT030.py:16:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
15 | def test_error_no_argument_given():
|
||||
16 | with pytest.warns(UserWarning):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
17 | pass
|
||||
|
|
||||
|
||||
PT030.py:19:40: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
17 | pass
|
||||
18 |
|
||||
19 | with pytest.warns(expected_warning=UserWarning):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
20 | pass
|
||||
|
|
||||
|
||||
PT030.py:22:23: PT030 `pytest.warns(foo.FooWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
20 | pass
|
||||
21 |
|
||||
22 | with pytest.warns(FooWarning):
|
||||
| ^^^^^^^^^^ PT030
|
||||
23 | pass
|
||||
|
|
||||
|
||||
PT030.py:27:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
26 | def test_error_match_is_empty():
|
||||
27 | with pytest.warns(UserWarning, match=None):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
28 | pass
|
||||
|
|
||||
|
||||
PT030.py:30:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
28 | pass
|
||||
29 |
|
||||
30 | with pytest.warns(UserWarning, match=""):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
31 | pass
|
||||
|
|
||||
|
||||
PT030.py:33:23: PT030 `pytest.warns(UserWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
31 | pass
|
||||
32 |
|
||||
33 | with pytest.warns(UserWarning, match=f""):
|
||||
| ^^^^^^^^^^^ PT030
|
||||
34 | pass
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
PT030.py:22:23: PT030 `pytest.warns(foo.FooWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
20 | pass
|
||||
21 |
|
||||
22 | with pytest.warns(FooWarning):
|
||||
| ^^^^^^^^^^ PT030
|
||||
23 | pass
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
PT030.py:11:23: PT030 `pytest.warns(EncodingWarning)` is too broad, set the `match` parameter or use a more specific warning
|
||||
|
|
||||
10 | def test_ok_different_error_from_config():
|
||||
11 | with pytest.warns(EncodingWarning):
|
||||
| ^^^^^^^^^^^^^^^ PT030
|
||||
12 | pass
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
PT031.py:42:5: PT031 `pytest.warns()` block should contain a single simple statement
|
||||
|
|
||||
41 | def test_error_multiple_statements():
|
||||
42 | with pytest.warns(UserWarning):
|
||||
| _____^
|
||||
43 | | foo()
|
||||
44 | | bar()
|
||||
| |_____________^ PT031
|
||||
|
|
||||
|
||||
PT031.py:48:5: PT031 `pytest.warns()` block should contain a single simple statement
|
||||
|
|
||||
47 | async def test_error_complex_statement():
|
||||
48 | with pytest.warns(UserWarning):
|
||||
| _____^
|
||||
49 | | if True:
|
||||
50 | | foo()
|
||||
| |_________________^ PT031
|
||||
51 |
|
||||
52 | with pytest.warns(UserWarning):
|
||||
|
|
||||
|
||||
PT031.py:52:5: PT031 `pytest.warns()` block should contain a single simple statement
|
||||
|
|
||||
50 | foo()
|
||||
51 |
|
||||
52 | with pytest.warns(UserWarning):
|
||||
| _____^
|
||||
53 | | for i in []:
|
||||
54 | | foo()
|
||||
| |_________________^ PT031
|
||||
55 |
|
||||
56 | with pytest.warns(UserWarning):
|
||||
|
|
||||
|
||||
PT031.py:56:5: PT031 `pytest.warns()` block should contain a single simple statement
|
||||
|
|
||||
54 | foo()
|
||||
55 |
|
||||
56 | with pytest.warns(UserWarning):
|
||||
| _____^
|
||||
57 | | async for i in []:
|
||||
58 | | foo()
|
||||
| |_________________^ PT031
|
||||
59 |
|
||||
60 | with pytest.warns(UserWarning):
|
||||
|
|
||||
|
||||
PT031.py:60:5: PT031 `pytest.warns()` block should contain a single simple statement
|
||||
|
|
||||
58 | foo()
|
||||
59 |
|
||||
60 | with pytest.warns(UserWarning):
|
||||
| _____^
|
||||
61 | | while True:
|
||||
62 | | foo()
|
||||
| |_________________^ PT031
|
||||
63 |
|
||||
64 | with pytest.warns(UserWarning):
|
||||
|
|
||||
|
||||
PT031.py:64:5: PT031 `pytest.warns()` block should contain a single simple statement
|
||||
|
|
||||
62 | foo()
|
||||
63 |
|
||||
64 | with pytest.warns(UserWarning):
|
||||
| _____^
|
||||
65 | | async with context_manager_under_test():
|
||||
66 | | if True:
|
||||
67 | | foo()
|
||||
| |_____________________^ PT031
|
||||
|
|
||||
|
||||
PT031.py:71:5: PT031 `pytest.warns()` block should contain a single simple statement
|
||||
|
|
||||
70 | def test_error_try():
|
||||
71 | with pytest.warns(UserWarning):
|
||||
| _____^
|
||||
72 | | try:
|
||||
73 | | foo()
|
||||
74 | | except:
|
||||
75 | | raise
|
||||
| |_________________^ PT031
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue