Repository: astral-sh/ruff
File: crates/ruff_linter/src/rules/pylint/rules/subprocess_run_without_check.rs (Rust)

Code before:
///
/// Or:
/// ```python
/// import subprocess
///
/// subprocess.run(["ls", "nonexistent"], check=False)  # Explicitly no check.
/// ```
///
/// ## Fix safety
/// This rule's fix is marked as unsafe for function calls that contain
/// `**kwargs`, as adding a `check` keyword argument to such a call may lead
/// to a duplicate keyword argument error.
///
/// ## References
/// - [Python documentation: `subprocess.run`](https://docs.python.org/3/library/subprocess.html#subprocess.run)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.285")]
pub(crate) struct SubprocessRunWithoutCheck;

impl AlwaysFixableViolation for SubprocessRunWithoutCheck {
    #[derive_message_formats]
    fn message(&self) -> String {
        "`subprocess.run` without explicit `check` argument".to_string()
    }

    fn fix_title(&self) -> String {
        "Add explicit `check=False`".to_string()
    }
}

/// PLW1510
pub(crate) fn subprocess_run_without_check(checker: &Checker, call: &ast::ExprCall) {
    if !checker.semantic().seen_module(Modules::SUBPROCESS) {
        return;
    }

    if checker
        .semantic()
        .resolve_qualified_name(&call.func)
        .is_some_and(|qualified_name| matches!(qualified_name.segments(), ["subprocess", "run"]))
    {
        if call.arguments.find_keyword("check").is_none() {
            let mut diagnostic =
                checker.report_diagnostic(SubprocessRunWithoutCheck, call.func.range());
            diagnostic.set_fix(Fix::applicable_edit(
                add_argument("check=False", &call.arguments, checker.tokens()),
                // If the function call contains `**kwargs`, mark the fix as unsafe.
                if call
                    .arguments
                    .keywords
                    .iter()

Review comment (suggestion):
This felt worth a comment here, but I think this is pretty reasonable in general. These fixes aren't usually shown to users. We could of course update the test code instead:

https://github.com/astral-sh/ruff/blob/8cd04df49d15869e9c1ce82ecc882ece0c7eb0d7/crates/ruff_linter/src/test.rs#L354-L359

Code after:
///
/// Or:
/// ```python
/// import subprocess
///
/// subprocess.run(["ls", "nonexistent"], check=False)  # Explicitly no check.
/// ```
///
/// ## Fix safety
///
/// This rule's fix is marked as display-only because it's not clear whether the
/// potential exception was meant to be ignored by setting `check=False` or if
/// the author simply forgot to include `check=True`. The fix adds
/// `check=False`, making the existing behavior explicit but possibly masking
/// the original intention.
///
/// ## References
/// - [Python documentation: `subprocess.run`](https://docs.python.org/3/library/subprocess.html#subprocess.run)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.285")]
pub(crate) struct SubprocessRunWithoutCheck;

impl Violation for SubprocessRunWithoutCheck {
    // The fix is always set on the diagnostic, but display-only fixes aren't
    // considered "fixable" in the tests.
    const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;

    #[derive_message_formats]
    fn message(&self) -> String {
        "`subprocess.run` without explicit `check` argument".to_string()
    }

    fn fix_title(&self) -> Option<String> {
        Some("Add explicit `check=False`".to_string())
    }
}

/// PLW1510
pub(crate) fn subprocess_run_without_check(checker: &Checker, call: &ast::ExprCall) {
    if !checker.semantic().seen_module(Modules::SUBPROCESS) {
        return;
    }

    if checker
        .semantic()
        .resolve_qualified_name(&call.func)
        .is_some_and(|qualified_name| matches!(qualified_name.segments(), ["subprocess", "run"]))
    {
        if call.arguments.find_keyword("check").is_none() {
            let mut diagnostic =
                checker.report_diagnostic(SubprocessRunWithoutCheck, call.func.range());