Skip to content

Fix ends_with returning False for an empty suffix#119

Open
gaoflow wants to merge 1 commit into
zeroSteiner:masterfrom
gaoflow:fix-ends-with-empty-suffix
Open

Fix ends_with returning False for an empty suffix#119
gaoflow wants to merge 1 commit into
zeroSteiner:masterfrom
gaoflow:fix-ends-with-empty-suffix

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What

ends_with returns False for an empty suffix, contradicting Python's
str.endswith('') / bytes.endswith(b'') and its own starts_with sibling.

'Rule Engine'.ends_with('')     # False — should be True
'Rule Engine'.starts_with('')   # True  (sibling is correct)
[1, 2].ends_with([])            # False — should be True

Why

_value_ends_with slices from the back:

return value[-len(suffix):] == suffix

For an empty suffix, -len(suffix) is -0 == 0, so the slice is value[0:]
— the whole value — and whole == empty is False. The sibling
_value_starts_with slices from the front (value[:len(prefix)]), which for
an empty prefix is value[:0] = an empty slice, correctly yielding True.
The two handlers disagree on the empty case even though every non-empty case
matches.

Fix

Index from the front so an empty suffix yields an empty slice:

return value[len(value) - len(suffix):] == suffix

Equivalent to the old expression for every non-empty suffix; correct for the
empty one.

Tests

Added test_ast_expression_value_methods_empty_affix, exercising STRING,
BYTES and ARRAY through both ends_with and starts_with, asserting that an
empty affix and the whole value both match. It fails before the change
(ends_with('') should be True) and passes after. Full suite: Ran 455 tests ... OK (skipped=31); mypy clean on the changed file.


This pull request was prepared with the assistance of AI, under my direction and review.

_value_ends_with sliced value[-len(suffix):]. For an empty suffix,
-len(suffix) is -0 == 0, so the slice is value[0:] (the whole value)
and 'whole == empty' is False. Its sibling _value_starts_with uses
value[:len(prefix)], which for an empty prefix is value[:0] (an empty
slice) and correctly returns True. So starts_with('') was True while
ends_with('') was False, contradicting Python's str.endswith('')
semantics.

Index from the front (len(value) - len(suffix)) so an empty suffix
yields an empty slice. Equivalent to the old code for non-empty
suffixes.
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