Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,34 @@ use crate::Locator;
use crate::{checkers::ast::Checker, settings::types::PythonVersion};

/// ## What it does
/// Checks for the removal of a prefix or suffix from a string by assigning
/// the string to a slice after checking `.startswith()` or `.endswith()`, respectively.
/// Checks for code that could be written more idiomatically using
/// [`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?
/// 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),
/// introduced in Python 3.9, have the same behavior
/// and are more readable and efficient.
/// 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),
/// introduced in Python 3.9, have the same behavior while being more readable and efficient.
///
/// ## Example
/// ```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"):
/// text = text[3:]
/// if text.startswith("pre"):
/// text = text[3:]
/// ```
///
/// Use instead:
/// ```python
/// filename = filename.removesuffix(".txt")
/// ```
///
/// ```python
/// text = text.removeprefix("pre")
/// def example(filename: str, text: str):
/// filename = filename.removesuffix(".txt")
/// text = text.removeprefix("pre")
/// ```
#[derive(ViolationMetadata)]
pub(crate) struct SliceToRemovePrefixOrSuffix {
Expand All @@ -46,10 +48,10 @@ impl AlwaysFixableViolation for SliceToRemovePrefixOrSuffix {
fn message(&self) -> String {
match self.affix_kind {
AffixKind::StartsWith => {
"Prefer `removeprefix` over conditionally replacing with slice.".to_string()
"Prefer `str.removeprefix()` over conditionally replacing with slice.".to_string()
}
AffixKind::EndsWith => {
"Prefer `removesuffix` over conditionally replacing with slice.".to_string()
"Prefer `str.removesuffix()` over conditionally replacing with slice.".to_string()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
---
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:
7 | if filename.endswith(".txt"):
Expand All @@ -25,7 +24,7 @@ FURB188.py:7:5: FURB188 [*] Prefer `removesuffix` over conditionally replacing w
10 9 | return filename
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:
14 | if filename.endswith(extension):
Expand All @@ -48,7 +47,7 @@ FURB188.py:14:5: FURB188 [*] Prefer `removesuffix` over conditionally replacing
17 16 | return filename
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:
21 | return filename[:-4] if filename.endswith(".txt") else filename
Expand All @@ -66,7 +65,7 @@ FURB188.py:21:12: FURB188 [*] Prefer `removesuffix` over conditionally replacing
23 23 |
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:
25 | return filename[:-len(extension)] if filename.endswith(extension) else filename
Expand All @@ -84,7 +83,7 @@ FURB188.py:25:12: FURB188 [*] Prefer `removesuffix` over conditionally replacing
27 27 |
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:
29 | return filename[4:] if filename.startswith("abc-") else filename
Expand All @@ -102,7 +101,7 @@ FURB188.py:29:12: FURB188 [*] Prefer `removeprefix` over conditionally replacing
31 31 |
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:
33 | return filename[len(prefix):] if filename.startswith(prefix) else filename
Expand All @@ -120,7 +119,7 @@ FURB188.py:33:12: FURB188 [*] Prefer `removeprefix` over conditionally replacing
35 35 |
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"
145 |
Expand All @@ -141,7 +140,7 @@ FURB188.py:146:9: FURB188 [*] Prefer `removesuffix` over conditionally replacing
148 148 | def remove_prefix_comparable_literal_expr() -> None:
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:
149 | return ("abc" "def")[3:] if ("abc" "def").startswith("abc") else "abc" "def"
Expand All @@ -161,7 +160,7 @@ FURB188.py:149:12: FURB188 [*] Prefer `removeprefix` over conditionally replacin
151 151 | def shadow_builtins(filename: str, extension: str) -> None:
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
153 |
Expand All @@ -182,7 +181,7 @@ FURB188.py:154:12: FURB188 [*] Prefer `removesuffix` over conditionally replacin
156 156 | def okay_steps():
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():
157 | text = "!x!y!z"
Expand All @@ -206,7 +205,7 @@ FURB188.py:158:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
161 160 | text = text[1::True]
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("!"):
159 | text = text[1::1]
Expand All @@ -230,7 +229,7 @@ FURB188.py:160:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
163 162 | text = text[1::None]
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("!"):
161 | text = text[1::True]
Expand All @@ -253,7 +252,7 @@ FURB188.py:162:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
165 164 |
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("ř")`
182 | text = "řetězec"
Expand All @@ -275,7 +274,7 @@ FURB188.py:183:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
186 185 |
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
189 | text = "\ud800\udc00heythere"
Expand All @@ -299,7 +298,7 @@ FURB188.py:190:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing
193 192 | if text.startswith("\U00010000"):
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:]
192 | text = "\U00010000heythere"
Expand Down
Loading