diff --git a/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP015.py b/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP015.py index 2413407ed6ba44..9f78caef4cdddc 100644 --- a/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP015.py +++ b/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP015.py @@ -78,3 +78,10 @@ open("foo", "rt") open("f", "r", encoding="UTF-8") open("f", "wt") + + +import aiofiles + +aiofiles.open("foo", "U") +aiofiles.open("foo", "r") +aiofiles.open("foo", mode="r") diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs index 50f35ce5d17f57..3939d3e321a516 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs @@ -61,7 +61,16 @@ impl AlwaysFixableViolation for RedundantOpenModes { /// UP015 pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall) { - if !checker.semantic().match_builtin_expr(&call.func, "open") { + if !checker + .semantic() + .resolve_qualified_name(&call.func) + .is_some_and(|qualified_name| { + matches!( + qualified_name.segments(), + ["" | "builtins" | "aiofiles", "open"] + ) + }) + { return; } diff --git a/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP015.py.snap b/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP015.py.snap index d85977a74ec80b..054bc00ec8c731 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP015.py.snap +++ b/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP015.py.snap @@ -899,4 +899,55 @@ UP015.py:70:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" 72 72 | open = 1 73 73 | open("foo", "U") +UP015.py:85:1: UP015 [*] Unnecessary open mode parameters + | +83 | import aiofiles +84 | +85 | aiofiles.open("foo", "U") + | ^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +86 | aiofiles.open("foo", "r") +87 | aiofiles.open("foo", mode="r") + | + = help: Remove open mode parameters + +ℹ Safe fix +82 82 | +83 83 | import aiofiles +84 84 | +85 |-aiofiles.open("foo", "U") + 85 |+aiofiles.open("foo") +86 86 | aiofiles.open("foo", "r") +87 87 | aiofiles.open("foo", mode="r") + +UP015.py:86:1: UP015 [*] Unnecessary open mode parameters + | +85 | aiofiles.open("foo", "U") +86 | aiofiles.open("foo", "r") + | ^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +87 | aiofiles.open("foo", mode="r") + | + = help: Remove open mode parameters + +ℹ Safe fix +83 83 | import aiofiles +84 84 | +85 85 | aiofiles.open("foo", "U") +86 |-aiofiles.open("foo", "r") + 86 |+aiofiles.open("foo") +87 87 | aiofiles.open("foo", mode="r") + +UP015.py:87:1: UP015 [*] Unnecessary open mode parameters + | +85 | aiofiles.open("foo", "U") +86 | aiofiles.open("foo", "r") +87 | aiofiles.open("foo", mode="r") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 + | + = help: Remove open mode parameters +ℹ Safe fix +84 84 | +85 85 | aiofiles.open("foo", "U") +86 86 | aiofiles.open("foo", "r") +87 |-aiofiles.open("foo", mode="r") + 87 |+aiofiles.open("foo")