Avoid attempting infinite open fix with re-bound builtin (#3650)

This commit is contained in:
Charlie Marsh 2023-03-21 11:32:31 -04:00 committed by GitHub
parent 33394e4a69
commit 3b1709ba1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 12 deletions

View File

@ -1,9 +1,9 @@
from io import open
with open("f.txt") as f:
print(f.read())
import io
with io.open("f.txt", mode="r", buffering=-1, **kwargs) as f:
print(f.read())
from io import open
with open("f.txt") as f:
print(f.read())

View File

@ -38,6 +38,7 @@ mod tests {
#[test_case(Rule::RedundantOpenModes, Path::new("UP015.py"); "UP015")]
#[test_case(Rule::NativeLiterals, Path::new("UP018.py"); "UP018")]
#[test_case(Rule::TypingTextStrAlias, Path::new("UP019.py"); "UP019")]
#[test_case(Rule::OpenAlias, Path::new("UP020.py"); "UP020")]
#[test_case(Rule::ReplaceUniversalNewlines, Path::new("UP021.py"); "UP021")]
#[test_case(Rule::ReplaceStdoutStderr, Path::new("UP022.py"); "UP022")]
#[test_case(Rule::DeprecatedCElementTree, Path::new("UP023.py"); "UP023")]

View File

@ -1,6 +1,6 @@
use rustpython_parser::ast::Expr;
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_diagnostics::{AutofixKind, Diagnostic, Fix, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::Range;
@ -8,16 +8,21 @@ use crate::checkers::ast::Checker;
use crate::registry::AsRule;
#[violation]
pub struct OpenAlias;
pub struct OpenAlias {
pub fixable: bool,
}
impl Violation for OpenAlias {
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
impl AlwaysAutofixableViolation for OpenAlias {
#[derive_message_formats]
fn message(&self) -> String {
format!("Use builtin `open`")
}
fn autofix_title(&self) -> String {
"Replace with builtin `open`".to_string()
fn autofix_title_formatter(&self) -> Option<fn(&Self) -> String> {
self.fixable
.then_some(|_| format!("Replace with builtin `open`"))
}
}
@ -28,8 +33,12 @@ pub fn open_alias(checker: &mut Checker, expr: &Expr, func: &Expr) {
.resolve_call_path(func)
.map_or(false, |call_path| call_path.as_slice() == ["io", "open"])
{
let mut diagnostic = Diagnostic::new(OpenAlias, Range::from(expr));
if checker.patch(diagnostic.kind.rule()) {
let fixable = checker
.ctx
.find_binding("open")
.map_or(true, |binding| binding.kind.is_builtin());
let mut diagnostic = Diagnostic::new(OpenAlias { fixable }, Range::from(expr));
if fixable && checker.patch(diagnostic.kind.rule()) {
diagnostic.amend(Fix::replacement(
"open".to_string(),
func.location,

View File

@ -0,0 +1,38 @@
---
source: crates/ruff/src/rules/pyupgrade/mod.rs
expression: diagnostics
---
- kind:
name: OpenAlias
body: "Use builtin `open`"
suggestion: "Replace with builtin `open`"
fixable: true
location:
row: 3
column: 5
end_location:
row: 3
column: 55
fix:
content: open
location:
row: 3
column: 5
end_location:
row: 3
column: 12
parent: ~
- kind:
name: OpenAlias
body: "Use builtin `open`"
suggestion: ~
fixable: false
location:
row: 8
column: 5
end_location:
row: 8
column: 18
fix: ~
parent: ~