radubulimac's picture
fix import issue
2d876d1
"""Module contains the class to create filepath prompt and filepath completer class."""
import os
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, Generator, Optional
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.completion.base import ThreadedCompleter
from InquirerPy.prompts.input import InputPrompt
from InquirerPy.utils import (
InquirerPyDefault,
InquirerPyKeybindings,
InquirerPyMessage,
InquirerPySessionResult,
InquirerPyStyle,
InquirerPyValidate,
)
if TYPE_CHECKING:
from prompt_toolkit.input.base import Input
from prompt_toolkit.output.base import Output
__all__ = ["FilePathPrompt", "FilePathCompleter"]
class FilePathCompleter(Completer):
"""An auto completion class which generates system filepath.
See Also:
:class:`~prompt_toolkit.completion.Completer`
Args:
only_directories: Only complete directories.
only_files: Only complete files.
"""
def __init__(self, only_directories: bool = False, only_files: bool = False):
self._only_directories = only_directories
self._only_files = only_files
self._delimiter = "/" if os.name == "posix" else "\\"
def get_completions(
self, document, complete_event
) -> Generator[Completion, None, None]:
"""Get a list of valid system paths."""
if document.text == "~":
return
validation = lambda file, doc_text: str(file).startswith(doc_text)
if document.cursor_position == 0:
dirname = Path.cwd()
validation = lambda file, doc_text: True
elif document.text.startswith("~"):
dirname = Path(os.path.dirname(f"{Path.home()}{document.text[1:]}"))
validation = lambda file, doc_text: str(file).startswith(
f"{Path.home()}{doc_text[1:]}"
)
elif document.text.startswith(f".{self._delimiter}"):
dirname = Path(os.path.dirname(document.text))
validation = lambda file, doc_text: str(file).startswith(doc_text[2:])
else:
dirname = Path(os.path.dirname(document.text))
for item in self._get_completion(document, dirname, validation):
yield item
def _get_completion(
self, document, path, validation
) -> Generator[Completion, None, None]:
if not path.is_dir():
return
for file in path.iterdir():
if self._only_directories and not file.is_dir():
continue
if self._only_files and not file.is_file():
continue
if validation(file, document.text):
file_name = file.name
display_name = file_name
if file.is_dir():
display_name = f"{file_name}{self._delimiter}"
yield Completion(
file.name,
start_position=-1 * len(os.path.basename(document.text)),
display=display_name,
)
class FilePathPrompt(InputPrompt):
"""Create a prompt that provides auto completion for system filepaths.
A wrapper class around :class:`~prompt_toolkit.shortcuts.PromptSession`.
Args:
message: The question to ask the user.
Refer to :ref:`pages/dynamic:message` documentation for more details.
style: An :class:`InquirerPyStyle` instance.
Refer to :ref:`Style <pages/style:Alternate Syntax>` documentation for more details.
vi_mode: Use vim keybinding for the prompt.
Refer to :ref:`pages/kb:Keybindings` documentation for more details.
default: Set the default text value of the prompt.
Refer to :ref:`pages/dynamic:default` documentation for more details.
qmark: Question mark symbol. Custom symbol that will be displayed infront of the question before its answered.
amark: Answer mark symbol. Custom symbol that will be displayed infront of the question after its answered.
instruction: Short instruction to display next to the question.
long_instruction: Long instructions to display at the bottom of the prompt.
multicolumn_complete: Change the auto-completion UI to a multi column display.
validate: Add validation to user input.
Refer to :ref:`pages/validator:Validator` documentation for more details.
invalid_message: Error message to display when user input is invalid.
Refer to :ref:`pages/validator:Validator` documentation for more details.
transformer: A function which performs additional transformation on the value that gets printed to the terminal.
Different than `filter` parameter, this is only visual effect and won’t affect the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
Refer to :ref:`pages/dynamic:transformer` documentation for more details.
filter: A function which performs additional transformation on the result.
This affects the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
Refer to :ref:`pages/dynamic:filter` documentation for more details.
keybindings: Customise the builtin keybindings.
Refer to :ref:`pages/kb:Keybindings` for more details.
wrap_lines: Soft wrap question lines when question exceeds the terminal width.
only_directories: Only complete directories.
only_files: Only complete files.
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.
mandatory: Indicate if the prompt is mandatory. If True, then the question cannot be skipped.
mandatory_message: Error message to show when user attempts to skip mandatory prompt.
session_result: Used internally for :ref:`index:Classic Syntax (PyInquirer)`.
input: Used internally and will be removed in future updates.
output: Used internally and will be removed in future updates.
Examples:
>>> from InquirerPy import inquirer
>>> result = inquirer.filepath(message="Enter a path:").execute()
>>> print(result)
/home/ubuntu/README.md
"""
def __init__(
self,
message: InquirerPyMessage,
style: Optional[InquirerPyStyle] = None,
vi_mode: bool = False,
default: InquirerPyDefault = "",
qmark: str = "?",
amark: str = "?",
instruction: str = "",
long_instruction: str = "",
multicolumn_complete: bool = False,
validate: Optional[InquirerPyValidate] = None,
invalid_message: str = "Invalid input",
only_directories: bool = False,
only_files: bool = False,
transformer: Optional[Callable[[str], Any]] = None,
filter: Optional[Callable[[str], Any]] = None,
keybindings: Optional[InquirerPyKeybindings] = None,
wrap_lines: bool = True,
raise_keyboard_interrupt: bool = True,
mandatory: bool = True,
mandatory_message: str = "Mandatory prompt",
session_result: Optional[InquirerPySessionResult] = None,
input: Optional["Input"] = None,
output: Optional["Output"] = None,
) -> None:
super().__init__(
message=message,
style=style,
vi_mode=vi_mode,
default=default,
qmark=qmark,
amark=amark,
instruction=instruction,
long_instruction=long_instruction,
completer=ThreadedCompleter(
FilePathCompleter(
only_directories=only_directories, only_files=only_files
)
),
multicolumn_complete=multicolumn_complete,
validate=validate,
invalid_message=invalid_message,
transformer=transformer,
filter=filter,
keybindings=keybindings,
wrap_lines=wrap_lines,
raise_keyboard_interrupt=raise_keyboard_interrupt,
mandatory=mandatory,
mandatory_message=mandatory_message,
session_result=session_result,
input=input,
output=output,
)