Skip to content

FIX Validate LeetspeakConverter custom_substitutions and match keys case-insensitively - #3295

Merged
Roman Lutz (romanlutz) merged 2 commits into
microsoft:mainfrom
ShivamSharma43:fix/leetspeak-custom-substitutions
Oct 18, 2026
Merged

Roman Lutz (romanlutz) merged 2 commits into
microsoft:mainfrom
ShivamSharma43:fix/leetspeak-custom-substitutions

Conversation

@ShivamSharma43

Copy link
Copy Markdown
Contributor

Description

Fixes #3293.

LeetspeakConverter.convert_word_async looks each character up as char.lower(), but custom_substitutions was used without validation. An uppercase key such as {"A": ["4"]} never matched, a multi-character key such as {"th": ["7"]} could never match, and an empty replacement list such as {"e": []} was accepted and then raised IndexError on the first matching character.

The converter now validates custom substitutions when it is created:

  • Keys are matched case-insensitively. They are stored by lowercase character, so {"A": ["4"]} replaces both A and a, the same way the default substitutions already apply to both cases.
  • A key that is not a single character, two keys that differ only in case (such as "a" and "A"), or a value that is not a non-empty list of strings raises ValueError.

Custom substitutions with lowercase single-character keys keep their output and their identifier: the custom_substitutions_hash is computed from the same mapping as before, so existing hashes do not change. {"A": ["4"]} now gets the same identifier as {"a": ["4"]}, because the two convert identically. An empty custom_substitutions dict still falls back to the defaults.

Tests and Documentation

  • New tests in test_leetspeak_converter.py:
    • Uppercase keys apply in deterministic and random modes.
    • {"A": ["4"]} and {"a": ["4"]} share an identifier.
    • Invalid mappings raise ValueError at construction, in both modes: an empty list, a string value, a non-string replacement, a multi-character key, an empty key, and keys differing only in case.
    • On main, all 15 new tests fail. With this change, all of them pass.
  • pytest tests/unit/converter/test_leetspeak_converter.py: 24 passed. pytest tests/unit/converter tests/unit/registry tests/unit/backend/test_converter_service.py: 3735 passed, 38 skipped.
  • ruff check, ruff format and ty check pass on the changed files. git diff --check is clean.
  • No documentation changes. JupyText not run, since the converter docs only use the default substitutions.

🤖 Generated with Claude Code

…ase-insensitively

Characters are looked up in lowercase, so uppercase keys never matched,
multi-character keys could never match, and an empty replacement list
raised IndexError on the first matching character. Key custom
substitutions by lowercase character and reject keys and values that
cannot be applied.

Fixes microsoft#3293

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 17, 2026 18:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@romanlutz
Roman Lutz (romanlutz) added this pull request to the merge queue Oct 18, 2026
Merged via the queue into microsoft:main with commit f277fed Oct 18, 2026
64 checks passed
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.

BUG: LeetspeakConverter ignores uppercase and multi-character custom_substitutions keys and fails on empty replacement lists

3 participants