"""
This module contains the base class for all workflows.
"""
from typing import TypeVar
from rich.console import Console
import questionary
from questionary import Choice
T = TypeVar('T')
[docs]class Workflow:
"""
This is the base class for all workflows. It features a few common methods
that we use in the derived workflows.
"""
[docs] def __init__(self) -> None:
self.c = Console()
self.q = questionary
self.style_mas = 'bold fg:#8B8000 bg:#000'
self.style_err = 'bold fg:#8B0000 bg:#000'
def _print_doc(self, more: str='') -> None:
self.q.print(10*'-' + '\n')
self.q.print(type(self).__doc__.strip() + more + '\n')
self.q.print(10*'-' + '\n')
def _wait_for(self, what_for: str) -> None:
self.q.print(text=f'Press [Enter] {what_for}.', style=self.style_mas, end='')
return self.q.text(message='', qmark='').ask()
[docs] def ask(self, options: list[str], prompt: str='You now have the following options:', rtype: T=int) -> T:
"""
Common method to ask for a selection of options among a list of choices.
Options are indexed starting from `0`. If the chosen return type is int,
the index is returned; the option as a string, otherwise.
options: ``list[str]``
A list of options to choose (select) from.
prompt: ``str``
The prompt shown to the user.
:rtype: ``T``
Returns either int (the index) or the option itself (of any type)
:return:
The index of the chosen option or the chosen option itself.
"""
res = self.askt(
options=list([(options[idx], idx) for idx in range(len(options))]),
prompt=prompt)
if res == None:
# When user cancels
return None
if rtype == str:
return options[res]
return res
[docs] def askt(self, options: list[tuple[str, T]], prompt: str='You now have the following options:') -> T:
"""
Wrapper around :py:meth:`ask()` that can use any type associated with
an option.
options: ``list[tuple[str, T]]``
The options, the text to show and the associated value for each
prompt: ``str``
The prompt shown to the user.
:rtype: ``T``
:return:
Returns the selected option's associated value.
"""
choices = list([Choice(title=options[idx][0], value=options[idx][1]) for idx in range(len(options))])
return self.q.select(message=prompt, choices=choices, use_shortcuts=True).ask()
[docs] def print_info(self, text_normal: str, text_vital: str=None, end: str=None, arrow: str=' -> ') -> None:
"""
Used to print an info that consists of a normal text (without extra styles)
and a vital text that has some extra styling applied to emphasize it.
text_normal: ``str``
The text that does not have extra styling
text_vital: ``str``
The text with extra styling for emphasis.
end: ``str``
The string to print at the end of the info.
arrow: ``str``
The string to print at the beginning of the info.
"""
kwargs = {}
if end != None:
kwargs['end'] = end
text_normal = f'{arrow}{text_normal}'
if text_vital == None:
self.q.print(text=text_normal, **kwargs)
else:
self.q.print(text=text_normal, end='')
self.q.print(text=text_vital, style=self.style_mas, **kwargs)