mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-03 13:23:10 +00:00
[refurb] Add fixes for FURB101, FURB103 (#20520)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
## Summary Part of `PTH-*` fixes: https://github.com/astral-sh/ruff/pull/19404#issuecomment-3089639686 ## Test Plan `cargo nextest run furb`
This commit is contained in:
parent
70f51e9648
commit
b66a3e7451
10 changed files with 698 additions and 34 deletions
|
|
@ -259,3 +259,13 @@ pub(crate) const fn is_b006_unsafe_fix_preserve_assignment_expr_enabled(
|
||||||
) -> bool {
|
) -> bool {
|
||||||
settings.preview.is_enabled()
|
settings.preview.is_enabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/astral-sh/ruff/pull/20520
|
||||||
|
pub(crate) const fn is_fix_read_whole_file_enabled(settings: &LinterSettings) -> bool {
|
||||||
|
settings.preview.is_enabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/astral-sh/ruff/pull/20520
|
||||||
|
pub(crate) const fn is_fix_write_whole_file_enabled(settings: &LinterSettings) -> bool {
|
||||||
|
settings.preview.is_enabled()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use ruff_python_ast::name::Name;
|
use ruff_python_ast::PythonVersion;
|
||||||
use ruff_python_ast::{self as ast, Expr, parenthesize::parenthesized_range};
|
use ruff_python_ast::{self as ast, Expr, name::Name, parenthesize::parenthesized_range};
|
||||||
use ruff_python_codegen::Generator;
|
use ruff_python_codegen::Generator;
|
||||||
use ruff_python_semantic::{BindingId, ResolvedReference, SemanticModel};
|
use ruff_python_semantic::{BindingId, ResolvedReference, SemanticModel};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::{Applicability, Edit, Fix};
|
use crate::{Applicability, Edit, Fix};
|
||||||
use ruff_python_ast::PythonVersion;
|
|
||||||
|
|
||||||
/// Format a code snippet to call `name.method()`.
|
/// Format a code snippet to call `name.method()`.
|
||||||
pub(super) fn generate_method_call(name: Name, method: &str, generator: Generator) -> String {
|
pub(super) fn generate_method_call(name: Name, method: &str, generator: Generator) -> String {
|
||||||
|
|
@ -345,12 +344,8 @@ pub(super) fn parenthesize_loop_iter_if_necessary<'a>(
|
||||||
let iter_in_source = locator.slice(iter);
|
let iter_in_source = locator.slice(iter);
|
||||||
|
|
||||||
match iter {
|
match iter {
|
||||||
ast::Expr::Tuple(tuple) if !tuple.parenthesized => {
|
Expr::Tuple(tuple) if !tuple.parenthesized => Cow::Owned(format!("({iter_in_source})")),
|
||||||
Cow::Owned(format!("({iter_in_source})"))
|
Expr::Lambda(_) | Expr::If(_) if matches!(location, IterLocation::Comprehension) => {
|
||||||
}
|
|
||||||
ast::Expr::Lambda(_) | ast::Expr::If(_)
|
|
||||||
if matches!(location, IterLocation::Comprehension) =>
|
|
||||||
{
|
|
||||||
Cow::Owned(format!("({iter_in_source})"))
|
Cow::Owned(format!("({iter_in_source})"))
|
||||||
}
|
}
|
||||||
_ => Cow::Borrowed(iter_in_source),
|
_ => Cow::Borrowed(iter_in_source),
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ mod tests {
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
use crate::registry::Rule;
|
use crate::registry::Rule;
|
||||||
|
use crate::settings::types::PreviewMode;
|
||||||
use crate::test::test_path;
|
use crate::test::test_path;
|
||||||
use crate::{assert_diagnostics, settings};
|
use crate::{assert_diagnostics, settings};
|
||||||
|
|
||||||
|
|
@ -62,6 +63,25 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(Rule::ReadWholeFile, Path::new("FURB101.py"))]
|
||||||
|
#[test_case(Rule::WriteWholeFile, Path::new("FURB103.py"))]
|
||||||
|
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
|
let snapshot = format!(
|
||||||
|
"preview_{}_{}",
|
||||||
|
rule_code.noqa_code(),
|
||||||
|
path.to_string_lossy()
|
||||||
|
);
|
||||||
|
let diagnostics = test_path(
|
||||||
|
Path::new("refurb").join(path).as_path(),
|
||||||
|
&settings::LinterSettings {
|
||||||
|
preview: PreviewMode::Enabled,
|
||||||
|
..settings::LinterSettings::for_rule(rule_code)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
assert_diagnostics!(snapshot, diagnostics);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn write_whole_file_python_39() -> Result<()> {
|
fn write_whole_file_python_39() -> Result<()> {
|
||||||
let diagnostics = test_path(
|
let diagnostics = test_path(
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
|
use ruff_diagnostics::{Applicability, Edit, Fix};
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::visitor::{self, Visitor};
|
use ruff_python_ast::{
|
||||||
use ruff_python_ast::{self as ast, Expr};
|
self as ast, Expr, Stmt,
|
||||||
|
visitor::{self, Visitor},
|
||||||
|
};
|
||||||
use ruff_python_codegen::Generator;
|
use ruff_python_codegen::Generator;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::Violation;
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::snippet::SourceCodeSnippet;
|
use crate::fix::snippet::SourceCodeSnippet;
|
||||||
|
use crate::importer::ImportRequest;
|
||||||
use crate::rules::refurb::helpers::{FileOpen, find_file_opens};
|
use crate::rules::refurb::helpers::{FileOpen, find_file_opens};
|
||||||
|
use crate::{FixAvailability, Violation};
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `open` and `read` that can be replaced by `pathlib`
|
/// Checks for uses of `open` and `read` that can be replaced by `pathlib`
|
||||||
|
|
@ -31,6 +34,8 @@ use crate::rules::refurb::helpers::{FileOpen, find_file_opens};
|
||||||
///
|
///
|
||||||
/// contents = Path(filename).read_text()
|
/// contents = Path(filename).read_text()
|
||||||
/// ```
|
/// ```
|
||||||
|
/// ## Fix Safety
|
||||||
|
/// This rule's fix is marked as unsafe if the replacement would remove comments attached to the original expression.
|
||||||
///
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: `Path.read_bytes`](https://docs.python.org/3/library/pathlib.html#pathlib.Path.read_bytes)
|
/// - [Python documentation: `Path.read_bytes`](https://docs.python.org/3/library/pathlib.html#pathlib.Path.read_bytes)
|
||||||
|
|
@ -42,12 +47,22 @@ pub(crate) struct ReadWholeFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for ReadWholeFile {
|
impl Violation for ReadWholeFile {
|
||||||
|
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||||
|
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let filename = self.filename.truncated_display();
|
let filename = self.filename.truncated_display();
|
||||||
let suggestion = self.suggestion.truncated_display();
|
let suggestion = self.suggestion.truncated_display();
|
||||||
format!("`open` and `read` should be replaced by `Path({filename}).{suggestion}`")
|
format!("`open` and `read` should be replaced by `Path({filename}).{suggestion}`")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fix_title(&self) -> Option<String> {
|
||||||
|
Some(format!(
|
||||||
|
"Replace with `Path({}).{}`",
|
||||||
|
self.filename.truncated_display(),
|
||||||
|
self.suggestion.truncated_display(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FURB101
|
/// FURB101
|
||||||
|
|
@ -64,7 +79,7 @@ pub(crate) fn read_whole_file(checker: &Checker, with: &ast::StmtWith) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then we need to match each `open` operation with exactly one `read` call.
|
// Then we need to match each `open` operation with exactly one `read` call.
|
||||||
let mut matcher = ReadMatcher::new(checker, candidates);
|
let mut matcher = ReadMatcher::new(checker, candidates, with);
|
||||||
visitor::walk_body(&mut matcher, &with.body);
|
visitor::walk_body(&mut matcher, &with.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,13 +87,19 @@ pub(crate) fn read_whole_file(checker: &Checker, with: &ast::StmtWith) {
|
||||||
struct ReadMatcher<'a, 'b> {
|
struct ReadMatcher<'a, 'b> {
|
||||||
checker: &'a Checker<'b>,
|
checker: &'a Checker<'b>,
|
||||||
candidates: Vec<FileOpen<'a>>,
|
candidates: Vec<FileOpen<'a>>,
|
||||||
|
with_stmt: &'a ast::StmtWith,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> ReadMatcher<'a, 'b> {
|
impl<'a, 'b> ReadMatcher<'a, 'b> {
|
||||||
fn new(checker: &'a Checker<'b>, candidates: Vec<FileOpen<'a>>) -> Self {
|
fn new(
|
||||||
|
checker: &'a Checker<'b>,
|
||||||
|
candidates: Vec<FileOpen<'a>>,
|
||||||
|
with_stmt: &'a ast::StmtWith,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
checker,
|
checker,
|
||||||
candidates,
|
candidates,
|
||||||
|
with_stmt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -92,15 +113,38 @@ impl<'a> Visitor<'a> for ReadMatcher<'a, '_> {
|
||||||
.position(|open| open.is_ref(read_from))
|
.position(|open| open.is_ref(read_from))
|
||||||
{
|
{
|
||||||
let open = self.candidates.remove(open);
|
let open = self.candidates.remove(open);
|
||||||
self.checker.report_diagnostic(
|
let suggestion = make_suggestion(&open, self.checker.generator());
|
||||||
|
let mut diagnostic = self.checker.report_diagnostic(
|
||||||
ReadWholeFile {
|
ReadWholeFile {
|
||||||
filename: SourceCodeSnippet::from_str(
|
filename: SourceCodeSnippet::from_str(
|
||||||
&self.checker.generator().expr(open.filename),
|
&self.checker.generator().expr(open.filename),
|
||||||
),
|
),
|
||||||
suggestion: make_suggestion(&open, self.checker.generator()),
|
suggestion: SourceCodeSnippet::from_str(&suggestion),
|
||||||
},
|
},
|
||||||
open.item.range(),
|
open.item.range(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if !crate::preview::is_fix_read_whole_file_enabled(self.checker.settings()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = match self.with_stmt.body.first() {
|
||||||
|
Some(Stmt::Assign(assign))
|
||||||
|
if assign.value.range().contains_range(expr.range()) =>
|
||||||
|
{
|
||||||
|
match assign.targets.first() {
|
||||||
|
Some(Expr::Name(name)) => Some(name.id.as_str()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(fix) =
|
||||||
|
generate_fix(self.checker, &open, target, self.with_stmt, &suggestion)
|
||||||
|
{
|
||||||
|
diagnostic.set_fix(fix);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +169,7 @@ fn match_read_call(expr: &Expr) -> Option<&Expr> {
|
||||||
Some(&*attr.value)
|
Some(&*attr.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_suggestion(open: &FileOpen<'_>, generator: Generator) -> SourceCodeSnippet {
|
fn make_suggestion(open: &FileOpen<'_>, generator: Generator) -> String {
|
||||||
let name = ast::ExprName {
|
let name = ast::ExprName {
|
||||||
id: open.mode.pathlib_method(),
|
id: open.mode.pathlib_method(),
|
||||||
ctx: ast::ExprContext::Load,
|
ctx: ast::ExprContext::Load,
|
||||||
|
|
@ -143,5 +187,46 @@ fn make_suggestion(open: &FileOpen<'_>, generator: Generator) -> SourceCodeSnipp
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
node_index: ruff_python_ast::AtomicNodeIndex::NONE,
|
node_index: ruff_python_ast::AtomicNodeIndex::NONE,
|
||||||
};
|
};
|
||||||
SourceCodeSnippet::from_str(&generator.expr(&call.into()))
|
generator.expr(&call.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_fix(
|
||||||
|
checker: &Checker,
|
||||||
|
open: &FileOpen,
|
||||||
|
target: Option<&str>,
|
||||||
|
with_stmt: &ast::StmtWith,
|
||||||
|
suggestion: &str,
|
||||||
|
) -> Option<Fix> {
|
||||||
|
if !(with_stmt.items.len() == 1 && matches!(with_stmt.body.as_slice(), [Stmt::Assign(_)])) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let locator = checker.locator();
|
||||||
|
let filename_code = locator.slice(open.filename.range());
|
||||||
|
|
||||||
|
let (import_edit, binding) = checker
|
||||||
|
.importer()
|
||||||
|
.get_or_import_symbol(
|
||||||
|
&ImportRequest::import("pathlib", "Path"),
|
||||||
|
with_stmt.start(),
|
||||||
|
checker.semantic(),
|
||||||
|
)
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
let replacement = match target {
|
||||||
|
Some(var) => format!("{var} = {binding}({filename_code}).{suggestion}"),
|
||||||
|
None => format!("{binding}({filename_code}).{suggestion}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let applicability = if checker.comment_ranges().intersects(with_stmt.range()) {
|
||||||
|
Applicability::Unsafe
|
||||||
|
} else {
|
||||||
|
Applicability::Safe
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Fix::applicable_edits(
|
||||||
|
Edit::range_replacement(replacement, with_stmt.range()),
|
||||||
|
[import_edit],
|
||||||
|
applicability,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,19 @@
|
||||||
|
use ruff_diagnostics::{Applicability, Edit, Fix};
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::relocate::relocate_expr;
|
use ruff_python_ast::{
|
||||||
use ruff_python_ast::visitor::{self, Visitor};
|
self as ast, Expr, Stmt,
|
||||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
relocate::relocate_expr,
|
||||||
|
visitor::{self, Visitor},
|
||||||
|
};
|
||||||
|
|
||||||
use ruff_python_codegen::Generator;
|
use ruff_python_codegen::Generator;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::Violation;
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::snippet::SourceCodeSnippet;
|
use crate::fix::snippet::SourceCodeSnippet;
|
||||||
|
use crate::importer::ImportRequest;
|
||||||
use crate::rules::refurb::helpers::{FileOpen, find_file_opens};
|
use crate::rules::refurb::helpers::{FileOpen, find_file_opens};
|
||||||
|
use crate::{FixAvailability, Violation};
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `open` and `write` that can be replaced by `pathlib`
|
/// Checks for uses of `open` and `write` that can be replaced by `pathlib`
|
||||||
|
|
@ -33,6 +37,9 @@ use crate::rules::refurb::helpers::{FileOpen, find_file_opens};
|
||||||
/// Path(filename).write_text(contents)
|
/// Path(filename).write_text(contents)
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// ## Fix Safety
|
||||||
|
/// This rule's fix is marked as unsafe if the replacement would remove comments attached to the original expression.
|
||||||
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: `Path.write_bytes`](https://docs.python.org/3/library/pathlib.html#pathlib.Path.write_bytes)
|
/// - [Python documentation: `Path.write_bytes`](https://docs.python.org/3/library/pathlib.html#pathlib.Path.write_bytes)
|
||||||
/// - [Python documentation: `Path.write_text`](https://docs.python.org/3/library/pathlib.html#pathlib.Path.write_text)
|
/// - [Python documentation: `Path.write_text`](https://docs.python.org/3/library/pathlib.html#pathlib.Path.write_text)
|
||||||
|
|
@ -43,12 +50,21 @@ pub(crate) struct WriteWholeFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for WriteWholeFile {
|
impl Violation for WriteWholeFile {
|
||||||
|
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||||
|
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let filename = self.filename.truncated_display();
|
let filename = self.filename.truncated_display();
|
||||||
let suggestion = self.suggestion.truncated_display();
|
let suggestion = self.suggestion.truncated_display();
|
||||||
format!("`open` and `write` should be replaced by `Path({filename}).{suggestion}`")
|
format!("`open` and `write` should be replaced by `Path({filename}).{suggestion}`")
|
||||||
}
|
}
|
||||||
|
fn fix_title(&self) -> Option<String> {
|
||||||
|
Some(format!(
|
||||||
|
"Replace with `Path({}).{}`",
|
||||||
|
self.filename.truncated_display(),
|
||||||
|
self.suggestion.truncated_display(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FURB103
|
/// FURB103
|
||||||
|
|
@ -65,7 +81,7 @@ pub(crate) fn write_whole_file(checker: &Checker, with: &ast::StmtWith) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then we need to match each `open` operation with exactly one `write` call.
|
// Then we need to match each `open` operation with exactly one `write` call.
|
||||||
let mut matcher = WriteMatcher::new(checker, candidates);
|
let mut matcher = WriteMatcher::new(checker, candidates, with);
|
||||||
visitor::walk_body(&mut matcher, &with.body);
|
visitor::walk_body(&mut matcher, &with.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,21 +90,27 @@ struct WriteMatcher<'a, 'b> {
|
||||||
checker: &'a Checker<'b>,
|
checker: &'a Checker<'b>,
|
||||||
candidates: Vec<FileOpen<'a>>,
|
candidates: Vec<FileOpen<'a>>,
|
||||||
loop_counter: u32,
|
loop_counter: u32,
|
||||||
|
with_stmt: &'a ast::StmtWith,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> WriteMatcher<'a, 'b> {
|
impl<'a, 'b> WriteMatcher<'a, 'b> {
|
||||||
fn new(checker: &'a Checker<'b>, candidates: Vec<FileOpen<'a>>) -> Self {
|
fn new(
|
||||||
|
checker: &'a Checker<'b>,
|
||||||
|
candidates: Vec<FileOpen<'a>>,
|
||||||
|
with_stmt: &'a ast::StmtWith,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
checker,
|
checker,
|
||||||
candidates,
|
candidates,
|
||||||
loop_counter: 0,
|
loop_counter: 0,
|
||||||
|
with_stmt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for WriteMatcher<'a, '_> {
|
impl<'a> Visitor<'a> for WriteMatcher<'a, '_> {
|
||||||
fn visit_stmt(&mut self, stmt: &'a Stmt) {
|
fn visit_stmt(&mut self, stmt: &'a Stmt) {
|
||||||
if matches!(stmt, ast::Stmt::While(_) | ast::Stmt::For(_)) {
|
if matches!(stmt, Stmt::While(_) | Stmt::For(_)) {
|
||||||
self.loop_counter += 1;
|
self.loop_counter += 1;
|
||||||
visitor::walk_stmt(self, stmt);
|
visitor::walk_stmt(self, stmt);
|
||||||
self.loop_counter -= 1;
|
self.loop_counter -= 1;
|
||||||
|
|
@ -104,19 +126,30 @@ impl<'a> Visitor<'a> for WriteMatcher<'a, '_> {
|
||||||
.iter()
|
.iter()
|
||||||
.position(|open| open.is_ref(write_to))
|
.position(|open| open.is_ref(write_to))
|
||||||
{
|
{
|
||||||
|
let open = self.candidates.remove(open);
|
||||||
|
|
||||||
if self.loop_counter == 0 {
|
if self.loop_counter == 0 {
|
||||||
let open = self.candidates.remove(open);
|
let suggestion = make_suggestion(&open, content, self.checker.generator());
|
||||||
self.checker.report_diagnostic(
|
|
||||||
|
let mut diagnostic = self.checker.report_diagnostic(
|
||||||
WriteWholeFile {
|
WriteWholeFile {
|
||||||
filename: SourceCodeSnippet::from_str(
|
filename: SourceCodeSnippet::from_str(
|
||||||
&self.checker.generator().expr(open.filename),
|
&self.checker.generator().expr(open.filename),
|
||||||
),
|
),
|
||||||
suggestion: make_suggestion(&open, content, self.checker.generator()),
|
suggestion: SourceCodeSnippet::from_str(&suggestion),
|
||||||
},
|
},
|
||||||
open.item.range(),
|
open.item.range(),
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
self.candidates.remove(open);
|
if !crate::preview::is_fix_write_whole_file_enabled(self.checker.settings()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(fix) =
|
||||||
|
generate_fix(self.checker, &open, self.with_stmt, &suggestion)
|
||||||
|
{
|
||||||
|
diagnostic.set_fix(fix);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -143,7 +176,7 @@ fn match_write_call(expr: &Expr) -> Option<(&Expr, &Expr)> {
|
||||||
Some((&*attr.value, call.arguments.args.first()?))
|
Some((&*attr.value, call.arguments.args.first()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_suggestion(open: &FileOpen<'_>, arg: &Expr, generator: Generator) -> SourceCodeSnippet {
|
fn make_suggestion(open: &FileOpen<'_>, arg: &Expr, generator: Generator) -> String {
|
||||||
let name = ast::ExprName {
|
let name = ast::ExprName {
|
||||||
id: open.mode.pathlib_method(),
|
id: open.mode.pathlib_method(),
|
||||||
ctx: ast::ExprContext::Load,
|
ctx: ast::ExprContext::Load,
|
||||||
|
|
@ -163,5 +196,42 @@ fn make_suggestion(open: &FileOpen<'_>, arg: &Expr, generator: Generator) -> Sou
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
node_index: ruff_python_ast::AtomicNodeIndex::NONE,
|
node_index: ruff_python_ast::AtomicNodeIndex::NONE,
|
||||||
};
|
};
|
||||||
SourceCodeSnippet::from_str(&generator.expr(&call.into()))
|
generator.expr(&call.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_fix(
|
||||||
|
checker: &Checker,
|
||||||
|
open: &FileOpen,
|
||||||
|
with_stmt: &ast::StmtWith,
|
||||||
|
suggestion: &str,
|
||||||
|
) -> Option<Fix> {
|
||||||
|
if !(with_stmt.items.len() == 1 && matches!(with_stmt.body.as_slice(), [Stmt::Expr(_)])) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let locator = checker.locator();
|
||||||
|
let filename_code = locator.slice(open.filename.range());
|
||||||
|
|
||||||
|
let (import_edit, binding) = checker
|
||||||
|
.importer()
|
||||||
|
.get_or_import_symbol(
|
||||||
|
&ImportRequest::import("pathlib", "Path"),
|
||||||
|
with_stmt.start(),
|
||||||
|
checker.semantic(),
|
||||||
|
)
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
let replacement = format!("{binding}({filename_code}).{suggestion}");
|
||||||
|
|
||||||
|
let applicability = if checker.comment_ranges().intersects(with_stmt.range()) {
|
||||||
|
Applicability::Unsafe
|
||||||
|
} else {
|
||||||
|
Applicability::Safe
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Fix::applicable_edits(
|
||||||
|
Edit::range_replacement(replacement, with_stmt.range()),
|
||||||
|
[import_edit],
|
||||||
|
applicability,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
13 | x = f.read()
|
13 | x = f.read()
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text()`
|
||||||
|
|
||||||
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_bytes()`
|
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_bytes()`
|
||||||
--> FURB101.py:16:6
|
--> FURB101.py:16:6
|
||||||
|
|
@ -18,6 +19,7 @@ FURB101 `open` and `read` should be replaced by `Path("file.txt").read_bytes()`
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
17 | x = f.read()
|
17 | x = f.read()
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_bytes()`
|
||||||
|
|
||||||
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_bytes()`
|
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_bytes()`
|
||||||
--> FURB101.py:20:6
|
--> FURB101.py:20:6
|
||||||
|
|
@ -27,6 +29,7 @@ FURB101 `open` and `read` should be replaced by `Path("file.txt").read_bytes()`
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
21 | x = f.read()
|
21 | x = f.read()
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_bytes()`
|
||||||
|
|
||||||
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text(encoding="utf8")`
|
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text(encoding="utf8")`
|
||||||
--> FURB101.py:24:6
|
--> FURB101.py:24:6
|
||||||
|
|
@ -36,6 +39,7 @@ FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text(enco
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
25 | x = f.read()
|
25 | x = f.read()
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text(encoding="utf8")`
|
||||||
|
|
||||||
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text(errors="ignore")`
|
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text(errors="ignore")`
|
||||||
--> FURB101.py:28:6
|
--> FURB101.py:28:6
|
||||||
|
|
@ -45,6 +49,7 @@ FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text(erro
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
29 | x = f.read()
|
29 | x = f.read()
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text(errors="ignore")`
|
||||||
|
|
||||||
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
||||||
--> FURB101.py:32:6
|
--> FURB101.py:32:6
|
||||||
|
|
@ -54,6 +59,7 @@ FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
33 | x = f.read()
|
33 | x = f.read()
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text()`
|
||||||
|
|
||||||
FURB101 `open` and `read` should be replaced by `Path(foo()).read_bytes()`
|
FURB101 `open` and `read` should be replaced by `Path(foo()).read_bytes()`
|
||||||
--> FURB101.py:36:6
|
--> FURB101.py:36:6
|
||||||
|
|
@ -64,6 +70,7 @@ FURB101 `open` and `read` should be replaced by `Path(foo()).read_bytes()`
|
||||||
37 | # The body of `with` is non-trivial, but the recommendation holds.
|
37 | # The body of `with` is non-trivial, but the recommendation holds.
|
||||||
38 | bar("pre")
|
38 | bar("pre")
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path(foo()).read_bytes()`
|
||||||
|
|
||||||
FURB101 `open` and `read` should be replaced by `Path("a.txt").read_text()`
|
FURB101 `open` and `read` should be replaced by `Path("a.txt").read_text()`
|
||||||
--> FURB101.py:44:6
|
--> FURB101.py:44:6
|
||||||
|
|
@ -74,6 +81,7 @@ FURB101 `open` and `read` should be replaced by `Path("a.txt").read_text()`
|
||||||
45 | x = a.read()
|
45 | x = a.read()
|
||||||
46 | y = b.read()
|
46 | y = b.read()
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("a.txt").read_text()`
|
||||||
|
|
||||||
FURB101 `open` and `read` should be replaced by `Path("b.txt").read_bytes()`
|
FURB101 `open` and `read` should be replaced by `Path("b.txt").read_bytes()`
|
||||||
--> FURB101.py:44:26
|
--> FURB101.py:44:26
|
||||||
|
|
@ -84,6 +92,7 @@ FURB101 `open` and `read` should be replaced by `Path("b.txt").read_bytes()`
|
||||||
45 | x = a.read()
|
45 | x = a.read()
|
||||||
46 | y = b.read()
|
46 | y = b.read()
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("b.txt").read_bytes()`
|
||||||
|
|
||||||
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
||||||
--> FURB101.py:49:18
|
--> FURB101.py:49:18
|
||||||
|
|
@ -94,3 +103,4 @@ FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
||||||
50 | # We have other things in here, multiple with items, but
|
50 | # We have other things in here, multiple with items, but
|
||||||
51 | # the user reads the whole file and that bit they can replace.
|
51 | # the user reads the whole file and that bit they can replace.
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text()`
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text("t
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
13 | f.write("test")
|
13 | f.write("test")
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text("test")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(foobar)`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(foobar)`
|
||||||
--> FURB103.py:16:6
|
--> FURB103.py:16:6
|
||||||
|
|
@ -18,6 +19,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(f
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
17 | f.write(foobar)
|
17 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_bytes(foobar)`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(b"abc")`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(b"abc")`
|
||||||
--> FURB103.py:20:6
|
--> FURB103.py:20:6
|
||||||
|
|
@ -27,6 +29,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(b
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
21 | f.write(b"abc")
|
21 | f.write(b"abc")
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_bytes(b"abc")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, encoding="utf8")`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, encoding="utf8")`
|
||||||
--> FURB103.py:24:6
|
--> FURB103.py:24:6
|
||||||
|
|
@ -36,6 +39,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
25 | f.write(foobar)
|
25 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, encoding="utf8")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, errors="ignore")`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, errors="ignore")`
|
||||||
--> FURB103.py:28:6
|
--> FURB103.py:28:6
|
||||||
|
|
@ -45,6 +49,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
29 | f.write(foobar)
|
29 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, errors="ignore")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar)`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar)`
|
||||||
--> FURB103.py:32:6
|
--> FURB103.py:32:6
|
||||||
|
|
@ -54,6 +59,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
33 | f.write(foobar)
|
33 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar)`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path(foo()).write_bytes(bar())`
|
FURB103 `open` and `write` should be replaced by `Path(foo()).write_bytes(bar())`
|
||||||
--> FURB103.py:36:6
|
--> FURB103.py:36:6
|
||||||
|
|
@ -64,6 +70,7 @@ FURB103 `open` and `write` should be replaced by `Path(foo()).write_bytes(bar())
|
||||||
37 | # The body of `with` is non-trivial, but the recommendation holds.
|
37 | # The body of `with` is non-trivial, but the recommendation holds.
|
||||||
38 | bar("pre")
|
38 | bar("pre")
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path(foo()).write_bytes(bar())`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("a.txt").write_text(x)`
|
FURB103 `open` and `write` should be replaced by `Path("a.txt").write_text(x)`
|
||||||
--> FURB103.py:44:6
|
--> FURB103.py:44:6
|
||||||
|
|
@ -74,6 +81,7 @@ FURB103 `open` and `write` should be replaced by `Path("a.txt").write_text(x)`
|
||||||
45 | a.write(x)
|
45 | a.write(x)
|
||||||
46 | b.write(y)
|
46 | b.write(y)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("a.txt").write_text(x)`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("b.txt").write_bytes(y)`
|
FURB103 `open` and `write` should be replaced by `Path("b.txt").write_bytes(y)`
|
||||||
--> FURB103.py:44:31
|
--> FURB103.py:44:31
|
||||||
|
|
@ -84,6 +92,7 @@ FURB103 `open` and `write` should be replaced by `Path("b.txt").write_bytes(y)`
|
||||||
45 | a.write(x)
|
45 | a.write(x)
|
||||||
46 | b.write(y)
|
46 | b.write(y)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("b.txt").write_bytes(y)`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(bar(bar(a + x)))`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(bar(bar(a + x)))`
|
||||||
--> FURB103.py:49:18
|
--> FURB103.py:49:18
|
||||||
|
|
@ -94,6 +103,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(ba
|
||||||
50 | # We have other things in here, multiple with items, but the user
|
50 | # We have other things in here, multiple with items, but the user
|
||||||
51 | # writes a single time to file and that bit they can replace.
|
51 | # writes a single time to file and that bit they can replace.
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(bar(bar(a + x)))`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, newline="\r\n")`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
--> FURB103.py:58:6
|
--> FURB103.py:58:6
|
||||||
|
|
@ -103,6 +113,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
59 | f.write(foobar)
|
59 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, newline="\r\n")`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
--> FURB103.py:66:6
|
--> FURB103.py:66:6
|
||||||
|
|
@ -112,6 +123,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
67 | f.write(foobar)
|
67 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, newline="\r\n")`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
--> FURB103.py:74:6
|
--> FURB103.py:74:6
|
||||||
|
|
@ -121,3 +133,4 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
75 | f.write(foobar)
|
75 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/refurb/mod.rs
|
||||||
|
---
|
||||||
|
FURB101 [*] `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
||||||
|
--> FURB101.py:12:6
|
||||||
|
|
|
||||||
|
11 | # FURB101
|
||||||
|
12 | with open("file.txt") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
13 | x = f.read()
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text()`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
10 | # Errors.
|
||||||
|
11 |
|
||||||
|
12 | # FURB101
|
||||||
|
- with open("file.txt") as f:
|
||||||
|
- x = f.read()
|
||||||
|
13 + x = pathlib.Path("file.txt").read_text()
|
||||||
|
14 |
|
||||||
|
15 | # FURB101
|
||||||
|
16 | with open("file.txt", "rb") as f:
|
||||||
|
|
||||||
|
FURB101 [*] `open` and `read` should be replaced by `Path("file.txt").read_bytes()`
|
||||||
|
--> FURB101.py:16:6
|
||||||
|
|
|
||||||
|
15 | # FURB101
|
||||||
|
16 | with open("file.txt", "rb") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
17 | x = f.read()
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_bytes()`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
14 | x = f.read()
|
||||||
|
15 |
|
||||||
|
16 | # FURB101
|
||||||
|
- with open("file.txt", "rb") as f:
|
||||||
|
- x = f.read()
|
||||||
|
17 + x = pathlib.Path("file.txt").read_bytes()
|
||||||
|
18 |
|
||||||
|
19 | # FURB101
|
||||||
|
20 | with open("file.txt", mode="rb") as f:
|
||||||
|
|
||||||
|
FURB101 [*] `open` and `read` should be replaced by `Path("file.txt").read_bytes()`
|
||||||
|
--> FURB101.py:20:6
|
||||||
|
|
|
||||||
|
19 | # FURB101
|
||||||
|
20 | with open("file.txt", mode="rb") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
21 | x = f.read()
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_bytes()`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
18 | x = f.read()
|
||||||
|
19 |
|
||||||
|
20 | # FURB101
|
||||||
|
- with open("file.txt", mode="rb") as f:
|
||||||
|
- x = f.read()
|
||||||
|
21 + x = pathlib.Path("file.txt").read_bytes()
|
||||||
|
22 |
|
||||||
|
23 | # FURB101
|
||||||
|
24 | with open("file.txt", encoding="utf8") as f:
|
||||||
|
|
||||||
|
FURB101 [*] `open` and `read` should be replaced by `Path("file.txt").read_text(encoding="utf8")`
|
||||||
|
--> FURB101.py:24:6
|
||||||
|
|
|
||||||
|
23 | # FURB101
|
||||||
|
24 | with open("file.txt", encoding="utf8") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
25 | x = f.read()
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text(encoding="utf8")`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
22 | x = f.read()
|
||||||
|
23 |
|
||||||
|
24 | # FURB101
|
||||||
|
- with open("file.txt", encoding="utf8") as f:
|
||||||
|
- x = f.read()
|
||||||
|
25 + x = pathlib.Path("file.txt").read_text(encoding="utf8")
|
||||||
|
26 |
|
||||||
|
27 | # FURB101
|
||||||
|
28 | with open("file.txt", errors="ignore") as f:
|
||||||
|
|
||||||
|
FURB101 [*] `open` and `read` should be replaced by `Path("file.txt").read_text(errors="ignore")`
|
||||||
|
--> FURB101.py:28:6
|
||||||
|
|
|
||||||
|
27 | # FURB101
|
||||||
|
28 | with open("file.txt", errors="ignore") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
29 | x = f.read()
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text(errors="ignore")`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
26 | x = f.read()
|
||||||
|
27 |
|
||||||
|
28 | # FURB101
|
||||||
|
- with open("file.txt", errors="ignore") as f:
|
||||||
|
- x = f.read()
|
||||||
|
29 + x = pathlib.Path("file.txt").read_text(errors="ignore")
|
||||||
|
30 |
|
||||||
|
31 | # FURB101
|
||||||
|
32 | with open("file.txt", mode="r") as f: # noqa: FURB120
|
||||||
|
|
||||||
|
FURB101 [*] `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
||||||
|
--> FURB101.py:32:6
|
||||||
|
|
|
||||||
|
31 | # FURB101
|
||||||
|
32 | with open("file.txt", mode="r") as f: # noqa: FURB120
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
33 | x = f.read()
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text()`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
30 | x = f.read()
|
||||||
|
31 |
|
||||||
|
32 | # FURB101
|
||||||
|
- with open("file.txt", mode="r") as f: # noqa: FURB120
|
||||||
|
- x = f.read()
|
||||||
|
33 + x = pathlib.Path("file.txt").read_text()
|
||||||
|
34 |
|
||||||
|
35 | # FURB101
|
||||||
|
36 | with open(foo(), "rb") as f:
|
||||||
|
note: This is an unsafe fix and may change runtime behavior
|
||||||
|
|
||||||
|
FURB101 `open` and `read` should be replaced by `Path(foo()).read_bytes()`
|
||||||
|
--> FURB101.py:36:6
|
||||||
|
|
|
||||||
|
35 | # FURB101
|
||||||
|
36 | with open(foo(), "rb") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
37 | # The body of `with` is non-trivial, but the recommendation holds.
|
||||||
|
38 | bar("pre")
|
||||||
|
|
|
||||||
|
help: Replace with `Path(foo()).read_bytes()`
|
||||||
|
|
||||||
|
FURB101 `open` and `read` should be replaced by `Path("a.txt").read_text()`
|
||||||
|
--> FURB101.py:44:6
|
||||||
|
|
|
||||||
|
43 | # FURB101
|
||||||
|
44 | with open("a.txt") as a, open("b.txt", "rb") as b:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
45 | x = a.read()
|
||||||
|
46 | y = b.read()
|
||||||
|
|
|
||||||
|
help: Replace with `Path("a.txt").read_text()`
|
||||||
|
|
||||||
|
FURB101 `open` and `read` should be replaced by `Path("b.txt").read_bytes()`
|
||||||
|
--> FURB101.py:44:26
|
||||||
|
|
|
||||||
|
43 | # FURB101
|
||||||
|
44 | with open("a.txt") as a, open("b.txt", "rb") as b:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
45 | x = a.read()
|
||||||
|
46 | y = b.read()
|
||||||
|
|
|
||||||
|
help: Replace with `Path("b.txt").read_bytes()`
|
||||||
|
|
||||||
|
FURB101 `open` and `read` should be replaced by `Path("file.txt").read_text()`
|
||||||
|
--> FURB101.py:49:18
|
||||||
|
|
|
||||||
|
48 | # FURB101
|
||||||
|
49 | with foo() as a, open("file.txt") as b, foo() as c:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
50 | # We have other things in here, multiple with items, but
|
||||||
|
51 | # the user reads the whole file and that bit they can replace.
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").read_text()`
|
||||||
|
|
@ -0,0 +1,260 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/refurb/mod.rs
|
||||||
|
---
|
||||||
|
FURB103 [*] `open` and `write` should be replaced by `Path("file.txt").write_text("test")`
|
||||||
|
--> FURB103.py:12:6
|
||||||
|
|
|
||||||
|
11 | # FURB103
|
||||||
|
12 | with open("file.txt", "w") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
13 | f.write("test")
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text("test")`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
10 | # Errors.
|
||||||
|
11 |
|
||||||
|
12 | # FURB103
|
||||||
|
- with open("file.txt", "w") as f:
|
||||||
|
- f.write("test")
|
||||||
|
13 + pathlib.Path("file.txt").write_text("test")
|
||||||
|
14 |
|
||||||
|
15 | # FURB103
|
||||||
|
16 | with open("file.txt", "wb") as f:
|
||||||
|
|
||||||
|
FURB103 [*] `open` and `write` should be replaced by `Path("file.txt").write_bytes(foobar)`
|
||||||
|
--> FURB103.py:16:6
|
||||||
|
|
|
||||||
|
15 | # FURB103
|
||||||
|
16 | with open("file.txt", "wb") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
17 | f.write(foobar)
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_bytes(foobar)`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
14 | f.write("test")
|
||||||
|
15 |
|
||||||
|
16 | # FURB103
|
||||||
|
- with open("file.txt", "wb") as f:
|
||||||
|
- f.write(foobar)
|
||||||
|
17 + pathlib.Path("file.txt").write_bytes(foobar)
|
||||||
|
18 |
|
||||||
|
19 | # FURB103
|
||||||
|
20 | with open("file.txt", mode="wb") as f:
|
||||||
|
|
||||||
|
FURB103 [*] `open` and `write` should be replaced by `Path("file.txt").write_bytes(b"abc")`
|
||||||
|
--> FURB103.py:20:6
|
||||||
|
|
|
||||||
|
19 | # FURB103
|
||||||
|
20 | with open("file.txt", mode="wb") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
21 | f.write(b"abc")
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_bytes(b"abc")`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
18 | f.write(foobar)
|
||||||
|
19 |
|
||||||
|
20 | # FURB103
|
||||||
|
- with open("file.txt", mode="wb") as f:
|
||||||
|
- f.write(b"abc")
|
||||||
|
21 + pathlib.Path("file.txt").write_bytes(b"abc")
|
||||||
|
22 |
|
||||||
|
23 | # FURB103
|
||||||
|
24 | with open("file.txt", "w", encoding="utf8") as f:
|
||||||
|
|
||||||
|
FURB103 [*] `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, encoding="utf8")`
|
||||||
|
--> FURB103.py:24:6
|
||||||
|
|
|
||||||
|
23 | # FURB103
|
||||||
|
24 | with open("file.txt", "w", encoding="utf8") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
25 | f.write(foobar)
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, encoding="utf8")`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
22 | f.write(b"abc")
|
||||||
|
23 |
|
||||||
|
24 | # FURB103
|
||||||
|
- with open("file.txt", "w", encoding="utf8") as f:
|
||||||
|
- f.write(foobar)
|
||||||
|
25 + pathlib.Path("file.txt").write_text(foobar, encoding="utf8")
|
||||||
|
26 |
|
||||||
|
27 | # FURB103
|
||||||
|
28 | with open("file.txt", "w", errors="ignore") as f:
|
||||||
|
|
||||||
|
FURB103 [*] `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, errors="ignore")`
|
||||||
|
--> FURB103.py:28:6
|
||||||
|
|
|
||||||
|
27 | # FURB103
|
||||||
|
28 | with open("file.txt", "w", errors="ignore") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
29 | f.write(foobar)
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, errors="ignore")`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
26 | f.write(foobar)
|
||||||
|
27 |
|
||||||
|
28 | # FURB103
|
||||||
|
- with open("file.txt", "w", errors="ignore") as f:
|
||||||
|
- f.write(foobar)
|
||||||
|
29 + pathlib.Path("file.txt").write_text(foobar, errors="ignore")
|
||||||
|
30 |
|
||||||
|
31 | # FURB103
|
||||||
|
32 | with open("file.txt", mode="w") as f:
|
||||||
|
|
||||||
|
FURB103 [*] `open` and `write` should be replaced by `Path("file.txt").write_text(foobar)`
|
||||||
|
--> FURB103.py:32:6
|
||||||
|
|
|
||||||
|
31 | # FURB103
|
||||||
|
32 | with open("file.txt", mode="w") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
33 | f.write(foobar)
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar)`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
30 | f.write(foobar)
|
||||||
|
31 |
|
||||||
|
32 | # FURB103
|
||||||
|
- with open("file.txt", mode="w") as f:
|
||||||
|
- f.write(foobar)
|
||||||
|
33 + pathlib.Path("file.txt").write_text(foobar)
|
||||||
|
34 |
|
||||||
|
35 | # FURB103
|
||||||
|
36 | with open(foo(), "wb") as f:
|
||||||
|
|
||||||
|
FURB103 `open` and `write` should be replaced by `Path(foo()).write_bytes(bar())`
|
||||||
|
--> FURB103.py:36:6
|
||||||
|
|
|
||||||
|
35 | # FURB103
|
||||||
|
36 | with open(foo(), "wb") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
37 | # The body of `with` is non-trivial, but the recommendation holds.
|
||||||
|
38 | bar("pre")
|
||||||
|
|
|
||||||
|
help: Replace with `Path(foo()).write_bytes(bar())`
|
||||||
|
|
||||||
|
FURB103 `open` and `write` should be replaced by `Path("a.txt").write_text(x)`
|
||||||
|
--> FURB103.py:44:6
|
||||||
|
|
|
||||||
|
43 | # FURB103
|
||||||
|
44 | with open("a.txt", "w") as a, open("b.txt", "wb") as b:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
45 | a.write(x)
|
||||||
|
46 | b.write(y)
|
||||||
|
|
|
||||||
|
help: Replace with `Path("a.txt").write_text(x)`
|
||||||
|
|
||||||
|
FURB103 `open` and `write` should be replaced by `Path("b.txt").write_bytes(y)`
|
||||||
|
--> FURB103.py:44:31
|
||||||
|
|
|
||||||
|
43 | # FURB103
|
||||||
|
44 | with open("a.txt", "w") as a, open("b.txt", "wb") as b:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
45 | a.write(x)
|
||||||
|
46 | b.write(y)
|
||||||
|
|
|
||||||
|
help: Replace with `Path("b.txt").write_bytes(y)`
|
||||||
|
|
||||||
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(bar(bar(a + x)))`
|
||||||
|
--> FURB103.py:49:18
|
||||||
|
|
|
||||||
|
48 | # FURB103
|
||||||
|
49 | with foo() as a, open("file.txt", "w") as b, foo() as c:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
50 | # We have other things in here, multiple with items, but the user
|
||||||
|
51 | # writes a single time to file and that bit they can replace.
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(bar(bar(a + x)))`
|
||||||
|
|
||||||
|
FURB103 [*] `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
|
--> FURB103.py:58:6
|
||||||
|
|
|
||||||
|
57 | # FURB103
|
||||||
|
58 | with open("file.txt", "w", newline="\r\n") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
59 | f.write(foobar)
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
|
1 + import pathlib
|
||||||
|
2 | def foo():
|
||||||
|
3 | ...
|
||||||
|
4 |
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
56 |
|
||||||
|
57 |
|
||||||
|
58 | # FURB103
|
||||||
|
- with open("file.txt", "w", newline="\r\n") as f:
|
||||||
|
- f.write(foobar)
|
||||||
|
59 + pathlib.Path("file.txt").write_text(foobar, newline="\r\n")
|
||||||
|
60 |
|
||||||
|
61 |
|
||||||
|
62 | import builtins
|
||||||
|
|
||||||
|
FURB103 [*] `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
|
--> FURB103.py:66:6
|
||||||
|
|
|
||||||
|
65 | # FURB103
|
||||||
|
66 | with builtins.open("file.txt", "w", newline="\r\n") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
67 | f.write(foobar)
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
|
60 |
|
||||||
|
61 |
|
||||||
|
62 | import builtins
|
||||||
|
63 + import pathlib
|
||||||
|
64 |
|
||||||
|
65 |
|
||||||
|
66 | # FURB103
|
||||||
|
- with builtins.open("file.txt", "w", newline="\r\n") as f:
|
||||||
|
- f.write(foobar)
|
||||||
|
67 + pathlib.Path("file.txt").write_text(foobar, newline="\r\n")
|
||||||
|
68 |
|
||||||
|
69 |
|
||||||
|
70 | from builtins import open as o
|
||||||
|
|
||||||
|
FURB103 [*] `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
|
--> FURB103.py:74:6
|
||||||
|
|
|
||||||
|
73 | # FURB103
|
||||||
|
74 | with o("file.txt", "w", newline="\r\n") as f:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
75 | f.write(foobar)
|
||||||
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, newline="\r\n")`
|
||||||
|
68 |
|
||||||
|
69 |
|
||||||
|
70 | from builtins import open as o
|
||||||
|
71 + import pathlib
|
||||||
|
72 |
|
||||||
|
73 |
|
||||||
|
74 | # FURB103
|
||||||
|
- with o("file.txt", "w", newline="\r\n") as f:
|
||||||
|
- f.write(foobar)
|
||||||
|
75 + pathlib.Path("file.txt").write_text(foobar, newline="\r\n")
|
||||||
|
76 |
|
||||||
|
77 | # Non-errors.
|
||||||
|
78 |
|
||||||
|
|
@ -9,6 +9,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text("t
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
13 | f.write("test")
|
13 | f.write("test")
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text("test")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(foobar)`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(foobar)`
|
||||||
--> FURB103.py:16:6
|
--> FURB103.py:16:6
|
||||||
|
|
@ -18,6 +19,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(f
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
17 | f.write(foobar)
|
17 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_bytes(foobar)`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(b"abc")`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(b"abc")`
|
||||||
--> FURB103.py:20:6
|
--> FURB103.py:20:6
|
||||||
|
|
@ -27,6 +29,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_bytes(b
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
21 | f.write(b"abc")
|
21 | f.write(b"abc")
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_bytes(b"abc")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, encoding="utf8")`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, encoding="utf8")`
|
||||||
--> FURB103.py:24:6
|
--> FURB103.py:24:6
|
||||||
|
|
@ -36,6 +39,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
25 | f.write(foobar)
|
25 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, encoding="utf8")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, errors="ignore")`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar, errors="ignore")`
|
||||||
--> FURB103.py:28:6
|
--> FURB103.py:28:6
|
||||||
|
|
@ -45,6 +49,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
29 | f.write(foobar)
|
29 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar, errors="ignore")`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar)`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(foobar)`
|
||||||
--> FURB103.py:32:6
|
--> FURB103.py:32:6
|
||||||
|
|
@ -54,6 +59,7 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
33 | f.write(foobar)
|
33 | f.write(foobar)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(foobar)`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path(foo()).write_bytes(bar())`
|
FURB103 `open` and `write` should be replaced by `Path(foo()).write_bytes(bar())`
|
||||||
--> FURB103.py:36:6
|
--> FURB103.py:36:6
|
||||||
|
|
@ -64,6 +70,7 @@ FURB103 `open` and `write` should be replaced by `Path(foo()).write_bytes(bar())
|
||||||
37 | # The body of `with` is non-trivial, but the recommendation holds.
|
37 | # The body of `with` is non-trivial, but the recommendation holds.
|
||||||
38 | bar("pre")
|
38 | bar("pre")
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path(foo()).write_bytes(bar())`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("a.txt").write_text(x)`
|
FURB103 `open` and `write` should be replaced by `Path("a.txt").write_text(x)`
|
||||||
--> FURB103.py:44:6
|
--> FURB103.py:44:6
|
||||||
|
|
@ -74,6 +81,7 @@ FURB103 `open` and `write` should be replaced by `Path("a.txt").write_text(x)`
|
||||||
45 | a.write(x)
|
45 | a.write(x)
|
||||||
46 | b.write(y)
|
46 | b.write(y)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("a.txt").write_text(x)`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("b.txt").write_bytes(y)`
|
FURB103 `open` and `write` should be replaced by `Path("b.txt").write_bytes(y)`
|
||||||
--> FURB103.py:44:31
|
--> FURB103.py:44:31
|
||||||
|
|
@ -84,6 +92,7 @@ FURB103 `open` and `write` should be replaced by `Path("b.txt").write_bytes(y)`
|
||||||
45 | a.write(x)
|
45 | a.write(x)
|
||||||
46 | b.write(y)
|
46 | b.write(y)
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("b.txt").write_bytes(y)`
|
||||||
|
|
||||||
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(bar(bar(a + x)))`
|
FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(bar(bar(a + x)))`
|
||||||
--> FURB103.py:49:18
|
--> FURB103.py:49:18
|
||||||
|
|
@ -94,3 +103,4 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(ba
|
||||||
50 | # We have other things in here, multiple with items, but the user
|
50 | # We have other things in here, multiple with items, but the user
|
||||||
51 | # writes a single time to file and that bit they can replace.
|
51 | # writes a single time to file and that bit they can replace.
|
||||||
|
|
|
|
||||||
|
help: Replace with `Path("file.txt").write_text(bar(bar(a + x)))`
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue