[pygrep_hooks] Stabilize usingAsyncMock methods in invalid-mock-access (PGH005) (#20272)

Introduced in #18547. Removed gating, updated tests. Not documented so
documentation is the same.
This commit is contained in:
Dylan 2025-09-08 08:56:52 -05:00 committed by Brent Westbrook
parent 512395f4e6
commit aef0a107a8
5 changed files with 129 additions and 258 deletions

View file

@ -200,11 +200,6 @@ pub(crate) const fn is_optional_as_none_in_union_enabled(settings: &LinterSettin
settings.preview.is_enabled() settings.preview.is_enabled()
} }
// https://github.com/astral-sh/ruff/pull/18547
pub(crate) const fn is_invalid_async_mock_access_check_enabled(settings: &LinterSettings) -> bool {
settings.preview.is_enabled()
}
// https://github.com/astral-sh/ruff/pull/18867 // https://github.com/astral-sh/ruff/pull/18867
pub(crate) const fn is_raise_exception_byte_string_enabled(settings: &LinterSettings) -> bool { pub(crate) const fn is_raise_exception_byte_string_enabled(settings: &LinterSettings) -> bool {
settings.preview.is_enabled() settings.preview.is_enabled()

View file

@ -10,7 +10,6 @@ mod tests {
use crate::registry::Rule; use crate::registry::Rule;
use crate::settings::types::PreviewMode;
use crate::test::test_path; use crate::test::test_path;
use crate::{assert_diagnostics, settings}; use crate::{assert_diagnostics, settings};
@ -30,22 +29,4 @@ mod tests {
assert_diagnostics!(snapshot, diagnostics); assert_diagnostics!(snapshot, diagnostics);
Ok(()) Ok(())
} }
#[test_case(Rule::InvalidMockAccess, Path::new("PGH005_0.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("pygrep_hooks").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_diagnostics!(snapshot, diagnostics);
Ok(())
}
} }

View file

@ -5,7 +5,6 @@ use ruff_text_size::Ranged;
use crate::Violation; use crate::Violation;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::preview::is_invalid_async_mock_access_check_enabled;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
enum Reason { enum Reason {
@ -62,18 +61,16 @@ pub(crate) fn uncalled_mock_method(checker: &Checker, expr: &Expr) {
| "assert_has_calls" | "assert_has_calls"
| "assert_not_called" | "assert_not_called"
); );
let is_uncalled_async_mock_method = let is_uncalled_async_mock_method = matches!(
is_invalid_async_mock_access_check_enabled(checker.settings()) attr.as_str(),
&& matches!( "assert_awaited"
attr.as_str(), | "assert_awaited_once"
"assert_awaited" | "assert_awaited_with"
| "assert_awaited_once" | "assert_awaited_once_with"
| "assert_awaited_with" | "assert_any_await"
| "assert_awaited_once_with" | "assert_has_awaits"
| "assert_any_await" | "assert_not_awaited"
| "assert_has_awaits" );
| "assert_not_awaited"
);
if is_uncalled_mock_method || is_uncalled_async_mock_method { if is_uncalled_mock_method || is_uncalled_async_mock_method {
checker.report_diagnostic( checker.report_diagnostic(
InvalidMockAccess { InvalidMockAccess {
@ -104,18 +101,16 @@ pub(crate) fn non_existent_mock_method(checker: &Checker, test: &Expr) {
| "has_calls" | "has_calls"
| "not_called" | "not_called"
); );
let is_missing_async_mock_method = let is_missing_async_mock_method = matches!(
is_invalid_async_mock_access_check_enabled(checker.settings()) attr.as_str(),
&& matches!( "awaited"
attr.as_str(), | "awaited_once"
"awaited" | "awaited_with"
| "awaited_once" | "awaited_once_with"
| "awaited_with" | "any_await"
| "awaited_once_with" | "has_awaits"
| "any_await" | "not_awaited"
| "has_awaits" );
| "not_awaited"
);
if is_missing_mock_method || is_missing_async_mock_method { if is_missing_mock_method || is_missing_async_mock_method {
checker.report_diagnostic( checker.report_diagnostic(
InvalidMockAccess { InvalidMockAccess {

View file

@ -98,3 +98,112 @@ PGH005 Mock method should be called: `assert_called_once_with`
13 | 13 |
14 | # OK 14 | # OK
| |
PGH005 Non-existent mock method: `not_awaited`
--> PGH005_0.py:26:8
|
24 | # =================
25 | # Errors
26 | assert my_mock.not_awaited()
| ^^^^^^^^^^^^^^^^^^^^^
27 | assert my_mock.awaited_once_with()
28 | assert my_mock.not_awaited
|
PGH005 Non-existent mock method: `awaited_once_with`
--> PGH005_0.py:27:8
|
25 | # Errors
26 | assert my_mock.not_awaited()
27 | assert my_mock.awaited_once_with()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
28 | assert my_mock.not_awaited
29 | assert my_mock.awaited_once_with
|
PGH005 Non-existent mock method: `not_awaited`
--> PGH005_0.py:28:8
|
26 | assert my_mock.not_awaited()
27 | assert my_mock.awaited_once_with()
28 | assert my_mock.not_awaited
| ^^^^^^^^^^^^^^^^^^^
29 | assert my_mock.awaited_once_with
30 | my_mock.assert_not_awaited
|
PGH005 Non-existent mock method: `awaited_once_with`
--> PGH005_0.py:29:8
|
27 | assert my_mock.awaited_once_with()
28 | assert my_mock.not_awaited
29 | assert my_mock.awaited_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^
30 | my_mock.assert_not_awaited
31 | my_mock.assert_awaited
|
PGH005 Mock method should be called: `assert_not_awaited`
--> PGH005_0.py:30:1
|
28 | assert my_mock.not_awaited
29 | assert my_mock.awaited_once_with
30 | my_mock.assert_not_awaited
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
31 | my_mock.assert_awaited
32 | my_mock.assert_awaited_once_with
|
PGH005 Mock method should be called: `assert_awaited`
--> PGH005_0.py:31:1
|
29 | assert my_mock.awaited_once_with
30 | my_mock.assert_not_awaited
31 | my_mock.assert_awaited
| ^^^^^^^^^^^^^^^^^^^^^^
32 | my_mock.assert_awaited_once_with
33 | my_mock.assert_awaited_once_with
|
PGH005 Mock method should be called: `assert_awaited_once_with`
--> PGH005_0.py:32:1
|
30 | my_mock.assert_not_awaited
31 | my_mock.assert_awaited
32 | my_mock.assert_awaited_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33 | my_mock.assert_awaited_once_with
34 | MyMock.assert_awaited_once_with
|
PGH005 Mock method should be called: `assert_awaited_once_with`
--> PGH005_0.py:33:1
|
31 | my_mock.assert_awaited
32 | my_mock.assert_awaited_once_with
33 | my_mock.assert_awaited_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34 | MyMock.assert_awaited_once_with
35 | assert my_mock.awaited
|
PGH005 Mock method should be called: `assert_awaited_once_with`
--> PGH005_0.py:34:1
|
32 | my_mock.assert_awaited_once_with
33 | my_mock.assert_awaited_once_with
34 | MyMock.assert_awaited_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35 | assert my_mock.awaited
|
PGH005 Non-existent mock method: `awaited`
--> PGH005_0.py:35:8
|
33 | my_mock.assert_awaited_once_with
34 | MyMock.assert_awaited_once_with
35 | assert my_mock.awaited
| ^^^^^^^^^^^^^^^
36 |
37 | # OK
|

View file

@ -1,209 +0,0 @@
---
source: crates/ruff_linter/src/rules/pygrep_hooks/mod.rs
---
PGH005 Non-existent mock method: `not_called`
--> PGH005_0.py:4:8
|
2 | # ============
3 | # Errors
4 | assert my_mock.not_called()
| ^^^^^^^^^^^^^^^^^^^^
5 | assert my_mock.called_once_with()
6 | assert my_mock.not_called
|
PGH005 Non-existent mock method: `called_once_with`
--> PGH005_0.py:5:8
|
3 | # Errors
4 | assert my_mock.not_called()
5 | assert my_mock.called_once_with()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
6 | assert my_mock.not_called
7 | assert my_mock.called_once_with
|
PGH005 Non-existent mock method: `not_called`
--> PGH005_0.py:6:8
|
4 | assert my_mock.not_called()
5 | assert my_mock.called_once_with()
6 | assert my_mock.not_called
| ^^^^^^^^^^^^^^^^^^
7 | assert my_mock.called_once_with
8 | my_mock.assert_not_called
|
PGH005 Non-existent mock method: `called_once_with`
--> PGH005_0.py:7:8
|
5 | assert my_mock.called_once_with()
6 | assert my_mock.not_called
7 | assert my_mock.called_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^
8 | my_mock.assert_not_called
9 | my_mock.assert_called
|
PGH005 Mock method should be called: `assert_not_called`
--> PGH005_0.py:8:1
|
6 | assert my_mock.not_called
7 | assert my_mock.called_once_with
8 | my_mock.assert_not_called
| ^^^^^^^^^^^^^^^^^^^^^^^^^
9 | my_mock.assert_called
10 | my_mock.assert_called_once_with
|
PGH005 Mock method should be called: `assert_called`
--> PGH005_0.py:9:1
|
7 | assert my_mock.called_once_with
8 | my_mock.assert_not_called
9 | my_mock.assert_called
| ^^^^^^^^^^^^^^^^^^^^^
10 | my_mock.assert_called_once_with
11 | my_mock.assert_called_once_with
|
PGH005 Mock method should be called: `assert_called_once_with`
--> PGH005_0.py:10:1
|
8 | my_mock.assert_not_called
9 | my_mock.assert_called
10 | my_mock.assert_called_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11 | my_mock.assert_called_once_with
12 | MyMock.assert_called_once_with
|
PGH005 Mock method should be called: `assert_called_once_with`
--> PGH005_0.py:11:1
|
9 | my_mock.assert_called
10 | my_mock.assert_called_once_with
11 | my_mock.assert_called_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12 | MyMock.assert_called_once_with
|
PGH005 Mock method should be called: `assert_called_once_with`
--> PGH005_0.py:12:1
|
10 | my_mock.assert_called_once_with
11 | my_mock.assert_called_once_with
12 | MyMock.assert_called_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13 |
14 | # OK
|
PGH005 Non-existent mock method: `not_awaited`
--> PGH005_0.py:26:8
|
24 | # =================
25 | # Errors
26 | assert my_mock.not_awaited()
| ^^^^^^^^^^^^^^^^^^^^^
27 | assert my_mock.awaited_once_with()
28 | assert my_mock.not_awaited
|
PGH005 Non-existent mock method: `awaited_once_with`
--> PGH005_0.py:27:8
|
25 | # Errors
26 | assert my_mock.not_awaited()
27 | assert my_mock.awaited_once_with()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
28 | assert my_mock.not_awaited
29 | assert my_mock.awaited_once_with
|
PGH005 Non-existent mock method: `not_awaited`
--> PGH005_0.py:28:8
|
26 | assert my_mock.not_awaited()
27 | assert my_mock.awaited_once_with()
28 | assert my_mock.not_awaited
| ^^^^^^^^^^^^^^^^^^^
29 | assert my_mock.awaited_once_with
30 | my_mock.assert_not_awaited
|
PGH005 Non-existent mock method: `awaited_once_with`
--> PGH005_0.py:29:8
|
27 | assert my_mock.awaited_once_with()
28 | assert my_mock.not_awaited
29 | assert my_mock.awaited_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^
30 | my_mock.assert_not_awaited
31 | my_mock.assert_awaited
|
PGH005 Mock method should be called: `assert_not_awaited`
--> PGH005_0.py:30:1
|
28 | assert my_mock.not_awaited
29 | assert my_mock.awaited_once_with
30 | my_mock.assert_not_awaited
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
31 | my_mock.assert_awaited
32 | my_mock.assert_awaited_once_with
|
PGH005 Mock method should be called: `assert_awaited`
--> PGH005_0.py:31:1
|
29 | assert my_mock.awaited_once_with
30 | my_mock.assert_not_awaited
31 | my_mock.assert_awaited
| ^^^^^^^^^^^^^^^^^^^^^^
32 | my_mock.assert_awaited_once_with
33 | my_mock.assert_awaited_once_with
|
PGH005 Mock method should be called: `assert_awaited_once_with`
--> PGH005_0.py:32:1
|
30 | my_mock.assert_not_awaited
31 | my_mock.assert_awaited
32 | my_mock.assert_awaited_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33 | my_mock.assert_awaited_once_with
34 | MyMock.assert_awaited_once_with
|
PGH005 Mock method should be called: `assert_awaited_once_with`
--> PGH005_0.py:33:1
|
31 | my_mock.assert_awaited
32 | my_mock.assert_awaited_once_with
33 | my_mock.assert_awaited_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34 | MyMock.assert_awaited_once_with
35 | assert my_mock.awaited
|
PGH005 Mock method should be called: `assert_awaited_once_with`
--> PGH005_0.py:34:1
|
32 | my_mock.assert_awaited_once_with
33 | my_mock.assert_awaited_once_with
34 | MyMock.assert_awaited_once_with
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35 | assert my_mock.awaited
|
PGH005 Non-existent mock method: `awaited`
--> PGH005_0.py:35:8
|
33 | my_mock.assert_awaited_once_with
34 | MyMock.assert_awaited_once_with
35 | assert my_mock.awaited
| ^^^^^^^^^^^^^^^
36 |
37 | # OK
|