Skip to content

fix: present_participle('be') returns 'bing' instead of 'being' - #252

Open
gaoflow wants to merge 2 commits into
jaraco:mainfrom
gaoflow:fix-present-participle-be
Open

fix: present_participle('be') returns 'bing' instead of 'being'#252
gaoflow wants to merge 2 commits into
jaraco:mainfrom
gaoflow:fix-present-participle-be

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 24, 2026

Copy link
Copy Markdown

Summary

present_participle('be') produces 'bing' instead of 'being'.

The root cause is the catch-all rule ([^e])e$ in
PRESENT_PARTICIPLE_REPLACEMENTS, which drops the trailing e from
any word ending in e. For a two-letter word like
be that leaves only b, then + ing = bing.

The fix adds an explicit guard ^(be)$ immediately before that rule
(consistent with the existing guards for are, were, had, hoe)
so be passes through intact and produces being.

Test plan

  • assert p.present_participle("be") == "being" added to test_prespart
  • All 208 existing tests still pass

The PRESENT_PARTICIPLE_REPLACEMENTS rule `([^e])e$` drops the trailing
'e' from any word ending in a non-e consonant + e. This incorrectly
strips 'be' down to 'b', yielding 'bing'.

Add an explicit guard for '^be$' ahead of that rule so 'be' passes
through intact and produces 'being'.

@eeshsaxena eeshsaxena left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed the bug on main:

>>> p.present_participle("be")
'bing'

The reason is that "be" reaches (re.compile(r"([^e])e$"), r"\g<1>"), which strips the trailing e after a non-e consonant (the rule that correctly turns hate into hating), leaving b + ing. Inserting ^(be)$ as an identity replacement above it short-circuits the loop before that rule is reached, which is the same trick the existing ^(hoe)$ entry uses. Placement is right: it has to sit above ([^e])e$ to have any effect.

I applied the rule to a local copy and diffed the output over the existing test words plus a set of neighbours that could plausibly be caught by the new pattern:

word    before    after
be      bing      being   <-- changed
are     being     being
were    being     being
had     having    having
hoe     hoeing    hoeing
bee     beeing    beeing
see     seeing    seeing
hate    hating    hating
spies   spying    spying
skis    skiing    skiing
free    freeing   freeing
die     dying     dying
use     using     using
make    making    making

be is the only word whose output changes, so the fix is properly surgical - the anchored ^(be)$ cannot catch bee, been or anything else.

One thing worth being aware of (not a blocker): present_participle's docstring says "word is the 3rd person singular verb", and the documented input already works, because plural_verb("is", 2) returns "are" and the existing ^(are|were)$ rule maps that to be:

>>> p.present_participle("is")
'being'

So "be" is a bare infinitive rather than the documented 3rd-person-singular form. That said, the function is already tolerant of infinitives everywhere else (hoe, see, make all work), bing is not a correct participle for any input, and ^(hoe)$ exists precisely to patch one of these. So I think accepting be is consistent with how the table already behaves rather than a scope expansion.

Two small suggestions:

  1. Consider folding it into the neighbouring rule as ^(hoe|be)$ instead of a separate entry - same behaviour, one fewer regex to walk, and it groups the "identity, do not strip the e" cases together. Purely cosmetic.
  2. The added test could also pin the documented path, so a future reordering of the table cannot silently break it:
assert p.present_participle("be") == "being"
assert p.present_participle("is") == "being"   # documented 3rd-person-singular input

Nice, well-scoped fix otherwise. Deferring to @jaraco.

…nput

Fold ^(be)$ into the neighbouring ^(hoe)$ entry (same replacement, one
fewer regex to walk) and add a present_participle("is") assertion so the
documented 3rd-person-singular path is pinned against future reordering.
@gaoflow

gaoflow commented Jul 10, 2026

Copy link
Copy Markdown
Author

Thanks for the thorough check. Applied both in d6665df:

  • Folded into the neighbouring rule as ^(hoe|be)$ — identical \g<1> replacement, one fewer regex to walk.
  • Added assert p.present_participle("is") == "being" alongside the "be" case, so the documented 3rd-person-singular path is pinned too.

Confirmed no output changes across your neighbour list (bee/been/see/free/die/skis/spies/etc. all unchanged); full suite is 207 passed, 16 xfailed.

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.

2 participants