Spruce up docs for slice-to-remove-prefix-or-suffix (FURB188) (#15328)

This commit is contained in:
Alex Waygood 2025-01-07 19:58:35 +00:00 committed by GitHub
parent a876090715
commit ac72aca27c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 35 additions and 34 deletions

View file

@ -8,32 +8,34 @@ use crate::Locator;
use crate::{checkers::ast::Checker, settings::types::PythonVersion}; use crate::{checkers::ast::Checker, settings::types::PythonVersion};
/// ## What it does /// ## What it does
/// Checks for the removal of a prefix or suffix from a string by assigning /// Checks for code that could be written more idiomatically using
/// the string to a slice after checking `.startswith()` or `.endswith()`, respectively. /// [`str.removeprefix()`](https://docs.python.org/3/library/stdtypes.html#str.removeprefix)
/// or [`str.removesuffix()`](https://docs.python.org/3/library/stdtypes.html#str.removesuffix).
///
/// Specifically, the rule flags code that conditionally removes a prefix or suffix
/// using a slice operation following an `if` test that uses `str.startswith()` or `str.endswith()`.
///
/// The rule is only applied if your project targets Python 3.9 or later.
/// ///
/// ## Why is this bad? /// ## Why is this bad?
/// The methods [`str.removeprefix`](https://docs.python.org/3/library/stdtypes.html#str.removeprefix) /// The methods [`str.removeprefix()`](https://docs.python.org/3/library/stdtypes.html#str.removeprefix)
/// and [`str.removesuffix`](https://docs.python.org/3/library/stdtypes.html#str.removesuffix), /// and [`str.removesuffix()`](https://docs.python.org/3/library/stdtypes.html#str.removesuffix),
/// introduced in Python 3.9, have the same behavior /// introduced in Python 3.9, have the same behavior while being more readable and efficient.
/// and are more readable and efficient.
/// ///
/// ## Example /// ## Example
/// ```python /// ```python
/// filename[:-4] if filename.endswith(".txt") else filename /// def example(filename: str, text: str):
/// ``` /// filename = filename[:-4] if filename.endswith(".txt") else filename
/// ///
/// ```python /// if text.startswith("pre"):
/// if text.startswith("pre"): /// text = text[3:]
/// text = text[3:]
/// ``` /// ```
/// ///
/// Use instead: /// Use instead:
/// ```python /// ```python
/// filename = filename.removesuffix(".txt") /// def example(filename: str, text: str):
/// ``` /// filename = filename.removesuffix(".txt")
/// /// text = text.removeprefix("pre")
/// ```python
/// text = text.removeprefix("pre")
/// ``` /// ```
#[derive(ViolationMetadata)] #[derive(ViolationMetadata)]
pub(crate) struct SliceToRemovePrefixOrSuffix { pub(crate) struct SliceToRemovePrefixOrSuffix {
@ -46,10 +48,10 @@ impl AlwaysFixableViolation for SliceToRemovePrefixOrSuffix {
fn message(&self) -> String { fn message(&self) -> String {
match self.affix_kind { match self.affix_kind {
AffixKind::StartsWith => { AffixKind::StartsWith => {
"Prefer `removeprefix` over conditionally replacing with slice.".to_string() "Prefer `str.removeprefix()` over conditionally replacing with slice.".to_string()
} }
AffixKind::EndsWith => { AffixKind::EndsWith => {
"Prefer `removesuffix` over conditionally replacing with slice.".to_string() "Prefer `str.removesuffix()` over conditionally replacing with slice.".to_string()
} }
} }
} }

View file

@ -1,8 +1,7 @@
--- ---
source: crates/ruff_linter/src/rules/refurb/mod.rs source: crates/ruff_linter/src/rules/refurb/mod.rs
snapshot_kind: text
--- ---
FURB188.py:7:5: FURB188 [*] Prefer `removesuffix` over conditionally replacing with slice. FURB188.py:7:5: FURB188 [*] Prefer `str.removesuffix()` over conditionally replacing with slice.
| |
6 | def remove_extension_via_slice(filename: str) -> str: 6 | def remove_extension_via_slice(filename: str) -> str:
7 | if filename.endswith(".txt"): 7 | if filename.endswith(".txt"):
@ -25,7 +24,7 @@ FURB188.py:7:5: FURB188 [*] Prefer `removesuffix` over conditionally replacing w
10 9 | return filename 10 9 | return filename
11 10 | 11 10 |
FURB188.py:14:5: FURB188 [*] Prefer `removesuffix` over conditionally replacing with slice. FURB188.py:14:5: FURB188 [*] Prefer `str.removesuffix()` over conditionally replacing with slice.
| |
13 | def remove_extension_via_slice_len(filename: str, extension: str) -> str: 13 | def remove_extension_via_slice_len(filename: str, extension: str) -> str:
14 | if filename.endswith(extension): 14 | if filename.endswith(extension):
@ -48,7 +47,7 @@ FURB188.py:14:5: FURB188 [*] Prefer `removesuffix` over conditionally replacing
17 16 | return filename 17 16 | return filename
18 17 | 18 17 |
FURB188.py:21:12: FURB188 [*] Prefer `removesuffix` over conditionally replacing with slice. FURB188.py:21:12: FURB188 [*] Prefer `str.removesuffix()` over conditionally replacing with slice.
| |
20 | def remove_extension_via_ternary(filename: str) -> str: 20 | def remove_extension_via_ternary(filename: str) -> str:
21 | return filename[:-4] if filename.endswith(".txt") else filename 21 | return filename[:-4] if filename.endswith(".txt") else filename
@ -66,7 +65,7 @@ FURB188.py:21:12: FURB188 [*] Prefer `removesuffix` over conditionally replacing
23 23 | 23 23 |
24 24 | def remove_extension_via_ternary_with_len(filename: str, extension: str) -> str: 24 24 | def remove_extension_via_ternary_with_len(filename: str, extension: str) -> str:
FURB188.py:25:12: FURB188 [*] Prefer `removesuffix` over conditionally replacing with slice. FURB188.py:25:12: FURB188 [*] Prefer `str.removesuffix()` over conditionally replacing with slice.
| |
24 | def remove_extension_via_ternary_with_len(filename: str, extension: str) -> str: 24 | def remove_extension_via_ternary_with_len(filename: str, extension: str) -> str:
25 | return filename[:-len(extension)] if filename.endswith(extension) else filename 25 | return filename[:-len(extension)] if filename.endswith(extension) else filename
@ -84,7 +83,7 @@ FURB188.py:25:12: FURB188 [*] Prefer `removesuffix` over conditionally replacing
27 27 | 27 27 |
28 28 | def remove_prefix(filename: str) -> str: 28 28 | def remove_prefix(filename: str) -> str:
FURB188.py:29:12: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice. FURB188.py:29:12: FURB188 [*] Prefer `str.removeprefix()` over conditionally replacing with slice.
| |
28 | def remove_prefix(filename: str) -> str: 28 | def remove_prefix(filename: str) -> str:
29 | return filename[4:] if filename.startswith("abc-") else filename 29 | return filename[4:] if filename.startswith("abc-") else filename
@ -102,7 +101,7 @@ FURB188.py:29:12: FURB188 [*] Prefer `removeprefix` over conditionally replacing
31 31 | 31 31 |
32 32 | def remove_prefix_via_len(filename: str, prefix: str) -> str: 32 32 | def remove_prefix_via_len(filename: str, prefix: str) -> str:
FURB188.py:33:12: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice. FURB188.py:33:12: FURB188 [*] Prefer `str.removeprefix()` over conditionally replacing with slice.
| |
32 | def remove_prefix_via_len(filename: str, prefix: str) -> str: 32 | def remove_prefix_via_len(filename: str, prefix: str) -> str:
33 | return filename[len(prefix):] if filename.startswith(prefix) else filename 33 | return filename[len(prefix):] if filename.startswith(prefix) else filename
@ -120,7 +119,7 @@ FURB188.py:33:12: FURB188 [*] Prefer `removeprefix` over conditionally replacing
35 35 | 35 35 |
36 36 | # these should not 36 36 | # these should not
FURB188.py:146:9: FURB188 [*] Prefer `removesuffix` over conditionally replacing with slice. FURB188.py:146:9: FURB188 [*] Prefer `str.removesuffix()` over conditionally replacing with slice.
| |
144 | SUFFIX = "suffix" 144 | SUFFIX = "suffix"
145 | 145 |
@ -141,7 +140,7 @@ FURB188.py:146:9: FURB188 [*] Prefer `removesuffix` over conditionally replacing
148 148 | def remove_prefix_comparable_literal_expr() -> None: 148 148 | def remove_prefix_comparable_literal_expr() -> None:
149 149 | return ("abc" "def")[3:] if ("abc" "def").startswith("abc") else "abc" "def" 149 149 | return ("abc" "def")[3:] if ("abc" "def").startswith("abc") else "abc" "def"
FURB188.py:149:12: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice. FURB188.py:149:12: FURB188 [*] Prefer `str.removeprefix()` over conditionally replacing with slice.
| |
148 | def remove_prefix_comparable_literal_expr() -> None: 148 | def remove_prefix_comparable_literal_expr() -> None:
149 | return ("abc" "def")[3:] if ("abc" "def").startswith("abc") else "abc" "def" 149 | return ("abc" "def")[3:] if ("abc" "def").startswith("abc") else "abc" "def"
@ -161,7 +160,7 @@ FURB188.py:149:12: FURB188 [*] Prefer `removeprefix` over conditionally replacin
151 151 | def shadow_builtins(filename: str, extension: str) -> None: 151 151 | def shadow_builtins(filename: str, extension: str) -> None:
152 152 | from builtins import len as builtins_len 152 152 | from builtins import len as builtins_len
FURB188.py:154:12: FURB188 [*] Prefer `removesuffix` over conditionally replacing with slice. FURB188.py:154:12: FURB188 [*] Prefer `str.removesuffix()` over conditionally replacing with slice.
| |
152 | from builtins import len as builtins_len 152 | from builtins import len as builtins_len
153 | 153 |
@ -182,7 +181,7 @@ FURB188.py:154:12: FURB188 [*] Prefer `removesuffix` over conditionally replacin
156 156 | def okay_steps(): 156 156 | def okay_steps():
157 157 | text = "!x!y!z" 157 157 | text = "!x!y!z"
FURB188.py:158:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice. FURB188.py:158:5: FURB188 [*] Prefer `str.removeprefix()` over conditionally replacing with slice.
| |
156 | def okay_steps(): 156 | def okay_steps():
157 | text = "!x!y!z" 157 | text = "!x!y!z"
@ -206,7 +205,7 @@ FURB188.py:158:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
161 160 | text = text[1::True] 161 160 | text = text[1::True]
162 161 | if text.startswith("!"): 162 161 | if text.startswith("!"):
FURB188.py:160:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice. FURB188.py:160:5: FURB188 [*] Prefer `str.removeprefix()` over conditionally replacing with slice.
| |
158 | if text.startswith("!"): 158 | if text.startswith("!"):
159 | text = text[1::1] 159 | text = text[1::1]
@ -230,7 +229,7 @@ FURB188.py:160:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
163 162 | text = text[1::None] 163 162 | text = text[1::None]
164 163 | print(text) 164 163 | print(text)
FURB188.py:162:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice. FURB188.py:162:5: FURB188 [*] Prefer `str.removeprefix()` over conditionally replacing with slice.
| |
160 | if text.startswith("!"): 160 | if text.startswith("!"):
161 | text = text[1::True] 161 | text = text[1::True]
@ -253,7 +252,7 @@ FURB188.py:162:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
165 164 | 165 164 |
166 165 | 166 165 |
FURB188.py:183:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice. FURB188.py:183:5: FURB188 [*] Prefer `str.removeprefix()` over conditionally replacing with slice.
| |
181 | # with fix `text = text.removeprefix("ř")` 181 | # with fix `text = text.removeprefix("ř")`
182 | text = "řetězec" 182 | text = "řetězec"
@ -275,7 +274,7 @@ FURB188.py:183:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
186 185 | 186 185 |
187 186 | def handle_surrogates(): 187 186 | def handle_surrogates():
FURB188.py:190:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice. FURB188.py:190:5: FURB188 [*] Prefer `str.removeprefix()` over conditionally replacing with slice.
| |
188 | # should be linted 188 | # should be linted
189 | text = "\ud800\udc00heythere" 189 | text = "\ud800\udc00heythere"
@ -299,7 +298,7 @@ FURB188.py:190:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
193 192 | if text.startswith("\U00010000"): 193 192 | if text.startswith("\U00010000"):
194 193 | text = text[1:] 194 193 | text = text[1:]
FURB188.py:193:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice. FURB188.py:193:5: FURB188 [*] Prefer `str.removeprefix()` over conditionally replacing with slice.
| |
191 | text = text[2:] 191 | text = text[2:]
192 | text = "\U00010000heythere" 192 | text = "\U00010000heythere"