Source code for questionary.prompt

from prompt_toolkit.output import ColorDepth
from typing import Any, Dict, Optional, Iterable, Mapping

from questionary import utils
from questionary.constants import DEFAULT_KBI_MESSAGE
from questionary.prompts import AVAILABLE_PROMPTS, prompt_by_name


class PromptParameterException(ValueError):
    def __init__(self, message: str, errors: Optional[BaseException] = None) -> None:
        # Call the base class constructor with the parameters it needs
        super().__init__("You must provide a `%s` value" % message, errors)


[docs]def prompt( questions: Iterable[Mapping[str, Any]], answers: Optional[Mapping[str, Any]] = None, patch_stdout: bool = False, true_color: bool = False, kbi_msg: str = DEFAULT_KBI_MESSAGE, **kwargs: Any, ) -> Dict[str, Any]: """Prompt the user for input on all the questions. Catches keyboard interrupts and prints a message. See :func:`unsafe_prompt` for possible question configurations. Args: questions: A list of question configs representing questions to ask. A question config may have the following options: * type - The type of question. * name - An ID for the question (to identify it in the answers :obj:`dict`). * when - Callable to conditionally show the question. This function takes a :obj:`dict` representing the current answers. * filter - Function that the answer is passed to. The return value of this function is saved as the answer. Additional options correspond to the parameter names for particular question types. answers: Default answers. patch_stdout: Ensure that the prompt renders correctly if other threads 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 value is ignored. type: Default ``type`` value to use in question config. filter: Default ``filter`` value to use in question config. name: Default ``name`` value to use in question config. when: Default ``when`` value to use in question config. default: Default ``default`` value to use in question config. kwargs: Additional options passed to every question. Returns: Dictionary of question answers. """ try: return unsafe_prompt(questions, answers, patch_stdout, true_color, **kwargs) except KeyboardInterrupt: print("") print(kbi_msg) print("") return {}
[docs]def unsafe_prompt( questions: Iterable[Mapping[str, Any]], answers: Optional[Mapping[str, Any]] = None, patch_stdout: bool = False, true_color: bool = False, **kwargs: Any, ) -> Dict[str, Any]: """Prompt the user for input on all the questions. Won't catch keyboard interrupts. Args: questions: A list of question configs representing questions to ask. A question config may have the following options: * type - The type of question. * name - An ID for the question (to identify it in the answers :obj:`dict`). * when - Callable to conditionally show the question. This function takes a :obj:`dict` representing the current answers. * filter - Function that the answer is passed to. The return value of this function is saved as the answer. Additional options correspond to the parameter names for particular question types. answers: Default answers. patch_stdout: Ensure that the prompt renders correctly if other threads are printing to stdout. true_color: Use true color output. color_depth: Color depth to use. If ``true_color`` is set to true then this value is ignored. type: Default ``type`` value to use in question config. filter: Default ``filter`` value to use in question config. name: Default ``name`` value to use in question config. when: Default ``when`` value to use in question config. default: Default ``default`` value to use in question config. kwargs: Additional options passed to every question. Returns: Dictionary of question answers. Raises: KeyboardInterrupt: raised on keyboard interrupt """ if isinstance(questions, dict): questions = [questions] answers = dict(answers or {}) for question_config in questions: question_config = dict(question_config) # import the question if "type" not in question_config: raise PromptParameterException("type") if "name" not in question_config: raise PromptParameterException("name") choices = question_config.get("choices") if choices is not None and callable(choices): question_config["choices"] = choices(answers) _kwargs = kwargs.copy() _kwargs.update(question_config) _type = _kwargs.pop("type") _filter = _kwargs.pop("filter", None) name = _kwargs.pop("name") when = _kwargs.pop("when", None) if true_color: _kwargs["color_depth"] = ColorDepth.TRUE_COLOR if when: # at least a little sanity check! if callable(question_config["when"]): try: if not question_config["when"](answers): continue except Exception as e: raise ValueError( "Problem in 'when' check of {} " "question: {}".format(name, e) ) else: raise ValueError( "'when' needs to be function that accepts a dict argument" ) if _filter: # at least a little sanity check! if not callable(_filter): raise ValueError( "'filter' needs to be function that accepts an argument" ) if callable(question_config.get("default")): _kwargs["default"] = question_config["default"](answers) create_question_func = prompt_by_name(_type) if not create_question_func: raise ValueError( "No question type '{}' found. " "Known question types are {}." "".format(_type, ", ".join(AVAILABLE_PROMPTS)) ) missing_args = list(utils.missing_arguments(create_question_func, _kwargs)) if missing_args: raise PromptParameterException(missing_args[0]) question = create_question_func(**_kwargs) answer = question.unsafe_ask(patch_stdout) if answer is not None: if _filter: try: answer = _filter(answer) except Exception as e: raise ValueError( "Problem processing 'filter' of {} " "question: {}".format(name, e) ) answers[name] = answer return answers