Whole file

rhasspy/unicode-rbnf

The author described this change as Fix zero remainder rules. It counts as a record because the check below fails on the code as it stood at f0010272f and passes on 9b64edcff, with nothing else changed between the two runs.

Fix saved2024-07-10
Sharing licenceMIT · LICENSE.md
Change size+15 7

What the code was meant to do, written into the code itself as a save note

Fix zero remainder rules

The change

5050 class SubType(str, Enum):
5151 """Type of substitution."""
5252
53- REMAINER = "remainder"
53+ REMAINDER = "remainder"
5454 """Use remainder for rule value."""
5555
5656 QUOTIENT = "quotient"
9191 TEXT = "text"
9292 SUB_OPTIONAL_BEFORE = "optional_before"
9393 SUB_OPTIONAL_AFTER = "optional_after"
94- SUB_REMAINER = "remainder"
94+ SUB_REMAINDER = "remainder"
9595 SUB_QUOTIENT = "quotient"
9696 SUB_RULESET_NAME = "sub_ruleset_name"
9797 REPLACE_RULESET_NAME = "replace_ruleset_name"
164164 if c in (">", "→"):
165165 # Divide the number by the rule's divisor and format the remainder
166166 if state in {ParseState.TEXT, ParseState.SUB_OPTIONAL_BEFORE}:
167- state = ParseState.SUB_REMAINER
167+ state = ParseState.SUB_REMAINDER
168168 part = SubRulePart(
169- SubType.REMAINER,
169+ SubType.REMAINDER,
170170 is_optional=is_sub_optional,
171171 text_before=sub_text_before,
172172 )
173173 rule.parts.append(part)
174174 sub_text_before = ""
175- elif state in {ParseState.SUB_REMAINER, ParseState.SUB_RULESET_NAME}:
175+ elif state in {ParseState.SUB_REMAINDER, ParseState.SUB_RULESET_NAME}:
176176 if is_sub_optional:
177177 state = ParseState.SUB_OPTIONAL_AFTER
178178 else:
196196 raise ValueError(f"Got {c} in {state}")
197197 elif c == "%":
198198 # =%rule_name= replacement
199- if state in {ParseState.SUB_QUOTIENT, ParseState.SUB_REMAINER}:
199+ if state in {ParseState.SUB_QUOTIENT, ParseState.SUB_REMAINDER}:
200200 assert isinstance(part, SubRulePart)
201201 state = ParseState.SUB_RULESET_NAME
202202 part.ruleset_name = ""
493493 yield part.text
494494 elif isinstance(part, SubRulePart):
495495 if (part.type == SubType.QUOTIENT) and (q > 0):
496+ if (q == 0) and (part.ruleset_name is None):
497+ # Rulesets can use quotients of zero
498+ continue
499+
496500 if part.text_before:
497501 yield part.text_before
498502 yield from self.iter_format_number(
500504 )
501505 if part.text_after:
502506 yield part.text_after
503- elif (part.type == SubType.REMAINER) and (r > 0):
507+ elif part.type == SubType.REMAINDER:
508+ if (r == 0) and (part.ruleset_name is None):
509+ # Rulesets can use remainders of zero
510+ continue
511+
504512 if part.text_before:
505513 yield part.text_before
506514 yield from self.iter_format_number(

The check that tells the two apart

failpass·tests/test_en.py::test_english

Check file tests/test_en.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.

Origin and history

The code before itf0010272f1076cfc5abc179e21c418ed689857d5
Broken version dated2024-02-06
Moduleunicode_rbnf.engine
Units changedParseState, RbnfEngine, RbnfRule, SubType
Fingerprint0620089ccc4e8646
Checked2026-08-18 by goldset/0.1

Every field above is generated by our program. None of it is written by hand.