From 3c343c34427753c18e2ceb58c104862bdccb39b4 Mon Sep 17 00:00:00 2001 From: Sevrain Date: Thu, 29 Jan 2026 00:13:20 +0200 Subject: [PATCH 1/2] fix: rename prompt() to safe_prompt() to avoid module shadowing The `questionary.prompt.prompt` function has the same name as its parent module. This, together with the `from questionary.prompt import prompt` line in the package's `__init__.py` file, causes the `questionary.prompt` module to be shadowed by its `prompt()` function. This built-in "shadowing" prevents the `prompt` module from being properly imported, as any `from questionary import prompt` statement will incorrectly import the `prompt.prompt` function instead of the required module. This is especially an issue when patching `prompt` module functions in unit tests. This commit renames the `prompt()` function to `safe_prompt()`, to prevent name shadowing and to match the naming style on its `unsafe_prompt()` sister function. --- docs/pages/advanced.rst | 18 +++++++++--------- docs/pages/quickstart.rst | 4 ++-- examples/advanced_workflow.py | 4 ++-- examples/autocomplete_ants.py | 4 ++-- examples/checkbox_separators.py | 4 ++-- examples/confirm_continue.py | 4 ++-- examples/dependent_selects.py | 4 ++-- examples/password_git.py | 4 ++-- examples/rawselect_separator.py | 4 ++-- examples/select_restaurant.py | 4 ++-- examples/select_search.py | 4 ++-- examples/text_phone_number.py | 4 ++-- questionary/__init__.py | 4 ++-- questionary/prompt.py | 4 ++-- tests/test_prompt.py | 12 ++++++------ tests/utils.py | 4 ++-- 16 files changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/pages/advanced.rst b/docs/pages/advanced.rst index 2e96691a..8cdc5e2c 100644 --- a/docs/pages/advanced.rst +++ b/docs/pages/advanced.rst @@ -104,7 +104,7 @@ Safe The following are safe (capture keyboard interrupts): -* :meth:`~questionary.prompt`; +* :meth:`~questionary.safe_prompt`; * :attr:`~questionary.Form.ask` on :class:`~questionary.Form` (returned by :meth:`~questionary.form`); @@ -121,7 +121,7 @@ Here is an example: # Questionary handles keyboard interrupt and returns `None` if the # user hits e.g. `Ctrl+C` - prompt(...) + safe_prompt(...) Unsafe ****** @@ -136,7 +136,7 @@ The following are unsafe (do not catch keyboard interrupts): * :attr:`~questionary.Question.unsafe_ask` on :class:`~questionary.Question`, which is returned by the various prompt functions (e.g. :meth:`~questionary.text`, :meth:`~questionary.checkbox`). - + As a caller you must handle keyboard interrupts yourself when calling these methods. Here is an example: @@ -252,7 +252,7 @@ them using a configuration dictionary: .. code-block:: python3 - from questionary import prompt + from questionary import safe_prompt questions = [ { @@ -268,7 +268,7 @@ them using a configuration dictionary: } ] - answers = prompt(questions) + answers = safe_prompt(questions) The questions will be prompted one after another and ``prompt`` will return as soon as all of them are answered. The returned ``answers`` @@ -314,9 +314,9 @@ add the following optional parameters: ``filter`` (optional) Receive the user input and return the filtered value to be - used inside the program. + used inside the program. -Further information can be found at the :class:`questionary.prompt` +Further information can be found at the :class:`questionary.safe_prompt` documentation. .. _random_label: @@ -345,14 +345,14 @@ Depending on the route the user took, the result will look like the following: .. code-block:: python3 - { + { 'conditional_step': False, 'second_question': 'Test input' # Free form text } .. code-block:: python3 - { + { 'conditional_step': True, 'next_question': 'questionary', 'second_question': 'Test input' # Free form text diff --git a/docs/pages/quickstart.rst b/docs/pages/quickstart.rst index 19b954fb..a9d3e524 100644 --- a/docs/pages/quickstart.rst +++ b/docs/pages/quickstart.rst @@ -82,7 +82,7 @@ The printed output will have the following format: {'first': True, 'second': 'item2'} -The :meth:`~questionary.prompt` function also allows you to ask a +The :meth:`~questionary.safe_prompt` function also allows you to ask a collection of questions, however instead of taking :class:`~questionary.Question` instances, it takes a dictionary: @@ -105,7 +105,7 @@ instances, it takes a dictionary: }, ] - questionary.prompt(questions) + questionary.safe_prompt(questions) The format of the returned answers is the same as the one for :meth:`~questionary.form`. You can find more details on the configuration diff --git a/examples/advanced_workflow.py b/examples/advanced_workflow.py index 5b066339..acb1551c 100644 --- a/examples/advanced_workflow.py +++ b/examples/advanced_workflow.py @@ -1,7 +1,7 @@ from pprint import pprint from questionary import Separator -from questionary import prompt +from questionary import safe_prompt def ask_dictstyle(**kwargs): @@ -51,7 +51,7 @@ def ask_dictstyle(**kwargs): "when": lambda x: x["second_question"] == "other", }, ] - return prompt(questions, **kwargs) + return safe_prompt(questions, **kwargs) if __name__ == "__main__": diff --git a/examples/autocomplete_ants.py b/examples/autocomplete_ants.py index 7b743d60..940a4a34 100644 --- a/examples/autocomplete_ants.py +++ b/examples/autocomplete_ants.py @@ -8,7 +8,7 @@ from examples import custom_style_fancy from questionary import ValidationError from questionary import Validator -from questionary import prompt +from questionary import safe_prompt class PolyergusValidator(Validator): @@ -81,7 +81,7 @@ def ask_dictstyle(**kwargs): } ] - return prompt(questions, style=custom_style_fancy, **kwargs) + return safe_prompt(questions, style=custom_style_fancy, **kwargs) if __name__ == "__main__": diff --git a/examples/checkbox_separators.py b/examples/checkbox_separators.py index 8de2f4b2..0a6969a7 100644 --- a/examples/checkbox_separators.py +++ b/examples/checkbox_separators.py @@ -8,7 +8,7 @@ from examples import custom_style_dope from questionary import Choice from questionary import Separator -from questionary import prompt +from questionary import safe_prompt def ask_pystyle(**kwargs): @@ -48,7 +48,7 @@ def ask_dictstyle(**kwargs): } ] - return prompt(questions, style=custom_style_dope, **kwargs) + return safe_prompt(questions, style=custom_style_dope, **kwargs) if __name__ == "__main__": diff --git a/examples/confirm_continue.py b/examples/confirm_continue.py index 46064b75..df70fe69 100644 --- a/examples/confirm_continue.py +++ b/examples/confirm_continue.py @@ -6,7 +6,7 @@ import questionary from examples import custom_style_dope -from questionary import prompt +from questionary import safe_prompt def ask_pystyle(**kwargs): @@ -29,7 +29,7 @@ def ask_dictstyle(**kwargs): } ] - return prompt(questions, style=custom_style_dope, **kwargs) + return safe_prompt(questions, style=custom_style_dope, **kwargs) if __name__ == "__main__": diff --git a/examples/dependent_selects.py b/examples/dependent_selects.py index 28497f39..29a2c5f4 100644 --- a/examples/dependent_selects.py +++ b/examples/dependent_selects.py @@ -1,6 +1,6 @@ from pprint import pprint -from questionary import prompt +from questionary import safe_prompt OPTIONS = {"key1": ["k1v1", "k1v2"], "key2": ["k2v1", "k2v2"]} @@ -20,7 +20,7 @@ def ask_dictstyle(**kwargs): "choices": lambda x: OPTIONS[x["key"]], }, ] - return prompt(questions, **kwargs) + return safe_prompt(questions, **kwargs) if __name__ == "__main__": diff --git a/examples/password_git.py b/examples/password_git.py index a52e125d..93fbd1ee 100644 --- a/examples/password_git.py +++ b/examples/password_git.py @@ -6,7 +6,7 @@ import questionary from examples import custom_style_dope -from questionary import prompt +from questionary import safe_prompt def ask_pystyle(**kwargs): @@ -24,7 +24,7 @@ def ask_dictstyle(**kwargs): {"type": "password", "message": "Enter your git password", "name": "password"} ] - return prompt(questions, style=custom_style_dope, **kwargs) + return safe_prompt(questions, style=custom_style_dope, **kwargs) if __name__ == "__main__": diff --git a/examples/rawselect_separator.py b/examples/rawselect_separator.py index 663fd39a..cc8d419d 100644 --- a/examples/rawselect_separator.py +++ b/examples/rawselect_separator.py @@ -7,7 +7,7 @@ import questionary from examples import custom_style_dope from questionary import Separator -from questionary import prompt +from questionary import safe_prompt def ask_pystyle(**kwargs): @@ -45,7 +45,7 @@ def ask_dictstyle(**kwargs): }, ] - return prompt(questions, style=custom_style_dope, **kwargs) + return safe_prompt(questions, style=custom_style_dope, **kwargs) if __name__ == "__main__": diff --git a/examples/select_restaurant.py b/examples/select_restaurant.py index 47d4d4f3..2245b076 100644 --- a/examples/select_restaurant.py +++ b/examples/select_restaurant.py @@ -8,7 +8,7 @@ from examples import custom_style_dope from questionary import Choice from questionary import Separator -from questionary import prompt +from questionary import safe_prompt def ask_pystyle(**kwargs): @@ -49,7 +49,7 @@ def ask_dictstyle(**kwargs): } ] - return prompt(questions, style=custom_style_dope, **kwargs) + return safe_prompt(questions, style=custom_style_dope, **kwargs) if __name__ == "__main__": diff --git a/examples/select_search.py b/examples/select_search.py index ac453630..a51472ec 100644 --- a/examples/select_search.py +++ b/examples/select_search.py @@ -8,7 +8,7 @@ from examples import custom_style_dope from questionary import Choice from questionary import Separator -from questionary import prompt +from questionary import safe_prompt def ask_pystyle(**kwargs): @@ -55,7 +55,7 @@ def ask_dictstyle(**kwargs): } ] - return prompt(questions, style=custom_style_dope, **kwargs) + return safe_prompt(questions, style=custom_style_dope, **kwargs) if __name__ == "__main__": diff --git a/examples/text_phone_number.py b/examples/text_phone_number.py index 82fb169b..ff586057 100644 --- a/examples/text_phone_number.py +++ b/examples/text_phone_number.py @@ -9,7 +9,7 @@ from examples import custom_style_dope from questionary import ValidationError from questionary import Validator -from questionary import prompt +from questionary import safe_prompt class PhoneNumberValidator(Validator): @@ -50,7 +50,7 @@ def ask_dictstyle(**kwargs): } ] - return prompt(questions, style=custom_style_dope, **kwargs) + return safe_prompt(questions, style=custom_style_dope, **kwargs) if __name__ == "__main__": diff --git a/questionary/__init__.py b/questionary/__init__.py index a438e68a..0868934e 100644 --- a/questionary/__init__.py +++ b/questionary/__init__.py @@ -7,8 +7,8 @@ from questionary.form import Form from questionary.form import FormField from questionary.form import form -from questionary.prompt import prompt from questionary.prompt import prompt_async +from questionary.prompt import safe_prompt from questionary.prompt import unsafe_prompt from questionary.prompt import unsafe_prompt_async @@ -44,7 +44,7 @@ # utility methods "print", "form", - "prompt", + "safe_prompt", "prompt_async", "unsafe_prompt", "unsafe_prompt_async", diff --git a/questionary/prompt.py b/questionary/prompt.py index 561ce7f2..fa176d48 100644 --- a/questionary/prompt.py +++ b/questionary/prompt.py @@ -193,7 +193,7 @@ async def prompt_async( return {} -def prompt( +def safe_prompt( questions: Union[Dict[str, Any], Iterable[Mapping[str, Any]]], answers: Optional[Mapping[str, Any]] = None, patch_stdout: bool = False, @@ -229,6 +229,7 @@ def prompt( are printing to stdout. kbi_msg: The message to be printed on a keyboard interrupt. + true_color: Use true color output. color_depth: Color depth to use. If ``true_color`` is set to true then this @@ -244,7 +245,6 @@ def prompt( Returns: Dictionary of question answers. """ - try: return unsafe_prompt(questions, answers, patch_stdout, true_color, **kwargs) except KeyboardInterrupt: diff --git a/tests/test_prompt.py b/tests/test_prompt.py index 9a9a84be..7d9733a0 100644 --- a/tests/test_prompt.py +++ b/tests/test_prompt.py @@ -1,18 +1,18 @@ import pytest from questionary.prompt import PromptParameterException -from questionary.prompt import prompt +from questionary.prompt import safe_prompt from tests.utils import patched_prompt def test_missing_message(): with pytest.raises(PromptParameterException): - prompt([{"type": "confirm", "name": "continue", "default": True}]) + safe_prompt([{"type": "confirm", "name": "continue", "default": True}]) def test_missing_type(): with pytest.raises(PromptParameterException): - prompt( + safe_prompt( [ { "message": "Do you want to continue?", @@ -25,7 +25,7 @@ def test_missing_type(): def test_missing_name(): with pytest.raises(PromptParameterException): - prompt( + safe_prompt( [ { "type": "confirm", @@ -38,7 +38,7 @@ def test_missing_name(): def test_invalid_question_type(): with pytest.raises(ValueError): - prompt( + safe_prompt( [ { "type": "mytype", @@ -53,7 +53,7 @@ def test_invalid_question_type(): def test_missing_print_message(): """Test 'print' raises exception if missing 'message'""" with pytest.raises(PromptParameterException): - prompt( + safe_prompt( [ { "name": "test", diff --git a/tests/utils.py b/tests/utils.py index 2737c336..eef099b5 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -5,7 +5,7 @@ from prompt_toolkit.input.defaults import create_pipe_input from prompt_toolkit.output import DummyOutput -from questionary import prompt +from questionary import safe_prompt from questionary.prompts import prompt_by_name from questionary.utils import is_prompt_toolkit_3 @@ -72,7 +72,7 @@ def patched_prompt(questions, text, **kwargs): def run(inp): # noinspection PyUnresolvedReferences inp.send_text(text) - result = prompt(questions, input=inp, output=DummyOutput(), **kwargs) + result = safe_prompt(questions, input=inp, output=DummyOutput(), **kwargs) return result return execute_with_input_pipe(run) From a80148feca7e4037418a69a9ef446b10df06e092 Mon Sep 17 00:00:00 2001 From: Sevrain Date: Thu, 29 Jan 2026 15:21:00 +0200 Subject: [PATCH 2/2] docs: fix invalid safe_prompt function links --- docs/pages/advanced.rst | 7 +++---- docs/pages/api_reference.rst | 2 +- docs/pages/quickstart.rst | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/pages/advanced.rst b/docs/pages/advanced.rst index 8cdc5e2c..5c58705d 100644 --- a/docs/pages/advanced.rst +++ b/docs/pages/advanced.rst @@ -104,7 +104,7 @@ Safe The following are safe (capture keyboard interrupts): -* :meth:`~questionary.safe_prompt`; +* :func:`~questionary.safe_prompt`; * :attr:`~questionary.Form.ask` on :class:`~questionary.Form` (returned by :meth:`~questionary.form`); @@ -270,7 +270,7 @@ them using a configuration dictionary: answers = safe_prompt(questions) -The questions will be prompted one after another and ``prompt`` will return +The questions will be prompted one after the other and ``safe_prompt`` will return as soon as all of them are answered. The returned ``answers`` will be a dictionary containing the responses, e.g. @@ -316,8 +316,7 @@ add the following optional parameters: Receive the user input and return the filtered value to be used inside the program. -Further information can be found at the :class:`questionary.safe_prompt` -documentation. +Further information can be found in the :func:`~questionary.safe_prompt` documentation. .. _random_label: diff --git a/docs/pages/api_reference.rst b/docs/pages/api_reference.rst index b3cef5e2..b7a2fcc1 100644 --- a/docs/pages/api_reference.rst +++ b/docs/pages/api_reference.rst @@ -21,6 +21,6 @@ API Reference .. automethod:: questionary::form -.. automethod:: questionary::prompt +.. automethod:: questionary::safe_prompt .. automethod:: questionary::unsafe_prompt diff --git a/docs/pages/quickstart.rst b/docs/pages/quickstart.rst index a9d3e524..d564abe2 100644 --- a/docs/pages/quickstart.rst +++ b/docs/pages/quickstart.rst @@ -82,7 +82,7 @@ The printed output will have the following format: {'first': True, 'second': 'item2'} -The :meth:`~questionary.safe_prompt` function also allows you to ask a +The :func:`~questionary.safe_prompt` function also allows you to ask a collection of questions, however instead of taking :class:`~questionary.Question` instances, it takes a dictionary: