failed WRONG_FIX wrong_fix · 17 tool calls · 197 s · Textualize/rich
Case insensitive prompt choices
## Type of changes
- [ ] Bug fix
- [x] 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.
- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.
- [x] I've added tests for new code.
- [x] I accept that @willmcgugan may be pedantic in the code review.
## Description
Optional flag for `Prompt.ask` allowing case-insensitive responses. Just add `case_sensitive=False` to the command options:
```python
from rich.prompt import Prompt
name = Prompt.ask("Enter your name", choices=["Paul", "Jessica", "Duncan"], default="Paul", case_sensitive=False)
```
Now, it would accept "paul" or "Paul" as valid responses. Defaults to True, which is the usual result.
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "grep -rn \"Prompt.ask\" rich/prompt.py"
} | {"status": "ok", "stdout": "rich/prompt.py:122: >>> filename = Prompt.ask(\"Enter a filename\")\nrich/prompt.py:290: >>> name = Prompt.ask(\"Enter your name\")\full{"status": "ok", "stdout": "rich/prompt.py:122: >>> filename = Prompt.ask(\"Enter a filename\")\nrich/prompt.py:290: >>> name = Prompt.ask(\"Enter your name\")\nrich/prompt.py:302: >>> burrito_count = IntPrompt.ask(\"How many burritos do you want to order\")\nrich/prompt.py:314: >>> temperature = FloatPrompt.ask(\"Enter desired temperature\")\nrich/prompt.py:354: result = IntPrompt.ask(\nrich/prompt.py:363: password = Prompt.ask(\nrich/prompt.py:372: fruit = Prompt.ask(\"Enter a fruit\", choices=[\"apple\", \"orange\", \"pear\"])\n", "stderr": "", "exit_code": 0} |
| 2 | read_file | {
"filepath": "rich/prompt.py"
} | {"status": "ok", "filepath": "rich/prompt.py", "content": "from typing import Any, Generic, List, Optional, TextIO, TypeVar, Union, overload\n\nfrom . import gefull{"status": "ok", "filepath": "rich/prompt.py", "content": "from typing import Any, Generic, List, Optional, TextIO, TypeVar, Union, overload\n\nfrom . import get_console\nfrom .console import Console\nfrom .text import Text, TextType\n\nPromptType = TypeVar(\"PromptType\")\nDefaultType = TypeVar(\"DefaultType\")\n\n\nclass PromptError(Exception):\n \"\"\"Exception base class for prompt related errors.\"\"\"\n\n\nclass InvalidResponse(PromptError):\n \"\"\"Exception to indicate a response was invalid. Raise this within process_response() to indicate an error\n and provide an error message.\n\n Args:\n message (Union[str, Text]): Error message.\n \"\"\"\n\n def __init__(self, message: TextType) -> None:\n self.message = message\n\n def __rich__(self) -> TextType:\n return self.message\n\n\nclass PromptBase(Generic[PromptType]):\n \"\"\"Ask the user for input until a valid response is received. This is the base class, see one of\n the concrete classes for examples.\n\n Args:\n prompt (TextType, optional): Prompt text. Defaults to \"\".\n console (Console, optional): A Console instance or None to use global console. Defaults to None.\n password (bool, optional): Enable password input. Defaults to False.\n choices (List[str], optional): A list of valid choices. Defaults to None.\n show_default (bool, optional): Show default in prompt. Defaults to True.\n show_choices (bool, optional): Show choices in prompt. Defaults to True.\n \"\"\"\n\n response_type: type = str\n\n validate_error_message = \"[prompt.invalid]Please enter a valid value\"\n illegal_choice_message = (\n \"[prompt.invalid.choice]Please select one of the available options\"\n )\n prompt_suffix = \": \"\n\n choices: Optional[List[str]] = None\n\n def __init__(\n self,\n prompt: TextType = \"\",\n *,\n console: Optional[Console] = None,\n password: bool |
| 3 | read_file | {
"filepath": "rich/prompt.py",
"start_line": 151
} | {"status": "ok", "filepath": "rich/prompt.py", "content": " \"\"\"\n return Text(f\"({default})\", \"prompt.default\")\n\n def make_prompt(self, default: Defaulfull{"status": "ok", "filepath": "rich/prompt.py", "content": " \"\"\"\n return Text(f\"({default})\", \"prompt.default\")\n\n def make_prompt(self, default: DefaultType) -> Text:\n \"\"\"Make prompt text.\n\n Args:\n default (DefaultType): Default value.\n\n Returns:\n Text: Text to display in prompt.\n \"\"\"\n prompt = self.prompt.copy()\n prompt.end = \"\"\n\n if self.show_choices and self.choices:\n _choices = \"/\".join(self.choices)\n choices = f\"[{_choices}]\"\n prompt.append(\" \")\n prompt.append(choices, \"prompt.choices\")\n\n if (\n default != ...\n and self.show_default\n and isinstance(default, (str, self.response_type))\n ):\n prompt.append(\" \")\n _default = self.render_default(default)\n prompt.append(_default)\n\n prompt.append(self.prompt_suffix)\n\n return prompt\n\n @classmethod\n def get_input(\n cls,\n console: Console,\n prompt: TextType,\n password: bool,\n stream: Optional[TextIO] = None,\n ) -> str:\n \"\"\"Get input from user.\n\n Args:\n console (Console): Console instance.\n prompt (TextType): Prompt text.\n password (bool): Enable password entry.\n\n Returns:\n str: String from user.\n \"\"\"\n return console.input(prompt, password=password, stream=stream)\n\n def check_choice(self, value: str) -> bool:\n \"\"\"Check value is in the list of valid choices.\n\n Args:\n value (str): Value entered by user.\n\n Returns:\n bool: True if choice was valid, otherwise False.\n \"\"\"\n assert self.choices is not None\n return value.strip() in self.choices\n\n def process_response(self, value: str) -> PromptType:\n \"\"\"Process |
| 4 | read_file | {
"filepath": "rich/prompt.py",
"start_line": 301
} | {"status": "ok", "filepath": "rich/prompt.py", "content": " Example:\n >>> burrito_count = IntPrompt.ask(\"How many burritos do you want to order\")\n\n \"\"\"\full{"status": "ok", "filepath": "rich/prompt.py", "content": " Example:\n >>> burrito_count = IntPrompt.ask(\"How many burritos do you want to order\")\n\n \"\"\"\n\n response_type = int\n validate_error_message = \"[prompt.invalid]Please enter a valid integer number\"\n\n\nclass FloatPrompt(PromptBase[int]):\n \"\"\"A prompt that returns a float.\n\n Example:\n >>> temperature = FloatPrompt.ask(\"Enter desired temperature\")\n\n \"\"\"\n\n response_type = float\n validate_error_message = \"[prompt.invalid]Please enter a number\"\n\n\nclass Confirm(PromptBase[bool]):\n \"\"\"A yes / no confirmation prompt.\n\n Example:\n >>> if Confirm.ask(\"Continue\"):\n run_job()\n\n \"\"\"\n\n response_type = bool\n validate_error_message = \"[prompt.invalid]Please enter Y or N\"\n choices: List[str] = [\"y\", \"n\"]\n\n def render_default(self, default: DefaultType) -> Text:\n \"\"\"Render the default as (y) or (n) rather than True/False.\"\"\"\n yes, no = self.choices\n return Text(f\"({yes})\" if default else f\"({no})\", style=\"prompt.default\")\n\n def process_response(self, value: str) -> bool:\n \"\"\"Convert choices to a bool.\"\"\"\n value = value.strip().lower()\n if value not in self.choices:\n raise InvalidResponse(self.validate_error_message)\n return value == self.choices[0]\n\n\nif __name__ == \"__main__\": # pragma: no cover\n\n from rich import print\n\n if Confirm.ask(\"Run [i]prompt[/i] tests?\", default=True):\n while True:\n result = IntPrompt.ask(\n \":rocket: Enter a number between [b]1[/b] and [b]10[/b]\", default=5\n )\n if result >= 1 and result <= 10:\n break\n print(\":pile_of_poo: [prompt.invalid]Number must be between 1 and 10\")\n print(f\"number={result}\")\n\n while True:\n password = Prompt.a |
| 5 | write_file | {
"content": "from rich.prompt import Prompt\n\ndef test_prompt_case_sensitive():\n # This is a mock test, we can't easily run it because it requires user input.\n # But we can test the logic by subclassing or mocking.\n pass\n\ndef test_prompt_case_insensitive():\n pass\n",
"filepath": "/tmp/test_prompt_case.py"
} | {"status": "error", "error_type": "FileWriteError", "error_message": "Path traversal detected: '/tmp/test_prompt_case.py' escapes workspace root."}full{"status": "error", "error_type": "FileWriteError", "error_message": "Path traversal detected: '/tmp/test_prompt_case.py' escapes workspace root."} |
| 6 | run_command | {
"command": "grep -rn \"test_prompt\" tests/"
} | {"status": "ok", "stdout": "tests/test_prompt.py:7:def test_prompt_str():\ntests/test_prompt.py:24:def test_prompt_str_default():\ntests/test_prompt.py:40:def tfull{"status": "ok", "stdout": "tests/test_prompt.py:7:def test_prompt_str():\ntests/test_prompt.py:24:def test_prompt_str_default():\ntests/test_prompt.py:40:def test_prompt_int():\ntests/test_prompt.py:55:def test_prompt_confirm_no():\ntests/test_prompt.py:70:def test_prompt_confirm_yes():\ntests/test_prompt.py:85:def test_prompt_confirm_default():\n", "stderr": "", "exit_code": 0} |
| 7 | read_file | {
"filepath": "tests/test_prompt.py"
} | {"status": "ok", "filepath": "tests/test_prompt.py", "content": "import io\n\nfrom rich.console import Console\nfrom rich.prompt import Prompt, IntPrompt, Confifull{"status": "ok", "filepath": "tests/test_prompt.py", "content": "import io\n\nfrom rich.console import Console\nfrom rich.prompt import Prompt, IntPrompt, Confirm\n\n\ndef test_prompt_str():\n INPUT = \"egg\\nfoo\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n choices=[\"foo\", \"bar\"],\n default=\"baz\",\n stream=io.StringIO(INPUT),\n )\n assert name == \"foo\"\n expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n print(repr(output))\n assert output == expected\n\n\ndef test_prompt_str_default():\n INPUT = \"\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n default=\"Will\",\n stream=io.StringIO(INPUT),\n )\n assert name == \"Will\"\n expected = \"what is your name (Will): \"\n output = console.file.getvalue()\n print(repr(output))\n assert output == expected\n\n\ndef test_prompt_int():\n INPUT = \"foo\\n100\"\n console = Console(file=io.StringIO())\n number = IntPrompt.ask(\n \"Enter a number\",\n console=console,\n stream=io.StringIO(INPUT),\n )\n assert number == 100\n expected = \"Enter a number: Please enter a valid integer number\\nEnter a number: \"\n output = console.file.getvalue()\n print(repr(output))\n assert output == expected\n\n\ndef test_prompt_confirm_no():\n INPUT = \"foo\\nNO\\nn\"\n console = Console(file=io.StringIO())\n answer = Confirm.ask(\n \"continue\",\n console=console,\n stream=io.StringIO(INPUT),\n )\n assert answer is False\n expected = \"continue [y/n]: Please enter Y or N\\ncontinue [y/n]: Please enter Y or N\\ncontinue [y/n]: \"\n output = console.file.getvalue()\n print(repr(output))\n as |
| 8 | edit_file | {
"filepath": "rich/prompt.py",
"new_string": " Args:\n prompt (TextType, optional): Prompt text. Defaults to \"\".\n console (Console, optional): A Console instance or None to use global console. Defaults to None.\n password (bool, optional): Enable password input. Defaults to False.\n choices (List[str], optional): A list of valid choices. Defaults to None.\n show_default (bool, optional): Show default in prompt. Defaults to True.\n show_choices (bool, optional): Show choices in prompt. Defaults to True.\n case_sensitive (bool, optional): Whether choices are case-sensitive. Defaults to True.\n \"\"\",old_string:",
"Args": "prompt (TextType",
"optional)": "Show choices in prompt. Defaults to True.\n \"\"\"",
"], optional)": "A list of valid choices. Defaults to None.\n show_default (bool"
} | {'error': 'Invoking `edit_file()` failed as the following mandatory input parameters are not present:\nold_string\nYou could retry calling this tool, but it is full{'error': 'Invoking `edit_file()` failed as the following mandatory input parameters are not present:\nold_string\nYou could retry calling this tool, but it is IMPORTANT for you to provide all the mandatory parameters.'} |
| 9-10 ×2 | edit_file | {
"filepath": "rich/prompt.py",
"new_string": " Args:\n prompt (TextType, optional): Prompt text. Defaults to \"\".\n console (Console, optional): A Console instance or None to use global console. Defaults to None.\n password (bool, optional): Enable password input. Defaults to False.\n choices (List[str], optional): A list of valid choices. Defaults to None.\n show_default (bool, optional): Show default in prompt. Defaults to True.\n show_choices (bool, optional): Show choices in prompt. Defaults to True.\n case_sensitive (bool, optional): Whether choices are case-sensitive. Defaults to True.\n \"\"\",old_string:",
"Args": "prompt (TextType",
"optional)": "Show choices in prompt. Defaults to True.\n \"\"\"<|\"|>",
"], optional)": "A list of valid choices. Defaults to None.\n show_default (bool"
} | {'error': 'Invoking `edit_file()` failed as the following mandatory input parameters are not present:\nold_string\nYou could retry calling this tool, but it is full{'error': 'Invoking `edit_file()` failed as the following mandatory input parameters are not present:\nold_string\nYou could retry calling this tool, but it is IMPORTANT for you to provide all the mandatory parameters.'} |
| 11 | edit_file | {
"filepath": "rich/prompt.py",
"new_string": " show_choices (bool, optional): Show choices in prompt. Defaults to True.\n case_sensitive (bool, optional): Whether choices are case-sensitive. Defaults to True.\n \"\"\"",
"old_string": " show_choices (bool, optional): Show choices in prompt. Defaults to True.\n \"\"\""
} | {"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -38,6 +38,7 @@\n cfull{"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -38,6 +38,7 @@\n choices (List[str], optional): A list of valid choices. Defaults to None.\n show_default (bool, optional): Show default in prompt. Defaults to True.\n show_choices (bool, optional): Show choices in prompt. Defaults to True.\n+ case_sensitive (bool, optional): Whether choices are case-sensitive. Defaults to True.\n \"\"\"\n \n response_type: type = str\n", "is_truncated": false} |
| 12 | edit_file | {
"filepath": "rich/prompt.py",
"new_string": " def __init__(\n self,\n prompt: TextType = \"\",\n *,\n console: Optional[Console] = None,\n password: bool = False,\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n case_sensitive: bool = True,\n ) -> None:\n self.console = console or get_console()\n self.prompt = (\n Text.from_markup(prompt, style=\"prompt\")\n if isinstance(prompt, str)\n else prompt\n )\n self.password = password\n if choices is not None:\n self.choices = choices\n self.show_default = show_default\n self.show_choices = show_choices\n self.case_sensitive = case_sensitive",
"old_string": " def __init__(\n self,\n prompt: TextType = \"\",\n *,\n console: Optional[Console] = None,\n password: bool = False,\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n ) -> None:\n self.console = console or get_console()\n self.prompt = (\n Text.from_markup(prompt, style=\"prompt\")\n if isinstance(prompt, str)\n else prompt\n )\n self.password = password\n if choices is not None:\n self.choices = choices\n self.show_default = show_default\n self.show_choices = show_choices"
} | {"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -60,6 +60,7 @@\n cfull{"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -60,6 +60,7 @@\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n+ case_sensitive: bool = True,\n ) -> None:\n self.console = console or get_console()\n self.prompt = (\n@@ -72,6 +73,7 @@\n self.choices = choices\n self.show_default = show_default\n self.show_choices = show_choices\n+ self.case_sensitive = case_sensitive\n \n @classmethod\n @overload\n", "is_truncated": false} |
| 13 | edit_file | {
"filepath": "rich/prompt.py",
"new_string": " @classmethod\n @overload\n def ask(\n cls,\n prompt: TextType = \"\",\n *,\n console: Optional[Console] = None,\n password: bool = False,\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n case_sensitive: bool = True,\n default: DefaultType,\n stream: Optional[TextIO] = None,\n ) -> Union[DefaultType, PromptType]:\n ...",
"old_string": " @classmethod\n @overload\n def ask(\n cls,\n prompt: TextType = \"\",\n *,\n console: Optional[Console] = None,\n password: bool = False,\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n default: DefaultType,\n stream: Optional[TextIO] = None,\n ) -> Union[DefaultType, PromptType]:\n ..."
} | {"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -86,6 +86,7 @@\n cfull{"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -86,6 +86,7 @@\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n+ case_sensitive: bool = True,\n default: DefaultType,\n stream: Optional[TextIO] = None,\n ) -> Union[DefaultType, PromptType]:\n", "is_truncated": false} |
| 14 | edit_file | {
"filepath": "rich/prompt.py",
"new_string": " @classmethod\n @overload\n def ask(\n cls,\n prompt: TextType = \"\",\n *,\n console: Optional[Console] = None,\n password: bool = False,\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n case_sensitive: bool = True,\n stream: Optional[TextIO] = None,\n ) -> PromptType:\n ...",
"old_string": " @classmethod\n @overload\n def ask(\n cls,\n prompt: TextType = \"\",\n *,\n console: Optional[Console] = None,\n password: bool = False,\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n stream: Optional[TextIO] = None,\n ) -> PromptType:\n ..."
} | {"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -103,6 +103,7 @@\nfull{"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -103,6 +103,7 @@\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n+ case_sensitive: bool = True,\n stream: Optional[TextIO] = None,\n ) -> PromptType:\n ...\n", "is_truncated": false} |
| 15 | edit_file | {
"filepath": "rich/prompt.py",
"new_string": " @classmethod\n def ask(\n cls,\n prompt: TextType = \"\",\n *,\n console: Optional[Console] = None,\n password: bool = False,\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n case_sensitive: bool = True,\n default: Any = ...,\n stream: Optional[TextIO] = None,\n ) -> Any:\n \"\"\"Shortcut to construct and run a prompt loop and return the result.\n\n Example:\n >>> filename = Prompt.ask(\"Enter a filename\")\n\n Args:\n prompt (TextType, optional): Prompt text. Defaults to \"\".\n console (Console, optional): A Console instance or None to use global console. Defaults to None.\n password (bool, optional): Enable password input. Defaults to False.\n choices (List[str], optional): A list of valid choices. Defaults to None.\n show_default (bool, optional): Show default in prompt. Defaults to True.\n show_choices (bool, optional): Show choices in prompt. Defaults to True.\n case_sensitive (bool, optional): Whether choices are case-sensitive. Defaults to True.\n stream (TextIO, optional): Optional text file open for reading to get input. Defaults to None.\n \"\"\"\n _prompt = cls(\n prompt,\n console=console,\n password=password,\n choices=choices,\n show_default=show_default,\n show_choices=show_choices,\n case_sensitive=case_sensitive,\n )\n return _prompt(default=default, stream=stream)",
"old_string": " @classmethod\n def ask(\n cls,\n prompt: TextType = \"\",\n *,\n console: Optional[Console] = None,\n password: bool = False,\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n default: Any = ...,\n stream: Optional[TextIO] = None,\n ) -> Any:\n \"\"\"Shortcut to construct and run a prompt loop and return the result.\n\n Example:\n >>> filename = Prompt.ask(\"Enter a filename\")\n\n Args:\n prompt (TextType, optional): Prompt text. Defaults to \"\".\n console (Console, optional): A Console instance or None to use global console. Defaults to None.\n password (bool, optional): Enable password input. Defaults to False.\n choices (List[str], optional): A list of valid choices. Defaults to None.\n show_default (bool, optional): Show default in prompt. Defaults to True.\n show_choices (bool, optional): Show choices in prompt. Defaults to True.\n stream (TextIO, optional): Optional text file open for reading to get input. Defaults to None.\n \"\"\"\n _prompt = cls(\n prompt,\n console=console,\n password=password,\n choices=choices,\n show_default=show_default,\n show_choices=show_choices,\n )\n return _prompt(default=default, stream=stream)"
} | {"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -118,6 +118,7 @@\nfull{"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -118,6 +118,7 @@\n choices: Optional[List[str]] = None,\n show_default: bool = True,\n show_choices: bool = True,\n+ case_sensitive: bool = True,\n default: Any = ...,\n stream: Optional[TextIO] = None,\n ) -> Any:\n@@ -133,6 +134,7 @@\n choices (List[str], optional): A list of valid choices. Defaults to None.\n show_default (bool, optional): Show default in prompt. Defaults to True.\n show_choices (bool, optional): Show choices in prompt. Defaults to True.\n+ case_sensitive (bool, optional): Whether choices are case-sensitive. Defaults to True.\n stream (TextIO, optional): Optional text file open for reading to get input. Defaults to None.\n \"\"\"\n _prompt = cls(\n@@ -142,6 +144,7 @@\n choices=choices,\n show_default=show_default,\n show_choices=show_choices,\n+ case_sensitive=case_sensitive,\n )\n return _prompt(default=default, stream=stream)\n \n", "is_truncated": false} |
| 16 | edit_file | {
"filepath": "rich/prompt.py",
"new_string": " def check_choice(self, value: str) -> bool:\n \"\"\"Check value is in the list of valid choices.\n\n Args:\n value (str): Value entered by user.\n\n Returns:\n bool: True if choice was valid, otherwise False.\n \"\"\"\n assert self.choices is not None\n if self.case_sensitive:\n return value.strip() in self.choices\n return value.strip().lower() in [choice.lower() for choice in self.choices]",
"old_string": " def check_choice(self, value: str) -> bool:\n \"\"\"Check value is in the list of valid choices.\n\n Args:\n value (str): Value entered by user.\n\n Returns:\n bool: True if choice was valid, otherwise False.\n \"\"\"\n assert self.choices is not None\n return value.strip() in self.choices"
} | {"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -220,7 +220,9 @@\nfull{"status": "ok", "filepath": "rich/prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/prompt.py\n+++ b/rich/prompt.py\n@@ -220,7 +220,9 @@\n bool: True if choice was valid, otherwise False.\n \"\"\"\n assert self.choices is not None\n- return value.strip() in self.choices\n+ if self.case_sensitive:\n+ return value.strip() in self.choices\n+ return value.strip().lower() in [choice.lower() for choice in self.choices]\n \n def process_response(self, value: str) -> PromptType:\n \"\"\"Process response from user, convert to prompt type.\n", "is_truncated": false} |
| 17 | edit_file | {
"filepath": "tests/test_prompt.py",
"new_string": "def test_prompt_str_case_insensitive():\n INPUT = \"EGG\\nfoo\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n choices=[\"foo\", \"bar\"],\n default=\"baz\",\n case_sensitive=False,\n stream=io.StringIO(INPUT),\n )\n assert name == \"foo\"\n expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n assert output == expected\n\ndef test_prompt_str_case_sensitive():\n INPUT = \"EGG\\nfoo\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n choices=[\"foo\", \"bar\"],\n default=\"baz\",\n case_sensitive=True,\n stream=io.StringIO(INPUT),\n )\n # This should fail and ask again, then we provide 'foo'\n # Wait, the INPUT is \"EGG\\nfoo\". \n # If case_sensitive=True, \"EGG\" is invalid, \"foo\" is valid.\n assert name == \"foo\"\n expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n assert output == expected\n",
"old_string": "def test_prompt_str():\n INPUT = \"egg\\nfoo\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n choices=[\"foo\", \"bar\"],\n default=\"baz\",\n stream=io.StringIO(INPUT),\n )\n assert name == \"foo\"\n expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n print(repr(output))\n assert output == expected\n"
} | {"status": "ok", "filepath": "tests/test_prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/tests/test_prompt.py\n+++ b/tests/test_prompt.py\n@@ full{"status": "ok", "filepath": "tests/test_prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/tests/test_prompt.py\n+++ b/tests/test_prompt.py\n@@ -4,20 +4,39 @@\n from rich.prompt import Prompt, IntPrompt, Confirm\n \n \n-def test_prompt_str():\n- INPUT = \"egg\\nfoo\"\n+def test_prompt_str_case_insensitive():\n+ INPUT = \"EGG\\nfoo\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n choices=[\"foo\", \"bar\"],\n default=\"baz\",\n+ case_sensitive=False,\n stream=io.StringIO(INPUT),\n )\n assert name == \"foo\"\n expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n- print(repr(output))\n+ assert output == expected\n+\n+def test_prompt_str_case_sensitive():\n+ INPUT = \"EGG\\nfoo\"\n+ console = Console(file=io.StringIO())\n+ name = Prompt.ask(\n+ \"what is your name\",\n+ console=console,\n+ choices=[\"foo\", \"bar\"],\n+ default=\"baz\",\n+ case_sensitive=True,\n+ stream=io.StringIO(INPUT),\n+ )\n+ # This should fail and ask again, then we provide 'foo'\n+ # Wait, the INPUT is \"EGG\\nfoo\". \n+ # If case_sensitive=True, \"EGG\" is invalid, \"foo\" is valid.\n+ assert name == \"foo\"\n+ expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n+ output = console.file.getvalue()\n assert output == expected\n \n \n", "is_truncated": false} |
| 18 | run_command | {
"command": "python -m pytest tests/test_prompt.py"
} | {"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-8.3.4, pfull{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-8.3.4, pluggy-1.6.0\nrootdir: /private/workspace/tests\nconfigfile: pytest.ini\ncollected 7 items\n\ntests/test_prompt.py ....... [100%]\n\n============================== 7 passed in 0.11s ===============================\n", "stderr": "", "exit_code": 0} |
| 19 | edit_file | {
"filepath": "tests/test_prompt.py",
"new_string": "def test_prompt_str_case_insensitive():\n INPUT = \"FOO\\n\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n choices=[\"foo\", \"bar\"],\n default=\"baz\",\n case_sensitive=False,\n stream=io.StringIO(INPUT),\n )\n assert name == \"FOO\"\n expected = \"what is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n assert output == expected\n\ndef test_prompt_str_case_sensitive():\n INPUT = \"FOO\\nfoo\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n choices=[\"foo\", \"bar\"],\n default=\"baz\",\n case_sensitive=True,\n stream=io.StringIO(INPUT),\n )\n assert name == \"foo\"\n expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n assert output == expected\n",
"old_string": "def test_prompt_str_case_insensitive():\n INPUT = \"EGG\\nfoo\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n choices=[\"foo\", \"bar\"],\n default=\"baz\",\n case_sensitive=False,\n stream=io.StringIO(INPUT),\n )\n assert name == \"foo\"\n expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n assert output == expected\n\ndef test_prompt_str_case_sensitive():\n INPUT = \"EGG\\nfoo\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n console=console,\n choices=[\"foo\", \"bar\"],\n default=\"baz\",\n case_sensitive=True,\n stream=io.StringIO(INPUT),\n )\n # This should fail and ask again, then we provide 'foo'\n # Wait, the INPUT is \"EGG\\nfoo\". \n # If case_sensitive=True, \"EGG\" is invalid, \"foo\" is valid.\n assert name == \"foo\"\n expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n assert output == expected\n"
} | {"status": "ok", "filepath": "tests/test_prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/tests/test_prompt.py\n+++ b/tests/test_prompt.py\n@@ full{"status": "ok", "filepath": "tests/test_prompt.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/tests/test_prompt.py\n+++ b/tests/test_prompt.py\n@@ -5,7 +5,7 @@\n \n \n def test_prompt_str_case_insensitive():\n- INPUT = \"EGG\\nfoo\"\n+ INPUT = \"FOO\\n\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n@@ -15,13 +15,13 @@\n case_sensitive=False,\n stream=io.StringIO(INPUT),\n )\n- assert name == \"foo\"\n- expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n+ assert name == \"FOO\"\n+ expected = \"what is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n assert output == expected\n \n def test_prompt_str_case_sensitive():\n- INPUT = \"EGG\\nfoo\"\n+ INPUT = \"FOO\\nfoo\"\n console = Console(file=io.StringIO())\n name = Prompt.ask(\n \"what is your name\",\n@@ -31,9 +31,6 @@\n case_sensitive=True,\n stream=io.StringIO(INPUT),\n )\n- # This should fail and ask again, then we provide 'foo'\n- # Wait, the INPUT is \"EGG\\nfoo\". \n- # If case_sensitive=True, \"EGG\" is invalid, \"foo\" is valid.\n assert name == \"foo\"\n expected = \"what is your name [foo/bar] (baz): Please select one of the available options\\nwhat is your name [foo/bar] (baz): \"\n output = console.file.getvalue()\n", "is_truncated": false} |
| 20 | run_command | {
"command": "python -m pytest tests/test_prompt.py"
} | {"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-8.3.4, pfull{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-8.3.4, pluggy-1.6.0\nrootdir: /private/workspace/tests\nconfigfile: pytest.ini\ncollected 7 items\n\ntests/test_prompt.py ....... [100%]\n\n============================== 7 passed in 0.14s ===============================\n", "stderr": "", "exit_code": 0} |
| 21 | submit_patch | {} | {"status": "ok", "patch_size": 4739, "files_changed": 2}full{"status": "ok", "patch_size": 4739, "files_changed": 2} |
diff --git a/rich/prompt.py b/rich/prompt.py
index 064c959b..ef524e1b 100644
--- a/rich/prompt.py
+++ b/rich/prompt.py
@@ -38,6 +38,7 @@ class PromptBase(Generic[PromptType]):
choices (List[str], optional): A list of valid choices. Defaults to None.
show_default (bool, optional): Show default in prompt. Defaults to True.
show_choices (bool, optional): Show choices in prompt. Defaults to True.
+ case_sensitive (bool, optional): Whether choices are case-sensitive. Defaults to True.
"""
response_type: type = str
@@ -59,6 +60,7 @@ class PromptBase(Generic[PromptType]):
choices: Optional[List[str]] = None,
show_default: bool = True,
show_choices: bool = True,
+ case_sensitive: bool = True,
) -> None:
self.console = console or get_console()
self.prompt = (
@@ -71,6 +73,7 @@ class PromptBase(Generic[PromptType]):
self.choices = choices
self.show_default = show_default
self.show_choices = show_choices
+ self.case_sensitive = case_sensitive
@classmethod
@overload
@@ -83,6 +86,7 @@ class PromptBase(Generic[PromptType]):
choices: Optional[List[str]] = None,
show_default: bool = True,
show_choices: bool = True,
+ case_sensitive: bool = True,
default: DefaultType,
stream: Optional[TextIO] = None,
) -> Union[DefaultType, PromptType]:
@@ -99,6 +103,7 @@ class PromptBase(Generic[PromptType]):
choices: Optional[List[str]] = None,
show_default: bool = True,
show_choices: bool = True,
+ case_sensitive: bool = True,
stream: Optional[TextIO] = None,
) -> PromptType:
...
@@ -113,6 +118,7 @@ class PromptBase(Generic[PromptType]):
choices: Optional[List[str]] = None,
show_default: bool = True,
show_choices: bool = True,
+ case_sensitive: bool = True,
default: Any = ...,
stream: Optional[TextIO] = None,
) -> Any:
@@ -128,6 +134,7 @@ class PromptBase(Generic[PromptType]):
choices (List[str], optional): A list of valid choices. Defaults to None.
show_default (bool, optional): Show default in prompt. Defaults to True.
show_choices (bool, optional): Show choices in prompt. Defaults to True.
+ case_sensitive (bool, optional): Whether choices are case-sensitive. Defaults to True.
stream (TextIO, optional): Optional text file open for reading to get input. Defaults to None.
"""
_prompt = cls(
@@ -137,6 +144,7 @@ class PromptBase(Generic[PromptType]):
choices=choices,
show_default=show_default,
show_choices=show_choices,
+ case_sensitive=case_sensitive,
)
return _prompt(default=default, stream=stream)
@@ -212,7 +220,9 @@ class PromptBase(Generic[PromptType]):
bool: True if choice was valid, otherwise False.
"""
assert self.choices is not None
- return value.strip() in self.choices
+ if self.case_sensitive:
+ return value.strip() in self.choices
+ return value.strip().lower() in [choice.lower() for choice in self.choices]
def process_response(self, value: str) -> PromptType:
"""Process response from user, convert to prompt type.
diff --git a/tests/test_prompt.py b/tests/test_prompt.py
index 9a41cc39..076b7855 100644
--- a/tests/test_prompt.py
+++ b/tests/test_prompt.py
@@ -4,20 +4,36 @@ from rich.console import Console
from rich.prompt import Prompt, IntPrompt, Confirm
-def test_prompt_str():
- INPUT = "egg\nfoo"
+def test_prompt_str_case_insensitive():
+ INPUT = "FOO\n"
console = Console(file=io.StringIO())
name = Prompt.ask(
"what is your name",
console=console,
choices=["foo", "bar"],
default="baz",
+ case_sensitive=False,
+ stream=io.StringIO(INPUT),
+ )
+ assert name == "FOO"
+ expected = "what is your name [foo/bar] (baz): "
+ output = console.file.getvalue()
+ assert output == expected
+
+def test_prompt_str_case_sensitive():
+ INPUT = "FOO\nfoo"
+ console = Console(file=io.StringIO())
+ name = Prompt.ask(
+ "what is your name",
+ console=console,
+ choices=["foo", "bar"],
+ default="baz",
+ case_sensitive=True,
stream=io.StringIO(INPUT),
)
assert name == "foo"
expected = "what is your name [foo/bar] (baz): Please select one of the available options\nwhat is your name [foo/bar] (baz): "
output = console.file.getvalue()
- print(repr(output))
assert output == expected
.F
=================================== FAILURES ===================================
_______________________ test_prompt_str_case_insensitive _______________________
def test_prompt_str_case_insensitive():
INPUT = "egg\nFoO"
console = Console(file=io.StringIO())
name = Prompt.ask(
"what is your name",
console=console,
choices=["foo", "bar"],
default="baz",
case_sensitive=False,
stream=io.StringIO(INPUT),
)
> assert name == "foo"
E AssertionError: assert 'FoO' == 'foo'
E
E - foo
E + FoO
tests/test_prompt.py:35: AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 1 passed in 0.13s