| """This module contains the classic entrypoint for creating prompts. |
| |
| A `PyInquirer <https://github.com/CITGuru/PyInquirer>`_ compatible entrypoint :func:`.prompt`. |
| """ |
| from typing import Any, Dict, List, Optional, Tuple, Union |
|
|
| from InquirerPy.exceptions import InvalidArgument, RequiredKeyNotFound |
| from InquirerPy.prompts.checkbox import CheckboxPrompt |
| from InquirerPy.prompts.confirm import ConfirmPrompt |
| from InquirerPy.prompts.expand import ExpandPrompt |
| from InquirerPy.prompts.filepath import FilePathPrompt |
| from InquirerPy.prompts.fuzzy import FuzzyPrompt |
| from InquirerPy.prompts.input import InputPrompt |
| from InquirerPy.prompts.list import ListPrompt |
| from InquirerPy.prompts.number import NumberPrompt |
| from InquirerPy.prompts.rawlist import RawlistPrompt |
| from InquirerPy.prompts.secret import SecretPrompt |
| from InquirerPy.utils import ( |
| InquirerPyKeybindings, |
| InquirerPyQuestions, |
| InquirerPySessionResult, |
| get_style, |
| ) |
|
|
| __all__ = ["prompt", "prompt_async"] |
|
|
| question_mapping = { |
| "confirm": ConfirmPrompt, |
| "filepath": FilePathPrompt, |
| "password": SecretPrompt, |
| "input": InputPrompt, |
| "list": ListPrompt, |
| "checkbox": CheckboxPrompt, |
| "rawlist": RawlistPrompt, |
| "expand": ExpandPrompt, |
| "fuzzy": FuzzyPrompt, |
| "number": NumberPrompt, |
| } |
|
|
|
|
| def _get_questions(questions: InquirerPyQuestions) -> List[Dict[str, Any]]: |
| """Process and validate questions. |
| |
| Args: |
| questions: List of questions to create prompt. |
| |
| Returns: |
| List of validated questions. |
| """ |
| if isinstance(questions, dict): |
| questions = [questions] |
|
|
| if not isinstance(questions, list): |
| raise InvalidArgument("argument questions should be type of list or dictionary") |
|
|
| return questions |
|
|
|
|
| def _get_question( |
| original_question: Dict[str, Any], result: InquirerPySessionResult, index: int |
| ) -> Tuple[Optional[Dict[str, Any]], str, Union[str, int], str]: |
| """Get information from individual question. |
| |
| Args: |
| original_question: Original question dictionary. |
| result: Current prompt session result. |
| index: Question index. |
| |
| Returns: |
| A tuple containing question information in the order of |
| question dictionary, type of question, name of question, message of question. |
| """ |
| question = original_question.copy() |
| question_type = question.pop("type") |
| question_name = question.pop("name", index) |
| message = question.pop("message") |
| question_when = question.pop("when", None) |
| if question_when and not question_when(result): |
| result[question_name] = None |
| question = None |
| return question, question_type, question_name, message |
|
|
|
|
| async def prompt_async( |
| questions: InquirerPyQuestions, |
| style: Optional[Dict[str, str]] = None, |
| vi_mode: bool = False, |
| raise_keyboard_interrupt: bool = True, |
| keybindings: Optional[InquirerPyKeybindings] = None, |
| style_override: bool = True, |
| ) -> InquirerPySessionResult: |
| """Classic syntax entrypoint to create a prompt session via asynchronous method. |
| |
| Refer to :func:`InquirerPy.resolver.prompt` for detailed documentations. |
| """ |
| result: InquirerPySessionResult = {} |
| if not keybindings: |
| keybindings = {} |
|
|
| questions = _get_questions(questions=questions) |
| question_style = get_style(style, style_override) |
|
|
| for index, original_question in enumerate(questions): |
| try: |
| question, question_type, question_name, message = _get_question( |
| original_question=original_question, result=result, index=index |
| ) |
| if question is None: |
| continue |
| args = { |
| "message": message, |
| "style": question_style, |
| "vi_mode": vi_mode, |
| "raise_keyboard_interrupt": raise_keyboard_interrupt, |
| "session_result": result, |
| "keybindings": {**keybindings, **question.pop("keybindings", {})}, |
| } |
| result[question_name] = await question_mapping[question_type]( |
| **args, **question |
| ).execute_async() |
| except KeyError: |
| raise RequiredKeyNotFound |
|
|
| return result |
|
|
|
|
| def prompt( |
| questions: InquirerPyQuestions, |
| style: Optional[Dict[str, str]] = None, |
| vi_mode: bool = False, |
| raise_keyboard_interrupt: bool = True, |
| keybindings: Optional[InquirerPyKeybindings] = None, |
| style_override: bool = True, |
| ) -> InquirerPySessionResult: |
| """Classic syntax entrypoint to create a prompt session. |
| |
| Resolve user provided list of questions, display prompts and get the results. |
| |
| Args: |
| questions: A list of :ref:`pages/prompt:question` to ask. Refer to documentation for more info. |
| style: A :class:`dict` containing the style specification for the prompt. Refer to :ref:`pages/style:Style` for more info. |
| vi_mode: Use vim keybindings for the prompt instead of the default emacs keybindings. |
| Refer to :ref:`pages/kb:Keybindings` for more info. |
| raise_keyboard_interrupt: Raise the :class:`KeyboardInterrupt` exception when `ctrl-c` is pressed. If false, the result |
| will be `None` and the question is skiped. |
| keybindings: List of custom :ref:`pages/kb:Keybindings` to apply. Refer to documentation for more info. |
| style_override: Override all default styles. When providing any style customisation, all default styles are removed when this is True. |
| |
| Returns: |
| A dictionary containing all of the question answers. The key is the name of the question and the value is the |
| user answer. If the `name` key is not present as part of the question, then the question index will be used |
| as the key. |
| |
| Raises: |
| RequiredKeyNotFound: When the question is missing required keys. |
| InvalidArgument: When the provided `questions` argument is not a type of :class:`list` nor :class:`dictionary`. |
| |
| Examples: |
| >>> from InquirerPy import prompt |
| >>> from InquirerPy.validator import NumberValidator |
| >>> questions = [ |
| ... { |
| ... "type": "input", |
| ... "message": "Enter your age:", |
| ... "validate": NumberValidator(), |
| ... "invalid_message": "Input should be number.", |
| ... "default": "18", |
| ... "name": "age", |
| ... "filter": lambda result: int(result), |
| ... "transformer": lambda result: "Adult" if int(result) >= 18 else "Youth", |
| ... }, |
| ... { |
| ... "type": "rawlist", |
| ... "message": "What drinks would you like to buy:", |
| ... "default": 2, |
| ... "choices": lambda result: ["Soda", "Cidr", "Water", "Milk"] |
| ... if result["age"] < 18 |
| ... else ["Wine", "Beer"], |
| ... "name": "drink", |
| ... }, |
| ... { |
| ... "type": "list", |
| ... "message": "Would you like a bag:", |
| ... "choices": ["Yes", "No"], |
| ... "when": lambda result: result["drink"] in {"Wine", "Beer"}, |
| ... }, |
| ... {"type": "confirm", "message": "Confirm?", "default": True}, |
| ... ] |
| >>> result = prompt(questions=questions) |
| """ |
| result: InquirerPySessionResult = {} |
| if not keybindings: |
| keybindings = {} |
|
|
| questions = _get_questions(questions=questions) |
| question_style = get_style(style, style_override) |
|
|
| for index, original_question in enumerate(questions): |
| try: |
| question, question_type, question_name, message = _get_question( |
| original_question=original_question, result=result, index=index |
| ) |
| if question is None: |
| continue |
| args = { |
| "message": message, |
| "style": question_style, |
| "vi_mode": vi_mode, |
| "raise_keyboard_interrupt": raise_keyboard_interrupt, |
| "session_result": result, |
| "keybindings": {**keybindings, **question.pop("keybindings", {})}, |
| } |
| result[question_name] = question_mapping[question_type]( |
| **args, **question |
| ).execute() |
| except KeyError: |
| raise RequiredKeyNotFound |
|
|
| return result |
|
|