From 5bf4759cff7d0dbb74523efb1f1ebd02ae7e62c1 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 10 Nov 2024 22:48:30 -0500 Subject: [PATCH] Detect permutations in redundant open modes (#14255) ## Summary Closes https://github.com/astral-sh/ruff/issues/14235. --- Cargo.lock | 1 + .../test/fixtures/pyupgrade/UP015.py | 18 +- .../src/rules/pylint/rules/bad_open_mode.rs | 87 +- .../pyupgrade/rules/redundant_open_modes.rs | 124 +- ...er__rules__pyupgrade__tests__UP015.py.snap | 1205 +++++++++-------- crates/ruff_python_stdlib/Cargo.toml | 1 + crates/ruff_python_stdlib/src/lib.rs | 1 + crates/ruff_python_stdlib/src/open_mode.rs | 146 ++ 8 files changed, 821 insertions(+), 762 deletions(-) create mode 100644 crates/ruff_python_stdlib/src/open_mode.rs diff --git a/Cargo.lock b/Cargo.lock index 6c0c68e182..974be6f998 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2911,6 +2911,7 @@ dependencies = [ name = "ruff_python_stdlib" version = "0.0.0" dependencies = [ + "bitflags 2.6.0", "unicode-ident", ] diff --git a/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP015.py b/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP015.py index 9f78caef4c..a3ba91645b 100644 --- a/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP015.py +++ b/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP015.py @@ -6,6 +6,7 @@ open("foo", "r") open("foo", "rt") open("f", "r", encoding="UTF-8") open("f", "wt") +open("f", "tw") with open("foo", "U") as f: pass @@ -69,19 +70,14 @@ open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -open = 1 -open("foo", "U") -open("foo", "Ur") -open("foo", "Ub") -open("foo", "rUb") -open("foo", "r") -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") + +open("foo", "r+") +open("foo", "rb") +open("foo", "r+b") +open("foo", "UU") +open("foo", "wtt") diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_open_mode.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_open_mode.rs index 0b66cab8ce..acd081f327 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_open_mode.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_open_mode.rs @@ -1,9 +1,8 @@ -use bitflags::bitflags; - use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Expr}; use ruff_python_semantic::SemanticModel; +use ruff_python_stdlib::open_mode::OpenMode; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -59,11 +58,11 @@ pub(crate) fn bad_open_mode(checker: &mut Checker, call: &ast::ExprCall) { return; }; - let ast::Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = mode else { + let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = mode else { return; }; - if is_valid_mode(value) { + if OpenMode::from_chars(value.chars()).is_ok() { return; } @@ -112,83 +111,3 @@ fn extract_mode(call: &ast::ExprCall, kind: Kind) -> Option<&Expr> { Kind::Pathlib => call.arguments.find_argument("mode", 0), } } - -bitflags! { - #[derive(Copy, Clone, Debug, PartialEq, Eq)] - pub(super) struct OpenMode: u8 { - /// `r` - const READ = 0b0001; - /// `w` - const WRITE = 0b0010; - /// `a` - const APPEND = 0b0100; - /// `x` - const CREATE = 0b1000; - /// `b` - const BINARY = 0b10000; - /// `t` - const TEXT = 0b10_0000; - /// `+` - const PLUS = 0b100_0000; - /// `U` - const UNIVERSAL_NEWLINES = 0b1000_0000; - - } -} - -impl TryFrom for OpenMode { - type Error = (); - - fn try_from(value: char) -> Result { - match value { - 'r' => Ok(Self::READ), - 'w' => Ok(Self::WRITE), - 'a' => Ok(Self::APPEND), - 'x' => Ok(Self::CREATE), - 'b' => Ok(Self::BINARY), - 't' => Ok(Self::TEXT), - '+' => Ok(Self::PLUS), - 'U' => Ok(Self::UNIVERSAL_NEWLINES), - _ => Err(()), - } - } -} - -/// Returns `true` if the open mode is valid. -fn is_valid_mode(mode: &ast::StringLiteralValue) -> bool { - // Flag duplicates and invalid characters. - let mut flags = OpenMode::empty(); - for char in mode.chars() { - let Ok(flag) = OpenMode::try_from(char) else { - return false; - }; - if flags.intersects(flag) { - return false; - } - flags.insert(flag); - } - - // Both text and binary mode cannot be set at the same time. - if flags.contains(OpenMode::TEXT | OpenMode::BINARY) { - return false; - } - - // The `U` mode is only valid with `r`. - if flags.contains(OpenMode::UNIVERSAL_NEWLINES) - && flags.intersects(OpenMode::WRITE | OpenMode::APPEND | OpenMode::CREATE) - { - return false; - } - - // Otherwise, reading, writing, creating, and appending are mutually exclusive. - [ - OpenMode::READ | OpenMode::UNIVERSAL_NEWLINES, - OpenMode::WRITE, - OpenMode::CREATE, - OpenMode::APPEND, - ] - .into_iter() - .filter(|flag| flags.intersects(*flag)) - .count() - == 1 -} 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 bba1afbdba..321907aae4 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 @@ -1,11 +1,10 @@ -use std::str::FromStr; - -use anyhow::{anyhow, Result}; - +use anyhow::Result; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Expr}; +use ruff_python_codegen::Stylist; use ruff_python_parser::{TokenKind, Tokens}; +use ruff_python_stdlib::open_mode::OpenMode; use ruff_text_size::{Ranged, TextSize}; use crate::checkers::ast::Checker; @@ -33,26 +32,26 @@ use crate::checkers::ast::Checker; /// - [Python documentation: `open`](https://docs.python.org/3/library/functions.html#open) #[violation] pub struct RedundantOpenModes { - replacement: Option, + replacement: String, } impl AlwaysFixableViolation for RedundantOpenModes { #[derive_message_formats] fn message(&self) -> String { - match &self.replacement { - None => "Unnecessary open mode parameters".to_string(), - Some(replacement) => { - format!("Unnecessary open mode parameters, use \"{replacement}\"") - } + let RedundantOpenModes { replacement } = self; + if replacement.is_empty() { + "Unnecessary open mode parameters".to_string() + } else { + format!("Unnecessary open mode parameters, use \"{replacement}\"") } } fn fix_title(&self) -> String { - match &self.replacement { - None => "Remove open mode parameters".to_string(), - Some(replacement) => { - format!("Replace with \"{replacement}\"") - } + let RedundantOpenModes { replacement } = self; + if replacement.is_empty() { + "Remove open mode parameters".to_string() + } else { + format!("Replace with \"{replacement}\"") } } } @@ -81,13 +80,17 @@ pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall) .. }) = &keyword.value { - if let Ok(mode) = OpenMode::from_str(mode_param_value.to_str()) { - checker.diagnostics.push(create_diagnostic( - call, - &keyword.value, - mode.replacement_value(), - checker.tokens(), - )); + if let Ok(mode) = OpenMode::from_chars(mode_param_value.chars()) { + let reduced = mode.reduce(); + if reduced != mode { + checker.diagnostics.push(create_diagnostic( + call, + &keyword.value, + reduced, + checker.tokens(), + checker.stylist(), + )); + } } } } @@ -95,82 +98,45 @@ pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall) } Some(mode_param) => { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &mode_param { - if let Ok(mode) = OpenMode::from_str(value.to_str()) { - checker.diagnostics.push(create_diagnostic( - call, - mode_param, - mode.replacement_value(), - checker.tokens(), - )); + if let Ok(mode) = OpenMode::from_chars(value.chars()) { + let reduced = mode.reduce(); + if reduced != mode { + checker.diagnostics.push(create_diagnostic( + call, + mode_param, + reduced, + checker.tokens(), + checker.stylist(), + )); + } } } } } } -#[derive(Debug, Copy, Clone)] -enum OpenMode { - U, - Ur, - Ub, - RUb, - R, - Rt, - Wt, -} - -impl FromStr for OpenMode { - type Err = anyhow::Error; - - fn from_str(string: &str) -> Result { - match string { - "U" => Ok(Self::U), - "Ur" => Ok(Self::Ur), - "Ub" => Ok(Self::Ub), - "rUb" => Ok(Self::RUb), - "r" => Ok(Self::R), - "rt" => Ok(Self::Rt), - "wt" => Ok(Self::Wt), - _ => Err(anyhow!("Unknown open mode: {}", string)), - } - } -} - -impl OpenMode { - fn replacement_value(self) -> Option<&'static str> { - match self { - Self::U => None, - Self::Ur => None, - Self::Ub => Some("\"rb\""), - Self::RUb => Some("\"rb\""), - Self::R => None, - Self::Rt => None, - Self::Wt => Some("\"w\""), - } - } -} - fn create_diagnostic( call: &ast::ExprCall, mode_param: &Expr, - replacement_value: Option<&str>, + mode: OpenMode, tokens: &Tokens, + stylist: &Stylist, ) -> Diagnostic { let mut diagnostic = Diagnostic::new( RedundantOpenModes { - replacement: replacement_value.map(ToString::to_string), + replacement: mode.to_string(), }, call.range(), ); - if let Some(content) = replacement_value { - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - content.to_string(), - mode_param.range(), - ))); - } else { + if mode.is_empty() { diagnostic .try_set_fix(|| create_remove_param_fix(call, mode_param, tokens).map(Fix::safe_edit)); + } else { + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + format!("{}{mode}{}", stylist.quote(), stylist.quote()), + mode_param.range(), + ))); } diagnostic 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 054bc00ec8..22e3044b55 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 @@ -35,7 +35,7 @@ UP015.py:2:1: UP015 [*] Unnecessary open mode parameters 4 4 | open("foo", "rUb") 5 5 | open("foo", "r") -UP015.py:3:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:3:1: UP015 [*] Unnecessary open mode parameters, use "rb" | 1 | open("foo", "U") 2 | open("foo", "Ur") @@ -44,7 +44,7 @@ UP015.py:3:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" 4 | open("foo", "rUb") 5 | open("foo", "r") | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix 1 1 | open("foo", "U") @@ -55,7 +55,7 @@ UP015.py:3:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" 5 5 | open("foo", "r") 6 6 | open("foo", "rt") -UP015.py:4:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:4:1: UP015 [*] Unnecessary open mode parameters, use "rb" | 2 | open("foo", "Ur") 3 | open("foo", "Ub") @@ -64,7 +64,7 @@ UP015.py:4:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" 5 | open("foo", "r") 6 | open("foo", "rt") | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix 1 1 | open("foo", "U") @@ -116,7 +116,7 @@ UP015.py:6:1: UP015 [*] Unnecessary open mode parameters 6 |+open("foo") 7 7 | open("f", "r", encoding="UTF-8") 8 8 | open("f", "wt") -9 9 | +9 9 | open("f", "tw") UP015.py:7:1: UP015 [*] Unnecessary open mode parameters | @@ -125,6 +125,7 @@ UP015.py:7:1: UP015 [*] Unnecessary open mode parameters 7 | open("f", "r", encoding="UTF-8") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 8 | open("f", "wt") +9 | open("f", "tw") | = help: Remove open mode parameters @@ -135,19 +136,18 @@ UP015.py:7:1: UP015 [*] Unnecessary open mode parameters 7 |-open("f", "r", encoding="UTF-8") 7 |+open("f", encoding="UTF-8") 8 8 | open("f", "wt") -9 9 | -10 10 | with open("foo", "U") as f: +9 9 | open("f", "tw") +10 10 | -UP015.py:8:1: UP015 [*] Unnecessary open mode parameters, use ""w"" - | - 6 | open("foo", "rt") - 7 | open("f", "r", encoding="UTF-8") - 8 | open("f", "wt") - | ^^^^^^^^^^^^^^^ UP015 - 9 | -10 | with open("foo", "U") as f: - | - = help: Replace with ""w"" +UP015.py:8:1: UP015 [*] Unnecessary open mode parameters, use "w" + | +6 | open("foo", "rt") +7 | open("f", "r", encoding="UTF-8") +8 | open("f", "wt") + | ^^^^^^^^^^^^^^^ UP015 +9 | open("f", "tw") + | + = help: Replace with "w" ℹ Safe fix 5 5 | open("foo", "r") @@ -155,799 +155,828 @@ UP015.py:8:1: UP015 [*] Unnecessary open mode parameters, use ""w"" 7 7 | open("f", "r", encoding="UTF-8") 8 |-open("f", "wt") 8 |+open("f", "w") -9 9 | -10 10 | with open("foo", "U") as f: -11 11 | pass +9 9 | open("f", "tw") +10 10 | +11 11 | with open("foo", "U") as f: -UP015.py:10:6: UP015 [*] Unnecessary open mode parameters +UP015.py:9:1: UP015 [*] Unnecessary open mode parameters, use "w" | + 7 | open("f", "r", encoding="UTF-8") 8 | open("f", "wt") - 9 | -10 | with open("foo", "U") as f: - | ^^^^^^^^^^^^^^^^ UP015 -11 | pass -12 | with open("foo", "Ur") as f: + 9 | open("f", "tw") + | ^^^^^^^^^^^^^^^ UP015 +10 | +11 | with open("foo", "U") as f: | - = help: Remove open mode parameters + = help: Replace with "w" ℹ Safe fix +6 6 | open("foo", "rt") 7 7 | open("f", "r", encoding="UTF-8") 8 8 | open("f", "wt") -9 9 | -10 |-with open("foo", "U") as f: - 10 |+with open("foo") as f: -11 11 | pass -12 12 | with open("foo", "Ur") as f: -13 13 | pass +9 |-open("f", "tw") + 9 |+open("f", "w") +10 10 | +11 11 | with open("foo", "U") as f: +12 12 | pass -UP015.py:12:6: UP015 [*] Unnecessary open mode parameters +UP015.py:11:6: UP015 [*] Unnecessary open mode parameters | -10 | with open("foo", "U") as f: -11 | pass -12 | with open("foo", "Ur") as f: - | ^^^^^^^^^^^^^^^^^ UP015 -13 | pass -14 | with open("foo", "Ub") as f: + 9 | open("f", "tw") +10 | +11 | with open("foo", "U") as f: + | ^^^^^^^^^^^^^^^^ UP015 +12 | pass +13 | with open("foo", "Ur") as f: | = help: Remove open mode parameters ℹ Safe fix -9 9 | -10 10 | with open("foo", "U") as f: -11 11 | pass -12 |-with open("foo", "Ur") as f: - 12 |+with open("foo") as f: -13 13 | pass -14 14 | with open("foo", "Ub") as f: -15 15 | pass +8 8 | open("f", "wt") +9 9 | open("f", "tw") +10 10 | +11 |-with open("foo", "U") as f: + 11 |+with open("foo") as f: +12 12 | pass +13 13 | with open("foo", "Ur") as f: +14 14 | pass -UP015.py:14:6: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:13:6: UP015 [*] Unnecessary open mode parameters | -12 | with open("foo", "Ur") as f: -13 | pass -14 | with open("foo", "Ub") as f: +11 | with open("foo", "U") as f: +12 | pass +13 | with open("foo", "Ur") as f: | ^^^^^^^^^^^^^^^^^ UP015 -15 | pass -16 | with open("foo", "rUb") as f: +14 | pass +15 | with open("foo", "Ub") as f: | - = help: Replace with ""rb"" + = help: Remove open mode parameters ℹ Safe fix -11 11 | pass -12 12 | with open("foo", "Ur") as f: -13 13 | pass -14 |-with open("foo", "Ub") as f: - 14 |+with open("foo", "rb") as f: -15 15 | pass -16 16 | with open("foo", "rUb") as f: -17 17 | pass +10 10 | +11 11 | with open("foo", "U") as f: +12 12 | pass +13 |-with open("foo", "Ur") as f: + 13 |+with open("foo") as f: +14 14 | pass +15 15 | with open("foo", "Ub") as f: +16 16 | pass -UP015.py:16:6: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:15:6: UP015 [*] Unnecessary open mode parameters, use "rb" | -14 | with open("foo", "Ub") as f: -15 | pass -16 | with open("foo", "rUb") as f: +13 | with open("foo", "Ur") as f: +14 | pass +15 | with open("foo", "Ub") as f: + | ^^^^^^^^^^^^^^^^^ UP015 +16 | pass +17 | with open("foo", "rUb") as f: + | + = help: Replace with "rb" + +ℹ Safe fix +12 12 | pass +13 13 | with open("foo", "Ur") as f: +14 14 | pass +15 |-with open("foo", "Ub") as f: + 15 |+with open("foo", "rb") as f: +16 16 | pass +17 17 | with open("foo", "rUb") as f: +18 18 | pass + +UP015.py:17:6: UP015 [*] Unnecessary open mode parameters, use "rb" + | +15 | with open("foo", "Ub") as f: +16 | pass +17 | with open("foo", "rUb") as f: | ^^^^^^^^^^^^^^^^^^ UP015 -17 | pass -18 | with open("foo", "r") as f: +18 | pass +19 | with open("foo", "r") as f: | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -13 13 | pass -14 14 | with open("foo", "Ub") as f: -15 15 | pass -16 |-with open("foo", "rUb") as f: - 16 |+with open("foo", "rb") as f: -17 17 | pass -18 18 | with open("foo", "r") as f: -19 19 | pass +14 14 | pass +15 15 | with open("foo", "Ub") as f: +16 16 | pass +17 |-with open("foo", "rUb") as f: + 17 |+with open("foo", "rb") as f: +18 18 | pass +19 19 | with open("foo", "r") as f: +20 20 | pass -UP015.py:18:6: UP015 [*] Unnecessary open mode parameters +UP015.py:19:6: UP015 [*] Unnecessary open mode parameters | -16 | with open("foo", "rUb") as f: -17 | pass -18 | with open("foo", "r") as f: +17 | with open("foo", "rUb") as f: +18 | pass +19 | with open("foo", "r") as f: | ^^^^^^^^^^^^^^^^ UP015 -19 | pass -20 | with open("foo", "rt") as f: +20 | pass +21 | with open("foo", "rt") as f: | = help: Remove open mode parameters ℹ Safe fix -15 15 | pass -16 16 | with open("foo", "rUb") as f: -17 17 | pass -18 |-with open("foo", "r") as f: - 18 |+with open("foo") as f: -19 19 | pass -20 20 | with open("foo", "rt") as f: -21 21 | pass +16 16 | pass +17 17 | with open("foo", "rUb") as f: +18 18 | pass +19 |-with open("foo", "r") as f: + 19 |+with open("foo") as f: +20 20 | pass +21 21 | with open("foo", "rt") as f: +22 22 | pass -UP015.py:20:6: UP015 [*] Unnecessary open mode parameters +UP015.py:21:6: UP015 [*] Unnecessary open mode parameters | -18 | with open("foo", "r") as f: -19 | pass -20 | with open("foo", "rt") as f: +19 | with open("foo", "r") as f: +20 | pass +21 | with open("foo", "rt") as f: | ^^^^^^^^^^^^^^^^^ UP015 -21 | pass -22 | with open("foo", "r", encoding="UTF-8") as f: +22 | pass +23 | with open("foo", "r", encoding="UTF-8") as f: | = help: Remove open mode parameters ℹ Safe fix -17 17 | pass -18 18 | with open("foo", "r") as f: -19 19 | pass -20 |-with open("foo", "rt") as f: - 20 |+with open("foo") as f: -21 21 | pass -22 22 | with open("foo", "r", encoding="UTF-8") as f: -23 23 | pass +18 18 | pass +19 19 | with open("foo", "r") as f: +20 20 | pass +21 |-with open("foo", "rt") as f: + 21 |+with open("foo") as f: +22 22 | pass +23 23 | with open("foo", "r", encoding="UTF-8") as f: +24 24 | pass -UP015.py:22:6: UP015 [*] Unnecessary open mode parameters +UP015.py:23:6: UP015 [*] Unnecessary open mode parameters | -20 | with open("foo", "rt") as f: -21 | pass -22 | with open("foo", "r", encoding="UTF-8") as f: +21 | with open("foo", "rt") as f: +22 | pass +23 | with open("foo", "r", encoding="UTF-8") as f: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -23 | pass -24 | with open("foo", "wt") as f: +24 | pass +25 | with open("foo", "wt") as f: | = help: Remove open mode parameters ℹ Safe fix -19 19 | pass -20 20 | with open("foo", "rt") as f: -21 21 | pass -22 |-with open("foo", "r", encoding="UTF-8") as f: - 22 |+with open("foo", encoding="UTF-8") as f: -23 23 | pass -24 24 | with open("foo", "wt") as f: -25 25 | pass +20 20 | pass +21 21 | with open("foo", "rt") as f: +22 22 | pass +23 |-with open("foo", "r", encoding="UTF-8") as f: + 23 |+with open("foo", encoding="UTF-8") as f: +24 24 | pass +25 25 | with open("foo", "wt") as f: +26 26 | pass -UP015.py:24:6: UP015 [*] Unnecessary open mode parameters, use ""w"" +UP015.py:25:6: UP015 [*] Unnecessary open mode parameters, use "w" | -22 | with open("foo", "r", encoding="UTF-8") as f: -23 | pass -24 | with open("foo", "wt") as f: +23 | with open("foo", "r", encoding="UTF-8") as f: +24 | pass +25 | with open("foo", "wt") as f: | ^^^^^^^^^^^^^^^^^ UP015 -25 | pass +26 | pass | - = help: Replace with ""w"" + = help: Replace with "w" ℹ Safe fix -21 21 | pass -22 22 | with open("foo", "r", encoding="UTF-8") as f: -23 23 | pass -24 |-with open("foo", "wt") as f: - 24 |+with open("foo", "w") as f: -25 25 | pass -26 26 | -27 27 | open(f("a", "b", "c"), "U") +22 22 | pass +23 23 | with open("foo", "r", encoding="UTF-8") as f: +24 24 | pass +25 |-with open("foo", "wt") as f: + 25 |+with open("foo", "w") as f: +26 26 | pass +27 27 | +28 28 | open(f("a", "b", "c"), "U") -UP015.py:27:1: UP015 [*] Unnecessary open mode parameters +UP015.py:28:1: UP015 [*] Unnecessary open mode parameters | -25 | pass -26 | -27 | open(f("a", "b", "c"), "U") +26 | pass +27 | +28 | open(f("a", "b", "c"), "U") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -28 | open(f("a", "b", "c"), "Ub") +29 | open(f("a", "b", "c"), "Ub") | = help: Remove open mode parameters ℹ Safe fix -24 24 | with open("foo", "wt") as f: -25 25 | pass -26 26 | -27 |-open(f("a", "b", "c"), "U") - 27 |+open(f("a", "b", "c")) -28 28 | open(f("a", "b", "c"), "Ub") -29 29 | -30 30 | with open(f("a", "b", "c"), "U") as f: +25 25 | with open("foo", "wt") as f: +26 26 | pass +27 27 | +28 |-open(f("a", "b", "c"), "U") + 28 |+open(f("a", "b", "c")) +29 29 | open(f("a", "b", "c"), "Ub") +30 30 | +31 31 | with open(f("a", "b", "c"), "U") as f: -UP015.py:28:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:29:1: UP015 [*] Unnecessary open mode parameters, use "rb" | -27 | open(f("a", "b", "c"), "U") -28 | open(f("a", "b", "c"), "Ub") +28 | open(f("a", "b", "c"), "U") +29 | open(f("a", "b", "c"), "Ub") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -29 | -30 | with open(f("a", "b", "c"), "U") as f: +30 | +31 | with open(f("a", "b", "c"), "U") as f: | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -25 25 | pass -26 26 | -27 27 | open(f("a", "b", "c"), "U") -28 |-open(f("a", "b", "c"), "Ub") - 28 |+open(f("a", "b", "c"), "rb") -29 29 | -30 30 | with open(f("a", "b", "c"), "U") as f: -31 31 | pass +26 26 | pass +27 27 | +28 28 | open(f("a", "b", "c"), "U") +29 |-open(f("a", "b", "c"), "Ub") + 29 |+open(f("a", "b", "c"), "rb") +30 30 | +31 31 | with open(f("a", "b", "c"), "U") as f: +32 32 | pass -UP015.py:30:6: UP015 [*] Unnecessary open mode parameters +UP015.py:31:6: UP015 [*] Unnecessary open mode parameters | -28 | open(f("a", "b", "c"), "Ub") -29 | -30 | with open(f("a", "b", "c"), "U") as f: +29 | open(f("a", "b", "c"), "Ub") +30 | +31 | with open(f("a", "b", "c"), "U") as f: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -31 | pass -32 | with open(f("a", "b", "c"), "Ub") as f: +32 | pass +33 | with open(f("a", "b", "c"), "Ub") as f: | = help: Remove open mode parameters ℹ Safe fix -27 27 | open(f("a", "b", "c"), "U") -28 28 | open(f("a", "b", "c"), "Ub") -29 29 | -30 |-with open(f("a", "b", "c"), "U") as f: - 30 |+with open(f("a", "b", "c")) as f: -31 31 | pass -32 32 | with open(f("a", "b", "c"), "Ub") as f: -33 33 | pass +28 28 | open(f("a", "b", "c"), "U") +29 29 | open(f("a", "b", "c"), "Ub") +30 30 | +31 |-with open(f("a", "b", "c"), "U") as f: + 31 |+with open(f("a", "b", "c")) as f: +32 32 | pass +33 33 | with open(f("a", "b", "c"), "Ub") as f: +34 34 | pass -UP015.py:32:6: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:33:6: UP015 [*] Unnecessary open mode parameters, use "rb" | -30 | with open(f("a", "b", "c"), "U") as f: -31 | pass -32 | with open(f("a", "b", "c"), "Ub") as f: +31 | with open(f("a", "b", "c"), "U") as f: +32 | pass +33 | with open(f("a", "b", "c"), "Ub") as f: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -33 | pass +34 | pass | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -29 29 | -30 30 | with open(f("a", "b", "c"), "U") as f: -31 31 | pass -32 |-with open(f("a", "b", "c"), "Ub") as f: - 32 |+with open(f("a", "b", "c"), "rb") as f: -33 33 | pass -34 34 | -35 35 | with open("foo", "U") as fa, open("bar", "U") as fb: +30 30 | +31 31 | with open(f("a", "b", "c"), "U") as f: +32 32 | pass +33 |-with open(f("a", "b", "c"), "Ub") as f: + 33 |+with open(f("a", "b", "c"), "rb") as f: +34 34 | pass +35 35 | +36 36 | with open("foo", "U") as fa, open("bar", "U") as fb: -UP015.py:35:6: UP015 [*] Unnecessary open mode parameters +UP015.py:36:6: UP015 [*] Unnecessary open mode parameters | -33 | pass -34 | -35 | with open("foo", "U") as fa, open("bar", "U") as fb: +34 | pass +35 | +36 | with open("foo", "U") as fa, open("bar", "U") as fb: | ^^^^^^^^^^^^^^^^ UP015 -36 | pass -37 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: +37 | pass +38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: | = help: Remove open mode parameters ℹ Safe fix -32 32 | with open(f("a", "b", "c"), "Ub") as f: -33 33 | pass -34 34 | -35 |-with open("foo", "U") as fa, open("bar", "U") as fb: - 35 |+with open("foo") as fa, open("bar", "U") as fb: -36 36 | pass -37 37 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: -38 38 | pass +33 33 | with open(f("a", "b", "c"), "Ub") as f: +34 34 | pass +35 35 | +36 |-with open("foo", "U") as fa, open("bar", "U") as fb: + 36 |+with open("foo") as fa, open("bar", "U") as fb: +37 37 | pass +38 38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: +39 39 | pass -UP015.py:35:30: UP015 [*] Unnecessary open mode parameters +UP015.py:36:30: UP015 [*] Unnecessary open mode parameters | -33 | pass -34 | -35 | with open("foo", "U") as fa, open("bar", "U") as fb: +34 | pass +35 | +36 | with open("foo", "U") as fa, open("bar", "U") as fb: | ^^^^^^^^^^^^^^^^ UP015 -36 | pass -37 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: +37 | pass +38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: | = help: Remove open mode parameters ℹ Safe fix -32 32 | with open(f("a", "b", "c"), "Ub") as f: -33 33 | pass -34 34 | -35 |-with open("foo", "U") as fa, open("bar", "U") as fb: - 35 |+with open("foo", "U") as fa, open("bar") as fb: -36 36 | pass -37 37 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: -38 38 | pass +33 33 | with open(f("a", "b", "c"), "Ub") as f: +34 34 | pass +35 35 | +36 |-with open("foo", "U") as fa, open("bar", "U") as fb: + 36 |+with open("foo", "U") as fa, open("bar") as fb: +37 37 | pass +38 38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: +39 39 | pass -UP015.py:37:6: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:38:6: UP015 [*] Unnecessary open mode parameters, use "rb" | -35 | with open("foo", "U") as fa, open("bar", "U") as fb: -36 | pass -37 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: +36 | with open("foo", "U") as fa, open("bar", "U") as fb: +37 | pass +38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: | ^^^^^^^^^^^^^^^^^ UP015 -38 | pass +39 | pass | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -34 34 | -35 35 | with open("foo", "U") as fa, open("bar", "U") as fb: -36 36 | pass -37 |-with open("foo", "Ub") as fa, open("bar", "Ub") as fb: - 37 |+with open("foo", "rb") as fa, open("bar", "Ub") as fb: -38 38 | pass -39 39 | -40 40 | open("foo", mode="U") +35 35 | +36 36 | with open("foo", "U") as fa, open("bar", "U") as fb: +37 37 | pass +38 |-with open("foo", "Ub") as fa, open("bar", "Ub") as fb: + 38 |+with open("foo", "rb") as fa, open("bar", "Ub") as fb: +39 39 | pass +40 40 | +41 41 | open("foo", mode="U") -UP015.py:37:31: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:38:31: UP015 [*] Unnecessary open mode parameters, use "rb" | -35 | with open("foo", "U") as fa, open("bar", "U") as fb: -36 | pass -37 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: +36 | with open("foo", "U") as fa, open("bar", "U") as fb: +37 | pass +38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: | ^^^^^^^^^^^^^^^^^ UP015 -38 | pass +39 | pass | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -34 34 | -35 35 | with open("foo", "U") as fa, open("bar", "U") as fb: -36 36 | pass -37 |-with open("foo", "Ub") as fa, open("bar", "Ub") as fb: - 37 |+with open("foo", "Ub") as fa, open("bar", "rb") as fb: -38 38 | pass -39 39 | -40 40 | open("foo", mode="U") - -UP015.py:40:1: UP015 [*] Unnecessary open mode parameters - | -38 | pass -39 | -40 | open("foo", mode="U") - | ^^^^^^^^^^^^^^^^^^^^^ UP015 -41 | open(name="foo", mode="U") -42 | open(mode="U", name="foo") - | - = help: Remove open mode parameters - -ℹ Safe fix -37 37 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: -38 38 | pass -39 39 | -40 |-open("foo", mode="U") - 40 |+open("foo") -41 41 | open(name="foo", mode="U") -42 42 | open(mode="U", name="foo") -43 43 | +35 35 | +36 36 | with open("foo", "U") as fa, open("bar", "U") as fb: +37 37 | pass +38 |-with open("foo", "Ub") as fa, open("bar", "Ub") as fb: + 38 |+with open("foo", "Ub") as fa, open("bar", "rb") as fb: +39 39 | pass +40 40 | +41 41 | open("foo", mode="U") UP015.py:41:1: UP015 [*] Unnecessary open mode parameters | -40 | open("foo", mode="U") -41 | open(name="foo", mode="U") - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -42 | open(mode="U", name="foo") +39 | pass +40 | +41 | open("foo", mode="U") + | ^^^^^^^^^^^^^^^^^^^^^ UP015 +42 | open(name="foo", mode="U") +43 | open(mode="U", name="foo") | = help: Remove open mode parameters ℹ Safe fix -38 38 | pass -39 39 | -40 40 | open("foo", mode="U") -41 |-open(name="foo", mode="U") - 41 |+open(name="foo") -42 42 | open(mode="U", name="foo") -43 43 | -44 44 | with open("foo", mode="U") as f: +38 38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb: +39 39 | pass +40 40 | +41 |-open("foo", mode="U") + 41 |+open("foo") +42 42 | open(name="foo", mode="U") +43 43 | open(mode="U", name="foo") +44 44 | UP015.py:42:1: UP015 [*] Unnecessary open mode parameters | -40 | open("foo", mode="U") -41 | open(name="foo", mode="U") -42 | open(mode="U", name="foo") +41 | open("foo", mode="U") +42 | open(name="foo", mode="U") | ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -43 | -44 | with open("foo", mode="U") as f: +43 | open(mode="U", name="foo") | = help: Remove open mode parameters ℹ Safe fix -39 39 | -40 40 | open("foo", mode="U") -41 41 | open(name="foo", mode="U") -42 |-open(mode="U", name="foo") +39 39 | pass +40 40 | +41 41 | open("foo", mode="U") +42 |-open(name="foo", mode="U") 42 |+open(name="foo") -43 43 | -44 44 | with open("foo", mode="U") as f: -45 45 | pass +43 43 | open(mode="U", name="foo") +44 44 | +45 45 | with open("foo", mode="U") as f: -UP015.py:44:6: UP015 [*] Unnecessary open mode parameters +UP015.py:43:1: UP015 [*] Unnecessary open mode parameters | -42 | open(mode="U", name="foo") -43 | -44 | with open("foo", mode="U") as f: +41 | open("foo", mode="U") +42 | open(name="foo", mode="U") +43 | open(mode="U", name="foo") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +44 | +45 | with open("foo", mode="U") as f: + | + = help: Remove open mode parameters + +ℹ Safe fix +40 40 | +41 41 | open("foo", mode="U") +42 42 | open(name="foo", mode="U") +43 |-open(mode="U", name="foo") + 43 |+open(name="foo") +44 44 | +45 45 | with open("foo", mode="U") as f: +46 46 | pass + +UP015.py:45:6: UP015 [*] Unnecessary open mode parameters + | +43 | open(mode="U", name="foo") +44 | +45 | with open("foo", mode="U") as f: | ^^^^^^^^^^^^^^^^^^^^^ UP015 -45 | pass -46 | with open(name="foo", mode="U") as f: +46 | pass +47 | with open(name="foo", mode="U") as f: | = help: Remove open mode parameters ℹ Safe fix -41 41 | open(name="foo", mode="U") -42 42 | open(mode="U", name="foo") -43 43 | -44 |-with open("foo", mode="U") as f: - 44 |+with open("foo") as f: -45 45 | pass -46 46 | with open(name="foo", mode="U") as f: -47 47 | pass +42 42 | open(name="foo", mode="U") +43 43 | open(mode="U", name="foo") +44 44 | +45 |-with open("foo", mode="U") as f: + 45 |+with open("foo") as f: +46 46 | pass +47 47 | with open(name="foo", mode="U") as f: +48 48 | pass -UP015.py:46:6: UP015 [*] Unnecessary open mode parameters +UP015.py:47:6: UP015 [*] Unnecessary open mode parameters | -44 | with open("foo", mode="U") as f: -45 | pass -46 | with open(name="foo", mode="U") as f: +45 | with open("foo", mode="U") as f: +46 | pass +47 | with open(name="foo", mode="U") as f: | ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -47 | pass -48 | with open(mode="U", name="foo") as f: +48 | pass +49 | with open(mode="U", name="foo") as f: | = help: Remove open mode parameters ℹ Safe fix -43 43 | -44 44 | with open("foo", mode="U") as f: -45 45 | pass -46 |-with open(name="foo", mode="U") as f: - 46 |+with open(name="foo") as f: -47 47 | pass -48 48 | with open(mode="U", name="foo") as f: -49 49 | pass +44 44 | +45 45 | with open("foo", mode="U") as f: +46 46 | pass +47 |-with open(name="foo", mode="U") as f: + 47 |+with open(name="foo") as f: +48 48 | pass +49 49 | with open(mode="U", name="foo") as f: +50 50 | pass -UP015.py:48:6: UP015 [*] Unnecessary open mode parameters +UP015.py:49:6: UP015 [*] Unnecessary open mode parameters | -46 | with open(name="foo", mode="U") as f: -47 | pass -48 | with open(mode="U", name="foo") as f: +47 | with open(name="foo", mode="U") as f: +48 | pass +49 | with open(mode="U", name="foo") as f: | ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -49 | pass +50 | pass | = help: Remove open mode parameters ℹ Safe fix -45 45 | pass -46 46 | with open(name="foo", mode="U") as f: -47 47 | pass -48 |-with open(mode="U", name="foo") as f: - 48 |+with open(name="foo") as f: -49 49 | pass -50 50 | -51 51 | open("foo", mode="Ub") +46 46 | pass +47 47 | with open(name="foo", mode="U") as f: +48 48 | pass +49 |-with open(mode="U", name="foo") as f: + 49 |+with open(name="foo") as f: +50 50 | pass +51 51 | +52 52 | open("foo", mode="Ub") -UP015.py:51:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:52:1: UP015 [*] Unnecessary open mode parameters, use "rb" | -49 | pass -50 | -51 | open("foo", mode="Ub") +50 | pass +51 | +52 | open("foo", mode="Ub") | ^^^^^^^^^^^^^^^^^^^^^^ UP015 -52 | open(name="foo", mode="Ub") -53 | open(mode="Ub", name="foo") +53 | open(name="foo", mode="Ub") +54 | open(mode="Ub", name="foo") | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -48 48 | with open(mode="U", name="foo") as f: -49 49 | pass -50 50 | -51 |-open("foo", mode="Ub") - 51 |+open("foo", mode="rb") -52 52 | open(name="foo", mode="Ub") -53 53 | open(mode="Ub", name="foo") -54 54 | +49 49 | with open(mode="U", name="foo") as f: +50 50 | pass +51 51 | +52 |-open("foo", mode="Ub") + 52 |+open("foo", mode="rb") +53 53 | open(name="foo", mode="Ub") +54 54 | open(mode="Ub", name="foo") +55 55 | -UP015.py:52:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:53:1: UP015 [*] Unnecessary open mode parameters, use "rb" | -51 | open("foo", mode="Ub") -52 | open(name="foo", mode="Ub") +52 | open("foo", mode="Ub") +53 | open(name="foo", mode="Ub") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -53 | open(mode="Ub", name="foo") +54 | open(mode="Ub", name="foo") | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -49 49 | pass -50 50 | -51 51 | open("foo", mode="Ub") -52 |-open(name="foo", mode="Ub") - 52 |+open(name="foo", mode="rb") -53 53 | open(mode="Ub", name="foo") -54 54 | -55 55 | with open("foo", mode="Ub") as f: +50 50 | pass +51 51 | +52 52 | open("foo", mode="Ub") +53 |-open(name="foo", mode="Ub") + 53 |+open(name="foo", mode="rb") +54 54 | open(mode="Ub", name="foo") +55 55 | +56 56 | with open("foo", mode="Ub") as f: -UP015.py:53:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:54:1: UP015 [*] Unnecessary open mode parameters, use "rb" | -51 | open("foo", mode="Ub") -52 | open(name="foo", mode="Ub") -53 | open(mode="Ub", name="foo") +52 | open("foo", mode="Ub") +53 | open(name="foo", mode="Ub") +54 | open(mode="Ub", name="foo") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -54 | -55 | with open("foo", mode="Ub") as f: +55 | +56 | with open("foo", mode="Ub") as f: | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -50 50 | -51 51 | open("foo", mode="Ub") -52 52 | open(name="foo", mode="Ub") -53 |-open(mode="Ub", name="foo") - 53 |+open(mode="rb", name="foo") -54 54 | -55 55 | with open("foo", mode="Ub") as f: -56 56 | pass +51 51 | +52 52 | open("foo", mode="Ub") +53 53 | open(name="foo", mode="Ub") +54 |-open(mode="Ub", name="foo") + 54 |+open(mode="rb", name="foo") +55 55 | +56 56 | with open("foo", mode="Ub") as f: +57 57 | pass -UP015.py:55:6: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:56:6: UP015 [*] Unnecessary open mode parameters, use "rb" | -53 | open(mode="Ub", name="foo") -54 | -55 | with open("foo", mode="Ub") as f: +54 | open(mode="Ub", name="foo") +55 | +56 | with open("foo", mode="Ub") as f: | ^^^^^^^^^^^^^^^^^^^^^^ UP015 -56 | pass -57 | with open(name="foo", mode="Ub") as f: +57 | pass +58 | with open(name="foo", mode="Ub") as f: | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -52 52 | open(name="foo", mode="Ub") -53 53 | open(mode="Ub", name="foo") -54 54 | -55 |-with open("foo", mode="Ub") as f: - 55 |+with open("foo", mode="rb") as f: -56 56 | pass -57 57 | with open(name="foo", mode="Ub") as f: -58 58 | pass +53 53 | open(name="foo", mode="Ub") +54 54 | open(mode="Ub", name="foo") +55 55 | +56 |-with open("foo", mode="Ub") as f: + 56 |+with open("foo", mode="rb") as f: +57 57 | pass +58 58 | with open(name="foo", mode="Ub") as f: +59 59 | pass -UP015.py:57:6: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:58:6: UP015 [*] Unnecessary open mode parameters, use "rb" | -55 | with open("foo", mode="Ub") as f: -56 | pass -57 | with open(name="foo", mode="Ub") as f: +56 | with open("foo", mode="Ub") as f: +57 | pass +58 | with open(name="foo", mode="Ub") as f: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -58 | pass -59 | with open(mode="Ub", name="foo") as f: +59 | pass +60 | with open(mode="Ub", name="foo") as f: | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -54 54 | -55 55 | with open("foo", mode="Ub") as f: -56 56 | pass -57 |-with open(name="foo", mode="Ub") as f: - 57 |+with open(name="foo", mode="rb") as f: -58 58 | pass -59 59 | with open(mode="Ub", name="foo") as f: -60 60 | pass +55 55 | +56 56 | with open("foo", mode="Ub") as f: +57 57 | pass +58 |-with open(name="foo", mode="Ub") as f: + 58 |+with open(name="foo", mode="rb") as f: +59 59 | pass +60 60 | with open(mode="Ub", name="foo") as f: +61 61 | pass -UP015.py:59:6: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:60:6: UP015 [*] Unnecessary open mode parameters, use "rb" | -57 | with open(name="foo", mode="Ub") as f: -58 | pass -59 | with open(mode="Ub", name="foo") as f: +58 | with open(name="foo", mode="Ub") as f: +59 | pass +60 | with open(mode="Ub", name="foo") as f: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -60 | pass +61 | pass | - = help: Replace with ""rb"" + = help: Replace with "rb" ℹ Safe fix -56 56 | pass -57 57 | with open(name="foo", mode="Ub") as f: -58 58 | pass -59 |-with open(mode="Ub", name="foo") as f: - 59 |+with open(mode="rb", name="foo") as f: -60 60 | pass -61 61 | -62 62 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - -UP015.py:62:1: UP015 [*] Unnecessary open mode parameters - | -60 | pass -61 | -62 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -63 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') -64 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) - | - = help: Remove open mode parameters - -ℹ Safe fix -59 59 | with open(mode="Ub", name="foo") as f: -60 60 | pass -61 61 | -62 |-open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - 62 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -63 63 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') -64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) -65 65 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +57 57 | pass +58 58 | with open(name="foo", mode="Ub") as f: +59 59 | pass +60 |-with open(mode="Ub", name="foo") as f: + 60 |+with open(mode="rb", name="foo") as f: +61 61 | pass +62 62 | +63 63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) UP015.py:63:1: UP015 [*] Unnecessary open mode parameters | -62 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -63 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') +61 | pass +62 | +63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -64 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) -65 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') +65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) | = help: Remove open mode parameters ℹ Safe fix -60 60 | pass -61 61 | -62 62 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -63 |-open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') +60 60 | with open(mode="Ub", name="foo") as f: +61 61 | pass +62 62 | +63 |-open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) 63 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) -65 65 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -66 66 | +64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') +65 65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) +66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) UP015.py:64:1: UP015 [*] Unnecessary open mode parameters | -62 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -63 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') -64 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) +63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -65 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) +66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) | = help: Remove open mode parameters ℹ Safe fix -61 61 | -62 62 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -63 63 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') -64 |-open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) +61 61 | pass +62 62 | +63 63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +64 |-open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') 64 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -65 65 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -66 66 | -67 67 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +65 65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) +66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +67 67 | UP015.py:65:1: UP015 [*] Unnecessary open mode parameters | -63 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') -64 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) -65 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') +65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -66 | -67 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) | = help: Remove open mode parameters ℹ Safe fix -62 62 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -63 63 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') -64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) -65 |-open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +62 62 | +63 63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') +65 |-open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) 65 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -66 66 | -67 67 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -68 68 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') +66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +67 67 | +68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -UP015.py:67:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" +UP015.py:66:1: UP015 [*] Unnecessary open mode parameters | -65 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -66 | -67 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -68 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') -69 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) - | - = help: Replace with ""rb"" - -ℹ Safe fix -64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) -65 65 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -66 66 | -67 |-open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - 67 |+open(file="foo", mode="rb", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -68 68 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') -69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) -70 70 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - -UP015.py:68:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" - | -67 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -68 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -69 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) -70 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - | - = help: Replace with ""rb"" - -ℹ Safe fix -65 65 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -66 66 | -67 67 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -68 |-open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') - 68 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode="rb") -69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) -70 70 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -71 71 | - -UP015.py:69:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" - | -67 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -68 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') -69 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -70 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - | - = help: Replace with ""rb"" - -ℹ Safe fix -66 66 | -67 67 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -68 68 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') -69 |-open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) - 69 |+open(file="foo", buffering=-1, encoding=None, errors=None, mode="rb", newline=None, closefd=True, opener=None) -70 70 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -71 71 | -72 72 | open = 1 - -UP015.py:70:1: UP015 [*] Unnecessary open mode parameters, use ""rb"" - | -68 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') -69 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) -70 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -71 | -72 | open = 1 - | - = help: Replace with ""rb"" - -ℹ Safe fix -67 67 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -68 68 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') -69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) -70 |-open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - 70 |+open(mode="rb", file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) -71 71 | -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") +64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') +65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) +66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +67 | +68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) | = 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") +63 63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U') +65 65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) +66 |-open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) + 66 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +67 67 | +68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') -UP015.py:86:1: UP015 [*] Unnecessary open mode parameters +UP015.py:68:1: UP015 [*] Unnecessary open mode parameters, use "rb" | -85 | aiofiles.open("foo", "U") -86 | aiofiles.open("foo", "r") +66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +67 | +68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') +70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) + | + = help: Replace with "rb" + +ℹ Safe fix +65 65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None) +66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +67 67 | +68 |-open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) + 68 |+open(file="foo", mode="rb", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') +70 70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) +71 71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) + +UP015.py:69:1: UP015 [*] Unnecessary open mode parameters, use "rb" + | +68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) +71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) + | + = help: Replace with "rb" + +ℹ Safe fix +66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +67 67 | +68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +69 |-open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') + 69 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode="rb") +70 70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) +71 71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +72 72 | + +UP015.py:70:1: UP015 [*] Unnecessary open mode parameters, use "rb" + | +68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') +70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) + | + = help: Replace with "rb" + +ℹ Safe fix +67 67 | +68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') +70 |-open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) + 70 |+open(file="foo", buffering=-1, encoding=None, errors=None, mode="rb", newline=None, closefd=True, opener=None) +71 71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +72 72 | +73 73 | import aiofiles + +UP015.py:71:1: UP015 [*] Unnecessary open mode parameters, use "rb" + | +69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') +70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) +71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +72 | +73 | import aiofiles + | + = help: Replace with "rb" + +ℹ Safe fix +68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub') +70 70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None) +71 |-open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) + 71 |+open(mode="rb", file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) +72 72 | +73 73 | import aiofiles +74 74 | + +UP015.py:75:1: UP015 [*] Unnecessary open mode parameters + | +73 | import aiofiles +74 | +75 | aiofiles.open("foo", "U") | ^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 -87 | aiofiles.open("foo", mode="r") +76 | aiofiles.open("foo", "r") +77 | 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") +72 72 | +73 73 | import aiofiles +74 74 | +75 |-aiofiles.open("foo", "U") + 75 |+aiofiles.open("foo") +76 76 | aiofiles.open("foo", "r") +77 77 | aiofiles.open("foo", mode="r") +78 78 | -UP015.py:87:1: UP015 [*] Unnecessary open mode parameters +UP015.py:76:1: UP015 [*] Unnecessary open mode parameters | -85 | aiofiles.open("foo", "U") -86 | aiofiles.open("foo", "r") -87 | aiofiles.open("foo", mode="r") +75 | aiofiles.open("foo", "U") +76 | aiofiles.open("foo", "r") + | ^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +77 | aiofiles.open("foo", mode="r") + | + = help: Remove open mode parameters + +ℹ Safe fix +73 73 | import aiofiles +74 74 | +75 75 | aiofiles.open("foo", "U") +76 |-aiofiles.open("foo", "r") + 76 |+aiofiles.open("foo") +77 77 | aiofiles.open("foo", mode="r") +78 78 | +79 79 | open("foo", "r+") + +UP015.py:77:1: UP015 [*] Unnecessary open mode parameters + | +75 | aiofiles.open("foo", "U") +76 | aiofiles.open("foo", "r") +77 | aiofiles.open("foo", mode="r") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015 +78 | +79 | open("foo", "r+") | = 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") +74 74 | +75 75 | aiofiles.open("foo", "U") +76 76 | aiofiles.open("foo", "r") +77 |-aiofiles.open("foo", mode="r") + 77 |+aiofiles.open("foo") +78 78 | +79 79 | open("foo", "r+") +80 80 | open("foo", "rb") diff --git a/crates/ruff_python_stdlib/Cargo.toml b/crates/ruff_python_stdlib/Cargo.toml index 19d5df0328..43f08f874b 100644 --- a/crates/ruff_python_stdlib/Cargo.toml +++ b/crates/ruff_python_stdlib/Cargo.toml @@ -13,6 +13,7 @@ license = { workspace = true } [lib] [dependencies] +bitflags = { workspace = true } unicode-ident = { workspace = true } [lints] diff --git a/crates/ruff_python_stdlib/src/lib.rs b/crates/ruff_python_stdlib/src/lib.rs index 009aebe0d4..a57f4315d6 100644 --- a/crates/ruff_python_stdlib/src/lib.rs +++ b/crates/ruff_python_stdlib/src/lib.rs @@ -3,6 +3,7 @@ pub mod future; pub mod identifiers; pub mod keyword; pub mod logging; +pub mod open_mode; pub mod path; pub mod str; pub mod sys; diff --git a/crates/ruff_python_stdlib/src/open_mode.rs b/crates/ruff_python_stdlib/src/open_mode.rs new file mode 100644 index 0000000000..afd05b74ad --- /dev/null +++ b/crates/ruff_python_stdlib/src/open_mode.rs @@ -0,0 +1,146 @@ +bitflags::bitflags! { + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub struct OpenMode: u8 { + /// `r` + const READ = 0b0001; + /// `w` + const WRITE = 0b0010; + /// `a` + const APPEND = 0b0100; + /// `x` + const CREATE = 0b1000; + /// `b` + const BINARY = 0b10000; + /// `t` + const TEXT = 0b10_0000; + /// `+` + const PLUS = 0b100_0000; + /// `U` + const UNIVERSAL_NEWLINES = 0b1000_0000; + } +} + +impl OpenMode { + /// Parse an [`OpenMode`] from a sequence of characters. + pub fn from_chars(chars: impl Iterator) -> Result { + let mut open_mode = OpenMode::empty(); + for c in chars { + let flag = OpenMode::try_from(c)?; + if flag.intersects(open_mode) { + return Err(format!("Open mode contains duplicate flag: `{c}`")); + } + open_mode.insert(flag); + } + + // Both text and binary mode cannot be set at the same time. + if open_mode.contains(OpenMode::TEXT | OpenMode::BINARY) { + return Err( + "Open mode cannot contain both text (`t`) and binary (`b`) flags".to_string(), + ); + } + + // The `U` mode is only valid with `r`. + if open_mode.contains(OpenMode::UNIVERSAL_NEWLINES) + && open_mode.intersects(OpenMode::WRITE | OpenMode::APPEND | OpenMode::CREATE) + { + return Err("Open mode cannot contain the universal newlines (`U`) flag with write (`w`), append (`a`), or create (`x`) flags".to_string()); + } + + // Otherwise, reading, writing, creating, and appending are mutually exclusive. + if [ + OpenMode::READ | OpenMode::UNIVERSAL_NEWLINES, + OpenMode::WRITE, + OpenMode::CREATE, + OpenMode::APPEND, + ] + .into_iter() + .filter(|flag| open_mode.intersects(*flag)) + .count() + != 1 + { + return Err("Open mode must contain exactly one of the following flags: read (`r`), write (`w`), create (`x`), or append (`a`)".to_string()); + } + + Ok(open_mode) + } + + /// Remove any redundant flags from the open mode. + #[must_use] + pub fn reduce(self) -> Self { + let mut open_mode = self; + + // `t` is always redundant. + open_mode.remove(Self::TEXT); + + // `U` is always redundant. + open_mode.remove(Self::UNIVERSAL_NEWLINES); + + // `r` is redundant, unless `b` or `+` is also set, in which case, we need one of `w`, `a`, `r`, or `x`. + if open_mode.intersects(Self::BINARY | Self::PLUS) { + if !open_mode.intersects(Self::WRITE | Self::CREATE | Self::APPEND) { + open_mode.insert(Self::READ); + } + } else { + open_mode.remove(Self::READ); + } + + open_mode + } +} + +/// Write the [`OpenMode`] as a string. +impl std::fmt::Display for OpenMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.contains(OpenMode::READ) { + write!(f, "r")?; + } + if self.contains(OpenMode::WRITE) { + write!(f, "w")?; + } + if self.contains(OpenMode::APPEND) { + write!(f, "a")?; + } + if self.contains(OpenMode::CREATE) { + write!(f, "x")?; + } + if self.contains(OpenMode::UNIVERSAL_NEWLINES) { + write!(f, "U")?; + } + if self.contains(OpenMode::BINARY) { + write!(f, "b")?; + } + if self.contains(OpenMode::TEXT) { + write!(f, "t")?; + } + if self.contains(OpenMode::PLUS) { + write!(f, "+")?; + } + Ok(()) + } +} + +impl TryFrom for OpenMode { + type Error = String; + + fn try_from(value: char) -> Result { + match value { + 'r' => Ok(Self::READ), + 'w' => Ok(Self::WRITE), + 'a' => Ok(Self::APPEND), + 'x' => Ok(Self::CREATE), + 'b' => Ok(Self::BINARY), + 't' => Ok(Self::TEXT), + '+' => Ok(Self::PLUS), + 'U' => Ok(Self::UNIVERSAL_NEWLINES), + _ => Err(format!("Invalid open mode flag: `{value}`")), + } + } +} + +impl TryFrom<&str> for OpenMode { + type Error = String; + + fn try_from(value: &str) -> Result { + OpenMode::from_chars(value.chars()) + } +}