resolved RESOLVED PASS · 14 tool calls · 141 s · Textualize/rich
Fix raw markup printed on prompt errors sometimes ## Type of changes - [x] Bug fix - [ ] New feature - [ ] Documentation / docstrings - [ ] Tests - [ ] Other ## Checklist - [x] I've run the latest [black](https://github.com/psf/black) with default args on new code. - [ ] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate (see note about typos above). - [x] I've added tests for new code. - [x] I accept that @willmcgugan may be pedantic in the code review. ## Description PromptBase.on_validate_error() should explicitly ask for markup in case the console passed to it has markup disabled globally. Fixes #3881.
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "grep -rn \"PromptBase.on_validate_error\" ."
} | {"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}full{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}} |
| 2 | run_command | {
"command": "grep -rn \"on_validate_error\" ."
} | {"status": "ok", "stdout": "./rich/prompt.py:258: def on_validate_error(self, value: str, error: InvalidResponse) -> None:\n./rich/prompt.py:298: self.on_validafull{"status": "ok", "stdout": "./rich/prompt.py:258: def on_validate_error(self, value: str, error: InvalidResponse) -> None:\n./rich/prompt.py:298: self.on_validate_error(value, error)\n", "stderr": "", "exit_code": 0} |
| 3 | run_command | {
"command": "sed -n '250,270p' rich/prompt.py"
} | {"status": "ok", "stdout": " # return the original choice, not the lower case version\n return_value = self.response_type(\n self.choices[\n [choice.lower() forfull{"status": "ok", "stdout": " # return the original choice, not the lower case version\n return_value = self.response_type(\n self.choices[\n [choice.lower() for choice in self.choices].index(value.lower())\n ]\n )\n return return_value\n\n def on_validate_error(self, value: str, error: InvalidResponse) -> None:\n \"\"\"Called to handle validation error.\n\n Args:\n value (str): String entered by user.\n error (InvalidResponse): Exception instance the initiated the error.\n \"\"\"\n self.console.print(error)\n\n def pre_prompt(self) -> None:\n \"\"\"Hook to display something before the prompt.\"\"\"\n\n @overload\n", "stderr": "", "exit_code": 0} |
| 4 | run_command | {
"command": "sed -n '258,265p' rich/prompt.py"
} | {"status": "ok", "stdout": " def on_validate_error(self, value: str, error: InvalidResponse) -> None:\n \"\"\"Called to handle validation error.\n\n Args:\n valfull{"status": "ok", "stdout": " def on_validate_error(self, value: str, error: InvalidResponse) -> None:\n \"\"\"Called to handle validation error.\n\n Args:\n value (str): String entered by user.\n error (InvalidResponse): Exception instance the initiated the error.\n \"\"\"\n self.console.print(error)\n", "stderr": "", "exit_code": 0} |
| 5 | run_command | {
"command": "grep -n \"class Prompt\" rich/prompt.py"
} | {"status": "ok", "stdout": "11:class PromptError(Exception):\n30:class PromptBase(Generic[PromptType]):\n304:class Prompt(PromptBase[str]):\n", "stderr": "", "efull{"status": "ok", "stdout": "11:class PromptError(Exception):\n30:class PromptBase(Generic[PromptType]):\n304:class Prompt(PromptBase[str]):\n", "stderr": "", "exit_code": 0} |
| 6 | run_command | {
"command": "sed -n '258,265p' rich/prompt.py"
} | {"status": "ok", "stdout": " def on_validate_error(self, value: str, error: InvalidResponse) -> None:\n \"\"\"Called to handle validation error.\n\n Args:\n valfull{"status": "ok", "stdout": " def on_validate_error(self, value: str, error: InvalidResponse) -> None:\n \"\"\"Called to handle validation error.\n\n Args:\n value (str): String entered by user.\n error (InvalidResponse): Exception instance the initiated the error.\n \"\"\"\n self.console.print(error)\n", "stderr": "", "exit_code": 0} |
| 7 | run_command | {
"command": "python3 -c \"from rich.console import Console; from rich.prompt import Prompt; import io; import sys; \n\nclass MockInput:\n def __init__(self, inputs):\n self.inputs = inputs\n def __next__(self):\n return next(self.inputs)\n def __iter__(self):\n return self\n\ndef test_markup_disabled():\n console = Console(markup=False, file=io.StringIO())\n prompt = Prompt('Enter something', console=console)\n \n # We need to trigger on_validate_error. \n # Prompt.ask calls validate() if provided.\n # Let's subclass Prompt to add a validator that always fails.\n class FailingPrompt(Prompt):\n def validate(self, value):\n from rich.prompt import InvalidResponse\n raise InvalidResponse('[red]Error![/red]')\n\n # Mocking input to provide a value that will fail validation\n # Since we can't easily mock input() in this environment without replacing sys.stdin,\n # we can call on_validate_error directly to see if it prints markup.\n \n output = io.StringIO()\n console.file = output\n \n # This is what we are testing:\n # PromptBase.on_validate_error(self, value, error)\n # where error is an InvalidResponse.\n # InvalidResponse is basically a string (or has a __str__ that returns the message).\n \n from rich.prompt import InvalidResponse\n error = InvalidResponse('[red]Error![/red]')\n \n # Manually trigger on_validate_error\n prompt.on_validate_error('some value', error)\n \n result = output.getvalue()\n print(f'Result: {repr(result)}')\n if '[red]Error![/red]' in result:\n print('FAILED: Markup was printed raw')\n else:\n print('PASSED: Markup was processed')\n\ntest_markup_disabled()\""
} | {"status": "ok", "stdout": "Result: '[red]Error![/red]\\n'\nFAILED: Markup was printed raw\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Result: '[red]Error![/red]\\n'\nFAILED: Markup was printed raw\n", "stderr": "", "exit_code": 0} |
| 8 | run_command | {
"command": "python3 -c \"from rich.console import Console; import io; \n\ndef test_markup_explicit():\n console = Console(markup=False, file=io.StringIO())\n output = console.file\n \n # Testing console.print(text, markup=True) when console.markup=False\n console.print('[red]Error![/red]', markup=True)\n \n result = output.getvalue()\n print(f'Result: {repr(result)}')\n if '[red]Error![/red]' in result:\n print('FAILED: Markup was still printed raw')\n else:\n print('PASSED: Markup was processed')\n\ntest_markup_explicit()\""
} | {"status": "ok", "stdout": "Result: 'Error!\\n'\nPASSED: Markup was processed\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Result: 'Error!\\n'\nPASSED: Markup was processed\n", "stderr": "", "exit_code": 0} |
| 9 | run_command | {
"command": "python3 -c \"from rich.console import Console; from rich.prompt import PromptBase, InvalidResponse; import io; \n\nclass MockPrompt(PromptBase):\n def __init__(self, console):\n self.console = console\n\ndef test_fix():\n console = Console(markup=False, file=io.StringIO())\n output = console.file\n prompt = MockPrompt(console)\n \n error = InvalidResponse('[red]Error![/red]')\n \n # The proposed fix: self.console.print(error, markup=True)\n prompt.console.print(error, markup=True)\n \n result = output.getvalue()\n print(f'Result: {repr(result)}')\n if '[red]Error![/red]' in result:\n print('FAILED: Markup was printed raw')\n else:\n print('PASSED: Markup was processed')\n\ntest_fix()\""
} | {"status": "ok", "stdout": "Result: 'Error!\\n'\nPASSED: Markup was processed\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Result: 'Error!\\n'\nPASSED: Markup was processed\n", "stderr": "", "exit_code": 0} |
| 10 | run_command | {
"command": "python3 -c \"from rich.console import Console; from rich.prompt import PromptBase, InvalidResponse; import io; \n\nclass MockPrompt(PromptBase):\n def __init__(self, console):\n self.console = console\n\ndef test_markup_enabled():\n console = Console(markup=True, file=io.StringIO())\n output = console.file\n prompt = MockPrompt(console)\n \n error = InvalidResponse('[red]Error![/red]')\n \n # The proposed fix: self.console.print(error, markup=True)\n prompt.console.print(error, markup=True)\n \n result = output.getvalue()\n # We can't easily check for ANSI codes in StringIO without a terminal, \n # but we can check that the raw markup is NOT there.\n print(f'Result: {repr(result)}')\n if '[red]Error![/red]' in result:\n print('FAILED: Markup was printed raw')\n else:\n print('PASSED: Markup was processed')\n\ntest_markup_enabled()\""
} | {"status": "ok", "stdout": "Result: 'Error!\\n'\nPASSED: Markup was processed\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Result: 'Error!\\n'\nPASSED: Markup was processed\n", "stderr": "", "exit_code": 0} |
| 11 | run_command | {
"command": "cd /workspace && python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"rich/prompt.py\")\ns = p.read_text()\nold = \" self.console.print(error)\"\nnew = \" self.console.print(error, markup=True)\"\nassert s.count(old) == 1, (\"old text found this many times:\", s.count(old))\nt = s.replace(old, new)\np.write_text(t)\nPY\n"
} | {"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0} |
| 12 | run_command | {
"command": "sed -n '258,265p' rich/prompt.py"
} | {"status": "ok", "stdout": " def on_validate_error(self, value: str, error: InvalidResponse) -> None:\n \"\"\"Called to handle validation error.\n\n Args:\n valfull{"status": "ok", "stdout": " def on_validate_error(self, value: str, error: InvalidResponse) -> None:\n \"\"\"Called to handle validation error.\n\n Args:\n value (str): String entered by user.\n error (InvalidResponse): Exception instance the initiated the error.\n \"\"\"\n self.console.print(error, markup=True)\n", "stderr": "", "exit_code": 0} |
| 13 | run_command | {
"command": "python3 -c \"from rich.console import Console; from rich.prompt import PromptBase, InvalidResponse; import io; \n\nclass MockPrompt(PromptBase):\n def __init__(self, console):\n self.console = console\n\ndef test_fix():\n console = Console(markup=False, file=io.StringIO())\n output = console.file\n prompt = MockPrompt(console)\n \n error = InvalidResponse('[red]Error![/red]')\n \n # This now calls the modified on_validate_error\n prompt.on_validate_error('some value', error)\n \n result = output.getvalue()\n print(f'Result: {repr(result)}')\n if '[red]Error![/red]' in result:\n print('FAILED: Markup was printed raw')\n else:\n print('PASSED: Markup was processed')\n\ntest_fix()\""
} | {"status": "ok", "stdout": "Result: 'Error!\\n'\nPASSED: Markup was processed\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Result: 'Error!\\n'\nPASSED: Markup was processed\n", "stderr": "", "exit_code": 0} |
| 14 | run_command | {
"command": "git diff"
} | {"status": "ok", "stdout": "diff --git a/rich/prompt.py b/rich/prompt.py\nindex c7cf25ba..ae94d9bb 100644\n--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -262,7full{"status": "ok", "stdout": "diff --git a/rich/prompt.py b/rich/prompt.py\nindex c7cf25ba..ae94d9bb 100644\n--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -262,7 +262,7 @@ class PromptBase(Generic[PromptType]):\n value (str): String entered by user.\n error (InvalidResponse): Exception instance the initiated the error.\n \"\"\"\n- self.console.print(error)\n+ self.console.print(error, markup=True)\n \n def pre_prompt(self) -> None:\n \"\"\"Hook to display something before the prompt.\"\"\"\n", "stderr": "", "exit_code": 0} |
| 15 | submit_patch | {} | {"status": "ok", "patch_size": 503, "files_changed": 1}full{"status": "ok", "patch_size": 503, "files_changed": 1} |
diff --git a/rich/prompt.py b/rich/prompt.py
index c7cf25ba..ae94d9bb 100644
--- a/rich/prompt.py
+++ b/rich/prompt.py
@@ -262,7 +262,7 @@ class PromptBase(Generic[PromptType]):
value (str): String entered by user.
error (InvalidResponse): Exception instance the initiated the error.
"""
- self.console.print(error)
+ self.console.print(error, markup=True)
def pre_prompt(self) -> None:
"""Hook to display something before the prompt."""
........ [100%] 8 passed in 0.16s