def test_validator_instance(): def validate(t): return len(t) == 3 validator = Validator.from_callable(validate) validator = build_validator(validator) assert validator.validate(Document("foo")) is None # should not raise
def test_validator_bool_function_fails(): def validate(t): return len(t) == 3 validator = build_validator(validate) with pytest.raises(ValidationError) as e: validator.validate(Document("fooooo")) assert e.value.message == "Invalid input"
def text(message: Text, default: Text = "", validate: Union[Type[Validator], Callable[[Text], bool], None] = None, # noqa qmark: Text = DEFAULT_QUESTION_PREFIX, style: Optional[Style] = None, **kwargs: Any) -> Question: """Prompt the user to enter a free text message. This question type can be used to prompt the user for some text input. Args: message: Question text default: Default value will be returned if the user just hits enter. validate: Require the entered value to pass a validation. The value can not be submited until the validator accepts it (e.g. to check minimum password length). This can either be a function accepting the input and returning a boolean, or an class reference to a subclass of the prompt toolkit Validator class. qmark: Question prefix displayed in front of the question. By default this is a `?` style: A custom color and style for the question parts. You can configure colors as well as font types for different elements. Returns: Question: Question instance, ready to be prompted (using `.ask()`). """ merged_style = merge_styles([DEFAULT_STYLE, style]) validator = build_validator(validate) def get_prompt_tokens(): return [("class:qmark", qmark), ("class:question", ' {} '.format(message))] p = PromptSession(get_prompt_tokens, style=merged_style, validator=validator, **kwargs) p.default_buffer.reset(Document(default)) return Question(p.app)
def test_validator_bool_function(): def validate(t): return len(t) == 3 validator = build_validator(validate) assert validator.validate(Document("foo")) is None # should not raise
def path( message: str, default: str = "", qmark: str = DEFAULT_QUESTION_PREFIX, validate: Any = None, style: Optional[Style] = None, only_directories: bool = False, file_filter: Optional[Callable[[str], bool]] = None, complete_style: CompleteStyle = CompleteStyle.MULTI_COLUMN, **kwargs: Any, ) -> Question: """A text input for a file or directory path with autocompletion enabled. Example: >>> import questionary >>> questionary.path("What's the path to the projects version file?").ask() ? What's the path to the projects version file? ./pyproject.toml './pyproject.toml' .. image:: ../images/path.gif This is just a really basic example, the prompt can be customised using the parameters. Args: message: Question text. default: Default return value (single value). qmark: Question prefix displayed in front of the question. By default this is a ``?``. complete_style: How autocomplete menu would be shown, it could be ``COLUMN`` ``MULTI_COLUMN`` or ``READLINE_LIKE`` from :class:`prompt_toolkit.shortcuts.CompleteStyle`. validate: Require the entered value to pass a validation. The value can not be submitted until the validator accepts it (e.g. to check minimum password length). This can either be a function accepting the input and returning a boolean, or an class reference to a subclass of the prompt toolkit Validator class. style: A custom color and style for the question parts. You can configure colors as well as font types for different elements. only_directories: Only show directories in auto completion file_filter: Optional callable to filter suggested paths. Only paths where the passed callable evaluates to ``True`` will show up in the suggested paths. This does not validate the typed path, e.g. it is still possible for the user to enter a path manually, even though this filter evaluates to ``False``. If in addition to filtering suggestions you also want to validate the result, use ``validate`` in combination with the ``file_filter``. Returns: :class:`Question`: Question instance, ready to be prompted (using ``.ask()``). """ merged_style = merge_styles([DEFAULT_STYLE, style]) def get_prompt_tokens() -> List[Tuple[str, str]]: return [("class:qmark", qmark), ("class:question", " {} ".format(message))] validator = build_validator(validate) bindings = KeyBindings() @bindings.add(Keys.ControlM, eager=True) def set_answer(event: KeyPressEvent): if event.current_buffer.complete_state is not None: event.current_buffer.complete_state = None elif event.app.current_buffer.validate(set_cursor=True): # When the validation succeeded, accept the input. result_path = event.app.current_buffer.document.text if result_path.endswith(os.path.sep): result_path = result_path[:-1] event.app.exit(result=result_path) event.app.current_buffer.append_to_history() @bindings.add(os.path.sep, eager=True) def next_segment(event: KeyPressEvent): b = event.app.current_buffer if b.complete_state: b.complete_state = None current_path = b.document.text if not current_path.endswith(os.path.sep): b.insert_text(os.path.sep) b.start_completion(select_first=False) p = PromptSession( get_prompt_tokens, lexer=SimpleLexer("class:answer"), style=merged_style, completer=GreatUXPathCompleter(only_directories=only_directories, file_filter=file_filter, expanduser=True), validator=validator, complete_style=complete_style, key_bindings=bindings, **kwargs, ) p.default_buffer.reset(Document(default)) return Question(p.app)
def autocomplete( message: str, choices: List[str], default: str = "", qmark: str = DEFAULT_QUESTION_PREFIX, completer: Optional[Completer] = None, meta_information: Optional[Dict[str, Any]] = None, ignore_case: bool = True, match_middle: bool = True, complete_style: CompleteStyle = CompleteStyle.COLUMN, validate: Any = None, style: Optional[Style] = None, **kwargs: Any, ) -> Question: """Prompt the user to enter a message with autocomplete help. Example: >>> import questionary >>> questionary.autocomplete( ... 'Choose ant specie', ... choices=[ ... 'Camponotus pennsylvanicus', ... 'Linepithema humile', ... 'Eciton burchellii', ... "Atta colombica", ... 'Polyergus lucidus', ... 'Polyergus rufescens', ... ]).ask() ? Choose ant specie Atta colombica 'Atta colombica' .. image:: ../images/autocomplete.gif This is just a realy basic example, the prompt can be customised using the parameters. Args: message: Question text choices: Items shown in the selection, this contains items as strings default: Default return value (single value). qmark: Question prefix displayed in front of the question. By default this is a ``?`` completer: A prompt_toolkit :class:`prompt_toolkit.completion.Completion` implementation. If not set, a questionary completer implementation will be used. meta_information: A dictionary with information/anything about choices. ignore_case: If true autocomplete would ignore case. match_middle: If true autocomplete would search in every string position not only in string begin. complete_style: How autocomplete menu would be shown, it could be ``COLUMN`` ``MULTI_COLUMN`` or ``READLINE_LIKE`` from :class:`prompt_toolkit.shortcuts.CompleteStyle`. validate: Require the entered value to pass a validation. The value can not be submitted until the validator accepts it (e.g. to check minimum password length). This can either be a function accepting the input and returning a boolean, or an class reference to a subclass of the prompt toolkit Validator class. style: A custom color and style for the question parts. You can configure colors as well as font types for different elements. Returns: :class:`Question`: Question instance, ready to be prompted (using ``.ask()``). """ merged_style = merge_styles([DEFAULT_STYLE, style]) def get_prompt_tokens() -> List[Tuple[str, str]]: return [("class:qmark", qmark), ("class:question", " {} ".format(message))] def get_meta_style(meta: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]: if meta: for key in meta: meta[key] = HTML("<text>{}</text>").format(meta[key]) return meta validator = build_validator(validate) if completer is None: if not choices: raise ValueError("No choices is given, you should use Text question.") # use the default completer completer = WordCompleter( choices, ignore_case=ignore_case, meta_information=get_meta_style(meta_information), match_middle=match_middle, ) p = PromptSession( get_prompt_tokens, lexer=SimpleLexer("class:answer"), style=merged_style, completer=completer, validator=validator, complete_style=complete_style, **kwargs, ) p.default_buffer.reset(Document(default)) return Question(p.app)
def text( message: Text, default: Text = "", validate: Any = None, qmark: Text = DEFAULT_QUESTION_PREFIX, style: Optional[Style] = None, multiline: bool = False, instruction: Optional[Text] = None, **kwargs: Any, ) -> Question: """Prompt the user to enter a free text message. This question type can be used to prompt the user for some text input. Args: message: Question text default: Default value will be returned if the user just hits enter. validate: Require the entered value to pass a validation. The value can not be submited until the validator accepts it (e.g. to check minimum password length). This can either be a function accepting the input and returning a boolean, or an class reference to a subclass of the prompt toolkit Validator class. qmark: Question prefix displayed in front of the question. By default this is a `?` style: A custom color and style for the question parts. You can configure colors as well as font types for different elements. multiline: If `True`, multiline input will be enabled. instruction: Write instructions for the user if needed. If `None` and `multiline=True`, some instructions will appear. Returns: Question: Question instance, ready to be prompted (using `.ask()`). """ merged_style = merge_styles([DEFAULT_STYLE, style]) validator = build_validator(validate) if instruction is None and multiline: instruction = INSTRUCTION_MULTILINE def get_prompt_tokens() -> List[Tuple[Text, Text]]: result = [("class:qmark", qmark), ("class:question", " {} ".format(message))] if instruction: result.append(("class:instruction", " {} ".format(instruction))) return result p = PromptSession( get_prompt_tokens, style=merged_style, validator=validator, lexer=SimpleLexer("class:answer"), multiline=multiline, **kwargs, ) p.default_buffer.reset(Document(default)) return Question(p.app)
def text(message: Text, default: Text = "", validate: Union[Validator, Callable[[Text], bool], None] = None, # noqa qmark: Text = DEFAULT_QUESTION_PREFIX, style: Optional[Style] = None, path_autocomplete=False, exec_autocomplete=False, custom_autocomplete=None, ** kwargs: Any) -> Question: """Prompt the user to enter a free text message. This question type can be used to prompt the user for some text input. Args: message: Question text default: Default value will be returned if the user just hits enter. validate: Require the entered value to pass a validation. The value can not be submited until the validator accepts it (e.g. to check minimum password length). This can either be a function accepting the input and returning a boolean, or an class reference to a subclass of the prompt toolkit Validator class. qmark: Question prefix displayed in front of the question. By default this is a `?` style: A custom color and style for the question parts. You can configure colors as well as font types for different elements. Returns: Question: Question instance, ready to be prompted (using `.ask()`). """ merged_style = merge_styles([DEFAULT_STYLE, style]) validator = build_validator(validate) def get_prompt_tokens(): return [("class:qmark", qmark), ("class:question", ' {} '.format(message))] promptArgs = dict({ 'style': merged_style, 'validator': validator, 'complete_style': CompleteStyle.READLINE_LIKE, }) if path_autocomplete: promptArgs['completer'] = PathCompleter( expanduser=True, delimiters=' \t\n;,') elif exec_autocomplete: promptArgs['completer'] = ExecutableCompleter(delimiters=' \t\n;,') elif custom_autocomplete is not None and len(custom_autocomplete): promptArgs['completer'] = WordCompleter( custom_autocomplete, ignore_case=True, sentence=True) p = PromptSession(get_prompt_tokens, **promptArgs, **kwargs) p.default_buffer.reset(Document(default)) return Question(p.app)
def autocomplete( message: Text, choices: List[Text], default: Text = "", qmark: Text = DEFAULT_QUESTION_PREFIX, completer: Optional[Completer] = None, meta_information: Optional[Dict[Text, Any]] = None, ignore_case: bool = True, match_middle: bool = True, complete_style: CompleteStyle = CompleteStyle.COLUMN, validate: Any = None, style: Optional[Style] = None, **kwargs: Any, ) -> Question: """Prompt the user to enter a message with autocomplete help. Args: message: Question text choices: Items shown in the selection, this contains items as strings default: Default return value (single value). qmark: Question prefix displayed in front of the question. By default this is a `?` completer: A prompt_toolkit `Completer` implementation. If not set, a questionary completer implementation will be used. meta_information: A dictionary with information/anything about choices. ignore_case: If true autocomplete would ignore case. match_middle: If true autocomplete would search in every string position not only in string begin. complete_style: How autocomplete menu would be shown, it could be COLUMN, MULTI_COLUMN or READLINE_LIKE validate: Require the entered value to pass a validation. The value can not be submitted until the validator accepts it (e.g. to check minimum password length). This can either be a function accepting the input and returning a boolean, or an class reference to a subclass of the prompt toolkit Validator class. style: A custom color and style for the question parts. You can configure colors as well as font types for different elements. Returns: Question: Question instance, ready to be prompted (using `.ask()`). """ merged_style = merge_styles([DEFAULT_STYLE, style]) def get_prompt_tokens() -> List[Tuple[Text, Text]]: return [("class:qmark", qmark), ("class:question", " {} ".format(message))] def get_meta_style( meta: Optional[Dict[Text, Any]]) -> Optional[Dict[Text, Any]]: if meta: for key in meta: meta[key] = HTML("<text>{}</text>").format(meta[key]) return meta validator = build_validator(validate) if completer is None: if not choices: raise ValueError( "No choices is given, you should use Text question.") # use the default completer completer = WordCompleter( choices, ignore_case=ignore_case, meta_information=get_meta_style(meta_information), match_middle=match_middle, ) p = PromptSession( get_prompt_tokens, lexer=SimpleLexer("class:answer"), style=merged_style, completer=completer, validator=validator, complete_style=complete_style, **kwargs, ) p.default_buffer.reset(Document(default)) return Question(p.app)
def text( message: str, default: str = "", validate: Any = None, qmark: str = DEFAULT_QUESTION_PREFIX, style: Optional[Style] = None, multiline: bool = False, instruction: Optional[str] = None, lexer: Optional[Lexer] = None, **kwargs: Any, ) -> Question: """Prompt the user to enter a free text message. This question type can be used to prompt the user for some text input. Example: >>> import questionary >>> questionary.text("What's your first name?").ask() ? What's your first name? Tom 'Tom' .. image:: ../images/text.gif This is just a really basic example, the prompt can be customised using the parameters. Args: message: Question text. default: Default value will be returned if the user just hits enter. validate: Require the entered value to pass a validation. The value can not be submitted until the validator accepts it (e.g. to check minimum password length). This can either be a function accepting the input and returning a boolean, or an class reference to a subclass of the prompt toolkit Validator class. qmark: Question prefix displayed in front of the question. By default this is a ``?``. style: A custom color and style for the question parts. You can configure colors as well as font types for different elements. multiline: If ``True``, multiline input will be enabled. instruction: Write instructions for the user if needed. If ``None`` and ``multiline=True``, some instructions will appear. lexer: Supply a valid lexer to style the answer. Leave empty to use a simple one by default. kwargs: Additional arguments, they will be passed to prompt toolkit. Returns: :class:`Question`: Question instance, ready to be prompted (using ``.ask()``). """ merged_style = merge_styles([DEFAULT_STYLE, style]) lexer = lexer or SimpleLexer("class:answer") validator = build_validator(validate) if instruction is None and multiline: instruction = INSTRUCTION_MULTILINE def get_prompt_tokens() -> List[Tuple[str, str]]: result = [("class:qmark", qmark), ("class:question", " {} ".format(message))] if instruction: result.append(("class:instruction", " {} ".format(instruction))) return result p = PromptSession( get_prompt_tokens, style=merged_style, validator=validator, lexer=lexer, multiline=multiline, **kwargs, ) p.default_buffer.reset(Document(default)) return Question(p.app)