From aef0a107a86dfff6ed1bd0653418f99aee7baa52 Mon Sep 17 00:00:00 2001 From: Dylan Date: Mon, 8 Sep 2025 08:56:52 -0500 Subject: [PATCH] [`pygrep_hooks`] Stabilize using`AsyncMock` methods in `invalid-mock-access` (`PGH005`) (#20272) Introduced in #18547. Removed gating, updated tests. Not documented so documentation is the same. --- crates/ruff_linter/src/preview.rs | 5 - .../ruff_linter/src/rules/pygrep_hooks/mod.rs | 19 -- .../pygrep_hooks/rules/invalid_mock_access.rs | 45 ++-- ...grep_hooks__tests__PGH005_PGH005_0.py.snap | 109 +++++++++ ...s__tests__preview__PGH005_PGH005_0.py.snap | 209 ------------------ 5 files changed, 129 insertions(+), 258 deletions(-) delete mode 100644 crates/ruff_linter/src/rules/pygrep_hooks/snapshots/ruff_linter__rules__pygrep_hooks__tests__preview__PGH005_PGH005_0.py.snap diff --git a/crates/ruff_linter/src/preview.rs b/crates/ruff_linter/src/preview.rs index 3eeed95e27..20310c8dda 100644 --- a/crates/ruff_linter/src/preview.rs +++ b/crates/ruff_linter/src/preview.rs @@ -200,11 +200,6 @@ pub(crate) const fn is_optional_as_none_in_union_enabled(settings: &LinterSettin 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 pub(crate) const fn is_raise_exception_byte_string_enabled(settings: &LinterSettings) -> bool { settings.preview.is_enabled() diff --git a/crates/ruff_linter/src/rules/pygrep_hooks/mod.rs b/crates/ruff_linter/src/rules/pygrep_hooks/mod.rs index 1117bb516a..525a3ff0be 100644 --- a/crates/ruff_linter/src/rules/pygrep_hooks/mod.rs +++ b/crates/ruff_linter/src/rules/pygrep_hooks/mod.rs @@ -10,7 +10,6 @@ mod tests { use crate::registry::Rule; - use crate::settings::types::PreviewMode; use crate::test::test_path; use crate::{assert_diagnostics, settings}; @@ -30,22 +29,4 @@ mod tests { assert_diagnostics!(snapshot, diagnostics); 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(()) - } } diff --git a/crates/ruff_linter/src/rules/pygrep_hooks/rules/invalid_mock_access.rs b/crates/ruff_linter/src/rules/pygrep_hooks/rules/invalid_mock_access.rs index 9ff519116d..ec33040df1 100644 --- a/crates/ruff_linter/src/rules/pygrep_hooks/rules/invalid_mock_access.rs +++ b/crates/ruff_linter/src/rules/pygrep_hooks/rules/invalid_mock_access.rs @@ -5,7 +5,6 @@ use ruff_text_size::Ranged; use crate::Violation; use crate::checkers::ast::Checker; -use crate::preview::is_invalid_async_mock_access_check_enabled; #[derive(Debug, PartialEq, Eq)] enum Reason { @@ -62,18 +61,16 @@ pub(crate) fn uncalled_mock_method(checker: &Checker, expr: &Expr) { | "assert_has_calls" | "assert_not_called" ); - let is_uncalled_async_mock_method = - is_invalid_async_mock_access_check_enabled(checker.settings()) - && matches!( - attr.as_str(), - "assert_awaited" - | "assert_awaited_once" - | "assert_awaited_with" - | "assert_awaited_once_with" - | "assert_any_await" - | "assert_has_awaits" - | "assert_not_awaited" - ); + let is_uncalled_async_mock_method = matches!( + attr.as_str(), + "assert_awaited" + | "assert_awaited_once" + | "assert_awaited_with" + | "assert_awaited_once_with" + | "assert_any_await" + | "assert_has_awaits" + | "assert_not_awaited" + ); if is_uncalled_mock_method || is_uncalled_async_mock_method { checker.report_diagnostic( InvalidMockAccess { @@ -104,18 +101,16 @@ pub(crate) fn non_existent_mock_method(checker: &Checker, test: &Expr) { | "has_calls" | "not_called" ); - let is_missing_async_mock_method = - is_invalid_async_mock_access_check_enabled(checker.settings()) - && matches!( - attr.as_str(), - "awaited" - | "awaited_once" - | "awaited_with" - | "awaited_once_with" - | "any_await" - | "has_awaits" - | "not_awaited" - ); + let is_missing_async_mock_method = matches!( + attr.as_str(), + "awaited" + | "awaited_once" + | "awaited_with" + | "awaited_once_with" + | "any_await" + | "has_awaits" + | "not_awaited" + ); if is_missing_mock_method || is_missing_async_mock_method { checker.report_diagnostic( InvalidMockAccess { diff --git a/crates/ruff_linter/src/rules/pygrep_hooks/snapshots/ruff_linter__rules__pygrep_hooks__tests__PGH005_PGH005_0.py.snap b/crates/ruff_linter/src/rules/pygrep_hooks/snapshots/ruff_linter__rules__pygrep_hooks__tests__PGH005_PGH005_0.py.snap index 651f26d344..664573f70b 100644 --- a/crates/ruff_linter/src/rules/pygrep_hooks/snapshots/ruff_linter__rules__pygrep_hooks__tests__PGH005_PGH005_0.py.snap +++ b/crates/ruff_linter/src/rules/pygrep_hooks/snapshots/ruff_linter__rules__pygrep_hooks__tests__PGH005_PGH005_0.py.snap @@ -98,3 +98,112 @@ PGH005 Mock method should be called: `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 + | diff --git a/crates/ruff_linter/src/rules/pygrep_hooks/snapshots/ruff_linter__rules__pygrep_hooks__tests__preview__PGH005_PGH005_0.py.snap b/crates/ruff_linter/src/rules/pygrep_hooks/snapshots/ruff_linter__rules__pygrep_hooks__tests__preview__PGH005_PGH005_0.py.snap deleted file mode 100644 index 664573f70b..0000000000 --- a/crates/ruff_linter/src/rules/pygrep_hooks/snapshots/ruff_linter__rules__pygrep_hooks__tests__preview__PGH005_PGH005_0.py.snap +++ /dev/null @@ -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 - |