Skip to content

fix(text): command_body no longer crashes when bot_username is None - #25

Merged
HeiTang merged 1 commit into
devfrom
feature/command-body-none-fix
Jul 7, 2026
Merged

fix(text): command_body no longer crashes when bot_username is None#25
HeiTang merged 1 commit into
devfrom
feature/command-body-none-fix

Conversation

@HeiTang

@HeiTang HeiTang commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

Pre-existing bug 修正:src/remindly/reminders/text.py:48-57command_bodybot_username=None 時直接 crash。

Bug trace

def command_body(text: str, command: str, bot_username: str | None = None) -> str | None:
    command_pattern = rf"^/{re.escape(command)}(?:@{re.escape(bot_username)})?\b"  # ← re.escape(None) TypeError
    if bot_username is None:
        command_pattern = rf"^/{re.escape(command)}(?:@\w+)?\b"
    ...

Line 49 無條件呼叫 re.escape(bot_username)。若使用者部署未設 BOT_USERNAMEsettings.py 允許 None),任何 /start/help/remind/list/cancel/timezone/groupmode 都會拋 TypeError

影響鏈

  1. 使用者送 /help
  2. command_handlers.handle 迭代呼叫 command_body
  3. 第一次呼叫就 TypeError(handle 沒 try/except)
  4. 拋到 router.handle_update(也沒 try/except)
  5. app.py 主迴圈 try/except Exception 抓下並 log 一行
  6. 使用者看不到任何回覆 — bot 對 commands 完全 DOA

修法(reorder)

if bot_username is None:
    command_pattern = rf"^/{re.escape(command)}(?:@\w+)?\b"
else:
    command_pattern = rf"^/{re.escape(command)}(?:@{re.escape(bot_username)})?\b"

先分支再構造 pattern,re.escape 只看到真的字串。

Test plan

  • make test — 154 tests 全過(146 → 154,新增 8)
  • make lint — ruff 全綠
  • 新增 tests/test_text.py
    • test_matches_bare_command_when_bot_username_none(bare /remind
    • test_matches_at_suffix_command_when_bot_username_none/remind@AnyBot
    • test_does_not_match_wrong_command_when_bot_username_none
    • test_matches_at_suffix_command_when_bot_username_set/remind@ReminderBot
    • test_bare_command_still_matches_when_bot_username_set
    • strip_bot_mention 3 個 baseline case(原本沒 test)

相關

  • Pre-existing bug 記錄在 [[Spec_Recurring_Reminders]] 的 backlog 區
  • 跟 Phase 3 / Phase 4 完全獨立

Line 49 unconditionally called re.escape(bot_username) before the
None guard on line 50, so command_body raised TypeError whenever
BOT_USERNAME was unset. That propagated through command_handlers.
handle → router.handle_update → app.py's outer try/except, which
silently logged the error, and users saw no response to any slash
command. Bots deployed without BOT_USERNAME were effectively DOA
for /start, /help, /remind, /list, /cancel, /timezone, /groupmode.

Move the None check before pattern construction so re.escape only
sees a real string. Add a test module (tests/test_text.py) that
locks down both branches (bot_username=None accepts bare and
"@anybot" suffixes; bot_username set accepts bare and matching
suffix), plus baseline strip_bot_mention coverage that was
missing.

Generated with AI

Co-Authored-By: AI <ai@example.com>
@HeiTang
HeiTang merged commit fb4f93c into dev Jul 7, 2026
1 check passed
@HeiTang
HeiTang deleted the feature/command-body-none-fix branch July 7, 2026 03:14
@HeiTang HeiTang mentioned this pull request Jul 10, 2026
3 tasks
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