diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP022.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP022.py index c5ccb93107..e93901bde1 100644 --- a/crates/ruff/resources/test/fixtures/pyupgrade/UP022.py +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP022.py @@ -35,6 +35,13 @@ if output: encoding="utf-8", ) +output = subprocess.run( + ["foo"], stdout=subprocess.PIPE, capture_output=True, stderr=subprocess.PIPE +) + +output = subprocess.run( + ["foo"], stdout=subprocess.PIPE, capture_output=False, stderr=subprocess.PIPE +) # Examples that should NOT trigger the rule from foo import PIPE diff --git a/crates/ruff/src/rules/pyupgrade/rules/replace_stdout_stderr.rs b/crates/ruff/src/rules/pyupgrade/rules/replace_stdout_stderr.rs index 86094b21fb..11c3591144 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/replace_stdout_stderr.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/replace_stdout_stderr.rs @@ -50,29 +50,6 @@ impl AlwaysAutofixableViolation for ReplaceStdoutStderr { } } -/// Generate a [`Edit`] for a `stdout` and `stderr` [`Keyword`] pair. -fn generate_fix( - stdout: &Keyword, - stderr: &Keyword, - call: &ast::ExprCall, - source: &str, -) -> Result { - let (first, second) = if stdout.start() < stderr.start() { - (stdout, stderr) - } else { - (stderr, stdout) - }; - Ok(Fix::suggested_edits( - Edit::range_replacement("capture_output=True".to_string(), first.range()), - [remove_argument( - second, - &call.arguments, - Parentheses::Preserve, - source, - )?], - )) -} - /// UP022 pub(crate) fn replace_stdout_stderr(checker: &mut Checker, call: &ast::ExprCall) { if checker @@ -109,3 +86,41 @@ pub(crate) fn replace_stdout_stderr(checker: &mut Checker, call: &ast::ExprCall) checker.diagnostics.push(diagnostic); } } + +/// Generate a [`Edit`] for a `stdout` and `stderr` [`Keyword`] pair. +fn generate_fix( + stdout: &Keyword, + stderr: &Keyword, + call: &ast::ExprCall, + source: &str, +) -> Result { + let (first, second) = if stdout.start() < stderr.start() { + (stdout, stderr) + } else { + (stderr, stdout) + }; + + if call.arguments.find_keyword("capture_output").is_some() { + // Remove both arguments. + Ok(Fix::suggested_edits( + remove_argument(first, &call.arguments, Parentheses::Preserve, source)?, + [remove_argument( + second, + &call.arguments, + Parentheses::Preserve, + source, + )?], + )) + } else { + // Replace one argument with `capture_output=True`, and remove the other. + Ok(Fix::suggested_edits( + Edit::range_replacement("capture_output=True".to_string(), first.range()), + [remove_argument( + second, + &call.arguments, + Parentheses::Preserve, + source, + )?], + )) + } +} diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP022.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP022.py.snap index 75df54757d..2d7ed39efa 100644 --- a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP022.py.snap +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP022.py.snap @@ -157,6 +157,8 @@ UP022.py:29:14: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, 35 | | encoding="utf-8", 36 | | ) | |_____^ UP022 +37 | +38 | output = subprocess.run( | = help: Replace with `capture_output` keyword argument @@ -172,4 +174,52 @@ UP022.py:29:14: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, 35 34 | encoding="utf-8", 36 35 | ) +UP022.py:38:10: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output` + | +36 | ) +37 | +38 | output = subprocess.run( + | __________^ +39 | | ["foo"], stdout=subprocess.PIPE, capture_output=True, stderr=subprocess.PIPE +40 | | ) + | |_^ UP022 +41 | +42 | output = subprocess.run( + | + = help: Replace with `capture_output` keyword argument + +ℹ Suggested fix +36 36 | ) +37 37 | +38 38 | output = subprocess.run( +39 |- ["foo"], stdout=subprocess.PIPE, capture_output=True, stderr=subprocess.PIPE + 39 |+ ["foo"], capture_output=True +40 40 | ) +41 41 | +42 42 | output = subprocess.run( + +UP022.py:42:10: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output` + | +40 | ) +41 | +42 | output = subprocess.run( + | __________^ +43 | | ["foo"], stdout=subprocess.PIPE, capture_output=False, stderr=subprocess.PIPE +44 | | ) + | |_^ UP022 +45 | +46 | # Examples that should NOT trigger the rule + | + = help: Replace with `capture_output` keyword argument + +ℹ Suggested fix +40 40 | ) +41 41 | +42 42 | output = subprocess.run( +43 |- ["foo"], stdout=subprocess.PIPE, capture_output=False, stderr=subprocess.PIPE + 43 |+ ["foo"], capture_output=False +44 44 | ) +45 45 | +46 46 | # Examples that should NOT trigger the rule +