def q(self, questions: Union[List[dict], dict], clear: bool = False, save_prompt: bool = True): """Ask questions and handle interruptions. Args: questions: Single dictionary or a list with question dictionaries clear: Set to True to clear screen before questioning. save_prompt: Set to False to disable asking about saving progress if the user interrupts. Returns: Dictionary with answers """ if clear: clear_screen() if isinstance(questions, dict): questions = [questions] # Wrap and indent question max_width = min(console.size[0], 80) tw1 = textwrap.TextWrapper(width=max_width, break_long_words=False, subsequent_indent=" ") tw2 = textwrap.TextWrapper(width=max_width, break_long_words=False, initial_indent=" ", subsequent_indent=" ") for q in questions: q["message"] = "\n".join( tw1.fill(line) if i == 0 else tw2.fill(line) for i, line in enumerate(q["message"].splitlines())) answer = prompt(questions, style=style) # Handle interruptions if not answer: if save_prompt: if prompt([{ "type": "confirm", "name": "answer", "message": "Do you want to save your progress so far to be able to resume the wizard later?" }], style=style).get("answer"): self.save_config() sys.exit() return answer
def get_login_info(self) -> Optional[Tuple[str, str]]: '''Returns the (email, password) pair for login''' args = get_args() if args.login: return args.login # end if if args.suppress: return None # end if answer = prompt([ { 'type': 'confirm', 'name': 'login', 'message': 'Do you want to log in?', 'default': False }, ]) if answer['login']: answer = prompt([ { 'type': 'input', 'name': 'email', 'message': 'User/Email:', 'validate': lambda a: True if a else 'User/Email should be not be empty' }, { 'type': 'password', 'name': 'password', 'message': 'Password:'******'validate': lambda a: True if a else 'Password should be not be empty' }, ]) return answer['email'], answer['password'] # end if return None
def server_configuration_questionaire(dirs, instance_name): """Questionary to generate a config file for the node instance.""" config = q.prompt([ { "type": "text", "name": "description", "message": "Enter a human-readable description:" }, { "type": "text", "name": "ip", "message": "ip:", "default": "0.0.0.0" }, { "type": "text", "name": "port", "message": "Enter port to which the server listens:", "default": "5000" }, { "type": "text", "name": "api_path", "message": "Path of the api:", "default": "/api" }, { "type": "text", "name": "uri", "message": "Database URI:", "default": "sqlite:///default.sqlite" }, { "type": "select", "name": "allow_drop_all", "message": "Allowed to drop all tables: ", "choices": ["True", "False"] } ]) res = q.select("Which level of logging would you like?", choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NOTSET"] ).ask() constant_jwt_secret = q.confirm("Do you want a constant JWT secret?").ask() if constant_jwt_secret: config["jwt_secret_key"] = str(uuid.uuid1()) config["logging"] = { "level": res, "file": f"{instance_name}.log", "use_console": True, "backup_count":5, "max_size": 1024, "format": "%(asctime)s - %(name)-14s - %(levelname)-8s - %(message)s", "datefmt": "%Y-%m-%d %H:%M:%S" } return config
def ask_dictstyle(**kwargs): questions = [ { "type": "confirm", "name": "conditional_step", "message": "Would you like the next question?", "default": True, }, { "type": "text", "name": "next_question", "message": "Name this library?", # Validate if the first question was answered with yes or no "when": lambda x: x["conditional_step"], # Only accept questionary as answer "validate": lambda val: val == "questionary", }, { "type": "select", "name": "second_question", "message": "Select item", "choices": ["item1", "item2", Separator(), "other"], }, { "type": "text", # intentionally overwrites result from previous question "name": "second_question", "message": "Insert free text", "when": lambda x: x["second_question"] == "other", }, ] return prompt(questions)
def user_selects(message: str, choices: list, selection_type="list", sort_choices=True) -> Union[str, list]: """Prompts the user to select a choice(s) given a message Args: message (str): the message to give to the user before they choose choices (list): a list of the options to provide selection_type (str, optional): Defaults to "list". Should be "list" or "checkbox" for radio-button-style or checkbox-style selections sort_choices (bool, optional): Defaults to True. Whether to alphabetically sort the choices in the list provided to the user Returns: str or list: the str for the choice selected if "list" is the selection_type the list of the choices selected if "checkbox" is the selection_type """ question = [ { "type": selection_type, "name": 'value', "message": message, "choices": sorted(choices) if sort_choices else choices }, ] answer = prompt(question) return answer['value']
def user_input(message: str, default="", validator=None) -> str: """Prompts the user for input Args: message (str): the message to give to the user before they provide input default (str, optional): Defaults to "". The default input response validator (Validator, optional): Defaults to None. A PyInquirer validator used to validate input before proceeding Returns: str: the user's response """ if validator is not None: question = [ { "type": "input", "name": 'value', "message": message, "default": default, "validate": validator, }, ] else: question = [ { "type": "input", "name": 'value', "message": message, "default": default }, ] answer = prompt(question) return answer["value"]
def q0() -> BaseTask: ''' This question is used to select the task you wish to alter with pdpp. ''' tasks = get_riggable_tasks() click_clear() choice_list = [] for task in tasks: choice_list.append(Choice( title=task.target_dir, value=task, )) questions_0 = [{ 'type': 'list', 'name': 'target_dir', 'message': 'Select the task you would like to rig:', 'choices': choice_list }] return prompt(questions_0, style=custom_style_fancy)['target_dir']
def get_answers(self) -> AnyByStrDict: """Obtain answers for all questions. It produces a TUI for querying the user if `ask_user` is true. Otherwise, it gets answers from other sources. """ previous_answers = self.get_best_answers() if self.ask_user: # HACK https://github.com/tmbo/questionary/pull/79 # TODO Remove type: ignore comments when fixed self.answers_user = prompt( (question.get_questionary_structure() for question in self.questions), # type: ignore answers=previous_answers, # type: ignore ) # HACK https://github.com/tmbo/questionary/issues/74 if not self.answers_user and self.questions: raise KeyboardInterrupt else: # Avoid prompting to not requiring a TTy when --force for question in self.questions: new_answer = question.get_default() previous_answer = previous_answers.get(question.var_name) if new_answer != previous_answer: self.answers_user[question.var_name] = new_answer return self.answers_user
def q_extant() -> StandardTask: ''' This question is used to select the directory you wish to automate. ''' task_dirs = [d.target_dir for d in get_pdpp_tasks()] click_clear() dir_list = [ d.name for d in os.scandir() if d.name not in task_dirs and d.is_dir() ] choice_list = [] print(task_dirs) print(dir_list) for _dir in dir_list: choice_list.append(Choice( title=_dir, value=_dir, )) questions_0 = [{ 'type': 'list', 'name': 'target_dir', 'message': 'Select the directory you would like to automate:', 'choices': choice_list }] dirname = prompt(questions_0, style=custom_style_fancy)['target_dir'] return StandardTask(target_dir=dirname)
def get_kpi(preloaded_matrix, preloaded_KPIs): """Prompts for user selection on KPIs to print. Invokes benchmarking.get_selected_metrics() to calculate KPIs. Lastly, display menu to user after calculation. Args: preloaded_matrix (obj): Matrix used for calculating KPIs preloaded_KPIs (obj): Metrics used for calculating KPIs """ benchmarking_kpi_choice = prompt(menu_options.benchmarking_kpi, style=blue) sid = benchmarking_kpi_choice['sid'] percentile = benchmarking_kpi_choice['percentile'] kpi_selected = benchmarking_kpi_choice['kpi_selected'] # Display metrics for user selection benchmarking.get_selected_metrics(kpi_selected, sid, percentile, preloaded_matrix, preloaded_KPIs) # Display menu while True: choice_after = questionary.select( "---Run Benchmarking---", choices=[ 'Run benchmarking for another SID', 'Go back to main menu', 'Exit' ], style=blue).ask() if choice_after == 'Run benchmarking for another SID': get_kpi(preloaded_matrix, preloaded_KPIs) elif choice_after == 'Go back to main menu': load_main_menu() elif choice_after == 'Exit': sys.exit()
def export_menu(): """ Second level menu with the purpose to catch all functionality related to exporting the data to a target. """ export_menu_answers = questionary.prompt(export_menu_questions) choice_export_menu = export_menu_answers.get("export_menu_target") choice_pretty_print_sort = export_menu_answers.get("export_menu_prettyprint_1") choice_pretty_print_indent = export_menu_answers.get("export_menu_prettyprint_2") if not choice_pretty_print_indent: choice_pretty_print_indent = None else: choice_pretty_print_indent = int(choice_pretty_print_indent) if choice_export_menu == "String": print(os_signatures.exportsignatures(ExportTypes.STRING, sort_keys=choice_pretty_print_sort, indent=choice_pretty_print_indent)) elif choice_export_menu == "File": input_export_menu_2 = export_menu_questions2.ask() if input_export_menu_2 == "": print("Target path for the file was not entered correctly. Returning to main menu.") return os_signatures.exportsignatures(ExportTypes.FILE, input_export_menu_2, choice_pretty_print_sort, choice_pretty_print_indent) elif choice_export_menu == "Go back": return else: print("Unknown option selected. Returning to the main menu.") return
def display_open_folder(folder_path: str): args = get_args() if args.suppress: return answer = prompt([ { 'type': 'confirm', 'name': 'exit', 'message': 'Open the output folder?', 'default': True, }, ]) if not answer['exit']: return if Icons.isWindows: import subprocess subprocess.Popen('explorer /select,"' + folder_path + '"') else: import pathlib import webbrowser url = pathlib.Path(folder_path).as_uri() webbrowser.open_new(url)
def ask_dictstyle(**kwargs): questions = [{ "type": "checkbox", "qmark": "😃", "message": "Select toppings", "name": "toppings", "choices": [ { "name": "foo", "checked": True }, Separator(), { "name": "bar", "disabled": "nope" }, "bazz", Separator("--END--"), ], }] return prompt(questions, style=custom_style_dope, **kwargs)
def _ask_for_credentials(): """ Prompt for key id and secret keys. Returns: str, str: Kei ID, Secret Key """ credentials = questionary.prompt([{ "type": "text", "name": "key_id", "message": "Key:", "qmark": ">", "validate": lambda value: bool(re.fullmatch(KEY_ID, value)) or "Invalid Key" }, { "type": "password", "name": "secret_key", "message": "Secret:", "qmark": ">", "validate": lambda value: bool(re.fullmatch(SECRET_KEY, value)) or "Invalid Secret", }]) if not credentials: return return list(credentials.values())
def get_output_path(self): '''Returns a valid output path where the files are stored''' args = get_args() output_path = args.output_path if args.suppress: if not output_path: output_path = self.app.output_path # end if if not output_path: output_path = os.path.join('Lightnovels', 'Unknown Novel') # end if # end if if not output_path: answer = prompt([ { 'type': 'input', 'name': 'output', 'message': 'Enter output directory:', 'default': os.path.abspath(self.app.output_path), }, ]) output_path = answer['output'] # end if output_path = os.path.abspath(output_path) if os.path.exists(output_path): if self.force_replace_old(): shutil.rmtree(output_path, ignore_errors=True) # end if # end if os.makedirs(output_path, exist_ok=True) return output_path
def get_output_formats(self): '''Returns a dictionary of output formats.''' args = get_args() formats = args.output_formats if not (formats or args.suppress): answer = prompt([ { 'type': 'checkbox', 'name': 'formats', 'message': 'Which output formats to create?', 'choices': [{ 'name': x, 'checked': x in ['epub', 'json'] } for x in available_formats], }, ]) formats = answer['formats'] # end if if not formats or len(formats) == 0: formats = ['epub'] # default to epub if none selected # end if return {x: (x in formats) for x in available_formats}
def get_novel_url(self): '''Returns a novel page url or a query''' args = get_args() if args.query and len(args.query) > 1: return args.query # end if url = args.novel_page if url: if re.match(r'^https?://.+\..+$', url): return url else: raise LNException('Invalid URL of novel page') # end if # end if try: if args.suppress: raise LNException() # end if answer = prompt([ { 'type': 'input', 'name': 'novel', 'message': 'Enter novel page url or query novel:', 'validate': lambda a: True if a else 'Input should not be empty', }, ]) return answer['novel'].strip() except Exception: raise LNException('Novel page url or query was not given')
def get_crawlers_to_search(self) -> List[str]: '''Returns user choice to search the choosen sites for a novel''' links = self.app.crawler_links if not links: return [] # end if args = get_args() if args.suppress or 'sources' not in args: return links # end if if args.sources: links = [l for l in links if re.search(args.sources, l)] # end if if args.suppress or len(links) <= 1: return links # end if answer = prompt([{ 'type': 'checkbox', 'name': 'sites', 'message': 'Where to search?', 'choices': [{ 'name': x, 'checked': True } for x in sorted(links)], }]) selected = answer['sites'] return selected if len(selected) > 0 else links
def force_replace_old(self): args = get_args() if args.force: return True elif args.ignore: return False # end if if args.suppress: return False # end if # answer = prompt([ # { # 'type': 'confirm', # 'name': 'force', # 'message': 'Detected existing folder. Replace it?', # 'default': False, # }, # ]) # return answer['force'] answer = prompt([ { 'type': 'list', 'name': 'replace', 'message': 'What to do with existing folder?', 'choices': [ 'Remove old folder and start fresh', 'Download remaining chapters only', ], }, ]) return answer['replace'].startswith('Remove')
def main_menu(self): questions = [{ 'type': 'list', 'name': 'questions', 'message': 'What do you want to do?', 'choices': ['Encrypt', 'Open config', 'Quit'], 'filter': lambda val: val.lower(), }] answer = prompt(questions, style=custom_style_fancy) while answer['questions'] != 'quit': if answer['questions'] == 'encrypt': self.encrypt() elif answer['questions'] == 'open config': self.configure_public_key() answer = prompt(questions, style=custom_style_fancy) print('Bye Bye...')
def get_base_version() -> str: """ Show runtime options to the user. Returns: base_version (str): selected base version """ with loading_indicator("Loading base version list..."): versions = get_supported_base_versions() version_choices = [{ "value": base_version["version"], "name": base_version["label"] } for base_version in versions] questions = [ { "type": "list", "name": "base_version", "message": "Please select the bot runtime version:", "choices": version_choices, }, ] answers = prompt(questions) base_version = answers["base_version"] return base_version
def first_question_batch(): # ask for age and education # RETURNS: DICT questions = [{ 'type': 'select', 'name': 'age', 'message': '\nWhat is Your age?\n', 'choices': [ Separator(), '0 - 12', '12 - 18', '18 - 25', '25 - 45', '45+', Separator() ] }, { 'type': 'select', 'name': 'education', 'message': '\nWhat is Your education level?\n', 'choices': [Separator(), 'primary', 'high school', 'university', Separator()] }] return prompt(questions)
def ask_dictstyle(**kwargs): questions = [{ "type": "password", "message": "Enter your git password", "name": "password" }] return prompt(questions, style=custom_style_dope, **kwargs)
def interactive_kwargs_instanciation(self) -> Config: """ Instanciate dictionary of 'kwargs' arguments from an interactive prompt :return: the 'kwargs' dictionary """ questions = [ x.get_pyinquirer_question() for x in self.get_hyperparameters() ] conditions = self.get_conditions() # applying conditions if any for condition in conditions: child = condition.get_child() parent = condition.get_parent() condition_type = condition.get_type() values = condition.get_values() question = List([x for x in questions if x.get('name') == child])\ .head_option()\ .get_or_else(None) if question is not None and condition_type == 'IN': question['name'] = parent # Need to keep the double lambda because of python scope and closure stuff pb question['when'] = (lambda parent_key, values_value: lambda x: x.get(parent_key) in values_value)(parent, values) # Put the question with a 'when' value at the end questions = sorted(questions, key=lambda q: str(q.get('when') is not None)) # In case of time series forecast, add horizon and discount if self.category == AlgorithmConfigurationCategory.TIME_SERIES_FORECAST: questions.append({ 'type': 'input', 'name': 'forecasting_horizon_steps', 'message': f'forecasting_horizon_steps must be at least 1', 'default': str(1), 'validate': IntegerValidator, 'filter': int }) questions.append({ 'type': 'input', 'name': 'forecasting_discount', 'message': f'forecasting_discount must be between 0.0 (excluded) and 1.1 (included)', 'default': str(1.0), 'validate': FloatValidator, 'filter': float }) # Prompting for answers answers = questionary.prompt(questions) config = self.instance_config() for k, v in answers.items(): config.add_kwargs(k, v) return config
def resume_session(): args = get_args() output_path = args.resume or C.DEFAULT_OUTPUT_PATH resumable_meta_data = [] for meta_file in Path(output_path).glob('**/' + C.META_FILE_NAME): with open(meta_file, 'r', encoding="utf-8") as file: data = json.load(file) if 'session' in data and not data['session']['completed']: resumable_meta_data.append(data) # end if # end with # end for metadata = None if len(resumable_meta_data) == 1: metadata = resumable_meta_data[0] elif len(resumable_meta_data) > 1: answer = prompt([{ 'type': 'list', 'name': 'resume', 'message': 'Which one do you want to resume?', 'choices': display.format_resume_choices(resumable_meta_data), }]) index = int(answer['resume'].split('.')[0]) metadata = resumable_meta_data[index - 1] # end if if not metadata: print('No unfinished download to resume\n') display.app_complete() return # end if app = load_session_from_metadata(metadata) assert isinstance(app.crawler, Crawler) print('Resuming', app.crawler.novel_title) print('Output path:', app.output_path) app.initialize() app.crawler.initialize() if app.can_do('login') and app.login_data: logger.debug('Login with %s', app.login_data) app.crawler.login(*list(app.login_data)) # end if app.start_download() app.bind_books() app.compress_books() app.destroy() display.app_complete() display_open_folder(app.output_path)
def ask_dictstyle(**kwargs): questions = [{ 'type': 'text', 'name': 'phone', 'message': "What's your phone number", 'validate': PhoneNumberValidator }] return prompt(questions, style=custom_style_dope, **kwargs)
def get_bot_uuid() -> str: """ Show bot options to the user, returns the selected bot ID. Returns: bot_uuid (str): ID of the selected bot. """ NEXT_PAGE = "__NEXT_PAGE__" PREV_PAGE = "__PREV_PAGE__" NONE = "__NONE__" META_RESPONSES = [NEXT_PAGE, PREV_PAGE, NONE] bot_uuid = NONE page = 0 while bot_uuid in META_RESPONSES: if bot_uuid == NEXT_PAGE: page += 1 if bot_uuid == PREV_PAGE: page -= 1 with loading_indicator("Loading bot list..."): bots = get_bots(page) bot_choices = list(map(get_bot_choice, bots.content)) page_count = math.ceil(bots.totalElements / bots.size) if page < page_count - 1: bot_choices.append({"name": "> Next page...", "value": NEXT_PAGE}) if page > 0: bot_choices.append({ "name": "> Previous page...", "value": PREV_PAGE }) questions = [ { "type": "list", "name": "bot_id", "message": "Please select the bot you would like to implement:", "choices": [ Choice(title=bot["name"], value=bot["value"]) if (bot["value"] == NEXT_PAGE or bot["value"] == PREV_PAGE) else Choice( title=str(bot["name"] + " (" + bot["value"] + ")"), value=bot["value"], ) for bot in bot_choices ], }, ] answers = prompt(questions) bot_uuid = answers["bot_id"] return bot_uuid
def ask_dictstyle(**kwargs): questions = [{ "type": "text", "name": "phone", "message": "What's your phone number", "validate": PhoneNumberValidator, }] return prompt(questions, style=custom_style_dope, **kwargs)
def calculate_matrix(extracted_data): """Calculates matrix based on user input weights and extracted data. Invokes benchmarking_calc.create_similarity_score_matrix() to create similarity matrix. Invokes benchmarking_calc.create_customer_KPI_database() to create KPI database. Lastly, display menu to user after calculation. Args: extracted_data (pandas df obj): Pandas dataframe containing data extracted from 71lbs database """ # Get user input for metric weights metric_weights = { 'weight_vs': 1 / 6, 'weight_vpz': 1 / 6, 'weight_vpm': 1 / 6, 'weight_ws': 1 / 6, 'weight_wpz': 1 / 6, 'weight_wpm': 1 / 6 } EVEN = questionary.confirm( "Create a new similarity matrix with even metric weights?").ask() if not EVEN: print( "\nPlease enter weight for each metric. Please make sure that sum of all 6 weights is approximately = 1" ) metric_weights = prompt(menu_options.benchmarking_metric_weights, style=blue) metric_weights_sum = sum(metric_weights.values()) print("\nRecalibrating weights...") for weight in metric_weights: metric_weights[ weight] = metric_weights[weight] / metric_weights_sum print("\nWeights:", metric_weights, "\n") print("\nCreating similarity score matrix...") model_id = utilities.get_timestamp() benchmarking_calc.create_similarity_score_matrix( extract_data=extracted_data, input_weights=metric_weights, model_id=model_id) benchmarking_calc.create_customer_KPI_database(arg_df=extracted_data, model_id=model_id) while True: choice_after = questionary.select( "---Calculate similarity matrix---", choices=[ 'Calculate another similarity matrix', 'Go back to main menu', 'Exit' ], style=blue).ask() if choice_after == 'Calculate another similarity matrix': calculate_matrix(extracted_data) elif choice_after == 'Go back to main menu': load_main_menu() elif choice_after == 'Exit': sys.exit()
def ask_dictstyle(**kwargs): questions = [ { 'type': 'password', 'message': 'Enter your git password', 'name': 'password' } ] return prompt(questions, style=custom_style_dope, **kwargs)