Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/specify_cli/workflows/steps/gate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,11 @@ def _prompt(message: str, options: list[str]) -> str:
except (EOFError, KeyboardInterrupt):
print()
return options[-1] # default to last (usually reject)
if raw.isdigit() and 1 <= int(raw) <= len(options):
# isdecimal() (not isdigit()): int() accepts exactly the decimal-digit
# set, whereas isdigit() also returns True for superscripts/subscripts
# (e.g. "²") that int() then rejects with ValueError — crashing
# this interactive loop.
if raw.isdecimal() and 1 <= int(raw) <= len(options):
return options[int(raw) - 1]
# Also accept the option name directly
if raw.lower() in [o.lower() for o in options]:
Expand Down
13 changes: 13 additions & 0 deletions tests/test_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -1985,6 +1985,19 @@ def test_interactive_prompt_renders_show_file(self, tmp_path, monkeypatch, capsy
assert result.status == StepStatus.COMPLETED
assert result.output["choice"] == "approve"

def test_interactive_prompt_rejects_non_decimal_digit(self, monkeypatch, capsys):
"""A Unicode digit int() can't parse — e.g. the superscript '²', which
str.isdigit() accepts but int() rejects — must be treated as an invalid
choice, not crash the prompt loop with an uncaught ValueError."""
from specify_cli.workflows.steps.gate import GateStep

_force_gate_stdin(monkeypatch, tty=True)
inputs = iter(["²", "1"]) # superscript-two, then a real "1"
monkeypatch.setattr("builtins.input", lambda _prompt="": next(inputs))

choice = GateStep._prompt("Review the spec.", ["approve", "reject"])
assert choice == "approve"

def test_interactive_prompt_missing_show_file_does_not_crash(
self, tmp_path, monkeypatch, capsys
):
Expand Down