Skip to content

chore: use str.removeprefix/removesuffix instead of slice (ruff FURB188)#166

Open
alexzhu0 wants to merge 1 commit intoFlowElement-ai:mainfrom
alexzhu0:chore/ruff-furb188-removeprefix-removesuffix
Open

chore: use str.removeprefix/removesuffix instead of slice (ruff FURB188)#166
alexzhu0 wants to merge 1 commit intoFlowElement-ai:mainfrom
alexzhu0:chore/ruff-furb188-removeprefix-removesuffix

Conversation

@alexzhu0
Copy link
Copy Markdown
Contributor

@alexzhu0 alexzhu0 commented May 3, 2026

Summary

Ruff rule FURB188 flags hand-rolled if s.startswith(p): s = s[len(p):] patterns that are equivalent to s = s.removeprefix(p) (and the symmetric endswith / removesuffix pair). These methods landed in Python 3.9 (docs), and pyproject.toml pins requires-python = ">=3.10,<3.14", so they are always available. 3 occurrences in one file, all auto-fixable.

-            for p in ("the ",):
-                if low.startswith(p):
-                    low = low[len(p) :]
+            for p in ("the ",):
+                low = low.removeprefix(p)
             for suf in (" inc", " ltd", " corp", " corporation", " llc"):
-                if low.endswith(suf):
-                    low = low[: -len(suf)]
+                low = low.removesuffix(suf)

Semantic equivalence

The str.removeprefix(p) / str.removesuffix(s) methods return a copy with the specified prefix/suffix stripped, or the original string unchanged if the prefix/suffix is absent — exactly the same observable behavior as the guarded slice.

One pedantic edge case: when the prefix/suffix is "", the old form s[len(""):] == s[0:] returns s, but s[:-len("")] == s[:0] would return "". The new removeprefix("") / removesuffix("") both return the original string. In this PR, all three loops iterate over tuples of non-empty literal strings ("the ", " inc", " ltd", " corp", " corporation", " llc", "a ", "an "), so the boundary never fires and the replacement is strictly byte-identical.

Scope

1 file, 3 sites, +3 / −6 (guard-and-slice collapses into a single assignment).

File Sites
coreference/english_coreference/ner_adapter.py 3

Verification

$ uv run ruff check . --exclude 'm_flow/baml_client' --exclude 'm_flow-frontend' --select FURB188
All checks passed!

$ uv run python -c "import ast; ast.parse(open('coreference/english_coreference/ner_adapter.py').read())"
# ast OK

No behavior change. Generated code under m_flow/baml_client/ is untouched.

I affirm that all code in every commit of this pull request conforms to the terms of the M-flow Developer Certificate of Origin

Ruff rule FURB188 flags hand-rolled `if s.startswith(p): s = s[len(p):]`
patterns that are equivalent to `s = s.removeprefix(p)` (and the symmetric
`endswith`/`removesuffix` pair). These string methods landed in Python 3.9,
and this repo targets `>=3.10`, so they are always available.

Only three sites are flagged, all in one file, and each iterates over
tuples of *non-empty* literal prefixes/suffixes, so the cosmetic
difference at the empty-string boundary does not apply here.

Verification:
- `uv run ruff check ... --select FURB188` is now clean
- ast.parse on every touched file: clean

No behavior change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant