From 7d9728b6ac6a8343afd5a204c7eb9fc2b71a5da1 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 12 Jan 2024 13:36:20 -0500 Subject: [PATCH] Limit inplace diagnostics to methods that accept inplace --- .../test/fixtures/pandas_vet/PD002.py | 3 ++ .../pandas_vet/rules/inplace_argument.rs | 41 +++++++++++++++++++ ...es__pandas_vet__tests__PD002_PD002.py.snap | 5 +++ 3 files changed, 49 insertions(+) diff --git a/crates/ruff_linter/resources/test/fixtures/pandas_vet/PD002.py b/crates/ruff_linter/resources/test/fixtures/pandas_vet/PD002.py index 70424437c36df..6ed910cd14efd 100644 --- a/crates/ruff_linter/resources/test/fixtures/pandas_vet/PD002.py +++ b/crates/ruff_linter/resources/test/fixtures/pandas_vet/PD002.py @@ -31,3 +31,6 @@ torch.m.ReLU(inplace=True) # safe because this isn't a pandas call (x.drop(["a"], axis=1, inplace=True)) + +# This method doesn't take exist in Pandas, so ignore it. +x.rotate_z(45, inplace=True) diff --git a/crates/ruff_linter/src/rules/pandas_vet/rules/inplace_argument.rs b/crates/ruff_linter/src/rules/pandas_vet/rules/inplace_argument.rs index f4924b0a6653d..656cb3e92d836 100644 --- a/crates/ruff_linter/src/rules/pandas_vet/rules/inplace_argument.rs +++ b/crates/ruff_linter/src/rules/pandas_vet/rules/inplace_argument.rs @@ -61,6 +61,15 @@ pub(crate) fn inplace_argument(checker: &mut Checker, call: &ast::ExprCall) { return; } + // If the function doesn't take an `inplace` argument, abort. + if !call + .func + .as_attribute_expr() + .is_some_and(|func| accepts_inplace_argument(&func.attr)) + { + return; + } + let mut seen_star = false; for keyword in call.arguments.keywords.iter().rev() { let Some(arg) = &keyword.arg else { @@ -134,3 +143,35 @@ fn convert_inplace_argument_to_assignment( Some(Fix::unsafe_edits(insert_assignment, [remove_argument])) } + +/// Returns `true` if the given method accepts an `inplace` argument when used on a Pandas +/// `DataFrame`, `Series`, or `Index`. +/// +/// See: +fn accepts_inplace_argument(method: &str) -> bool { + matches!( + method, + "where" + | "mask" + | "query" + | "clip" + | "eval" + | "backfill" + | "bfill" + | "ffill" + | "fillna" + | "interpolate" + | "dropna" + | "pad" + | "replace" + | "drop" + | "drop_duplicates" + | "rename" + | "rename_axis" + | "reset_index" + | "set_index" + | "sort_values" + | "sort_index" + | "set_names" + ) +} diff --git a/crates/ruff_linter/src/rules/pandas_vet/snapshots/ruff_linter__rules__pandas_vet__tests__PD002_PD002.py.snap b/crates/ruff_linter/src/rules/pandas_vet/snapshots/ruff_linter__rules__pandas_vet__tests__PD002_PD002.py.snap index e1c17dabed9dd..4b95a1c29a686 100644 --- a/crates/ruff_linter/src/rules/pandas_vet/snapshots/ruff_linter__rules__pandas_vet__tests__PD002_PD002.py.snap +++ b/crates/ruff_linter/src/rules/pandas_vet/snapshots/ruff_linter__rules__pandas_vet__tests__PD002_PD002.py.snap @@ -164,6 +164,8 @@ PD002.py:33:24: PD002 [*] `inplace=True` should be avoided; it has inconsistent 32 | 33 | (x.drop(["a"], axis=1, inplace=True)) | ^^^^^^^^^^^^ PD002 +34 | +35 | # This method doesn't take exist in Pandas, so ignore it. | = help: Assign to variable; remove `inplace` arg @@ -173,5 +175,8 @@ PD002.py:33:24: PD002 [*] `inplace=True` should be avoided; it has inconsistent 32 32 | 33 |-(x.drop(["a"], axis=1, inplace=True)) 33 |+x = (x.drop(["a"], axis=1)) +34 34 | +35 35 | # This method doesn't take exist in Pandas, so ignore it. +36 36 | x.rotate_z(45, inplace=True)