def notification(self, message: str, pause: bool = True, wrap: bool = True, force_interactive: bool = False, decorate: bool = True) -> None: """Displays a notification and waits for user acceptance. :param str message: Message to display :param bool pause: Whether or not the program should pause for the user's confirmation :param bool wrap: Whether or not the application should wrap text :param bool force_interactive: True if it's safe to prompt the user because it won't cause any workflow regressions :param bool decorate: Whether to surround the message with a decorated frame """ if wrap: message = util.wrap_lines(message) logger.debug("Notifying user: %s", message) self.outfile.write( (("{line}{frame}{line}" if decorate else "") + "{msg}{line}" + ("{frame}{line}" if decorate else "")).format(line=os.linesep, frame=SIDE_FRAME, msg=message)) self.outfile.flush() if pause: if self._can_interact(force_interactive): util.input_with_timeout("Press Enter to Continue") else: logger.debug("Not pausing for user confirmation")
def notification( self, message: str, pause: bool = False, wrap: bool = True, # pylint: disable=unused-argument decorate: bool = True, **unused_kwargs: Any) -> None: """Displays a notification without waiting for user acceptance. :param str message: Message to display to stdout :param bool pause: The NoninteractiveDisplay waits for no keyboard :param bool wrap: Whether or not the application should wrap text :param bool decorate: Whether to apply a decorated frame to the message """ if wrap: message = util.wrap_lines(message) logger.debug("Notifying user: %s", message) self.outfile.write( (("{line}{frame}{line}" if decorate else "") + "{msg}{line}" + ("{frame}{line}" if decorate else "")).format(line=os.linesep, frame=SIDE_FRAME, msg=message)) self.outfile.flush()
def _print_menu(self, message: str, choices: Union[List[Tuple[str, str]], List[str]]) -> None: """Print a menu on the screen. :param str message: title of menu :param choices: Menu lines :type choices: list of tuples (tag, item) or list of descriptions (tags will be enumerated) """ # Can take either tuples or single items in choices list if choices and isinstance(choices[0], tuple): choices = [f"{c[0]} - {c[1]}" for c in choices] # Write out the message to the user self.outfile.write(f"{os.linesep}{message}{os.linesep}") self.outfile.write(SIDE_FRAME + os.linesep) # Write out the menu choices for i, desc in enumerate(choices, 1): msg = f"{i}: {desc}" self.outfile.write(util.wrap_lines(msg)) # Keep this outside of the textwrap self.outfile.write(os.linesep) self.outfile.write(SIDE_FRAME + os.linesep) self.outfile.flush()
def input(self, message: str, default: Optional[str] = None, cli_flag: Optional[str] = None, force_interactive: bool = False, **unused_kwargs: Any) -> Tuple[str, str]: """Accept input from the user. :param str message: message to display to the user :param default: default value to return (if one exists) :param str cli_flag: option used to set this value with the CLI :param bool force_interactive: True if it's safe to prompt the user because it won't cause any workflow regressions :returns: tuple of (`code`, `input`) where `code` - str display exit code `input` - str of the user's input :rtype: tuple """ return_default = self._return_default(message, default, cli_flag, force_interactive) if return_default is not None: return OK, return_default # Trailing space must be added outside of util.wrap_lines to # be preserved message = util.wrap_lines("%s (Enter 'c' to cancel):" % message) + " " ans = util.input_with_timeout(message) if ans in ("c", "C"): return CANCEL, "-1" return OK, ans
def _print_menu(self, message, choices): """Print a menu on the screen. :param str message: title of menu :param choices: Menu lines :type choices: list of tuples (tag, item) or list of descriptions (tags will be enumerated) """ # Can take either tuples or single items in choices list if choices and isinstance(choices[0], tuple): choices = ["%s - %s" % (c[0], c[1]) for c in choices] # Write out the message to the user self.outfile.write( "{new}{msg}{new}".format(new=os.linesep, msg=message)) self.outfile.write(SIDE_FRAME + os.linesep) # Write out the menu choices for i, desc in enumerate(choices, 1): msg = "{num}: {desc}".format(num=i, desc=desc) self.outfile.write(util.wrap_lines(msg)) # Keep this outside of the textwrap self.outfile.write(os.linesep) self.outfile.write(SIDE_FRAME + os.linesep) self.outfile.flush()
def test_wrap_lines(self): from certbot._internal.display.util import wrap_lines msg = ( "This is just a weak test{0}" "This function is only meant to be for easy viewing{0}" "Test a really really really really really really really really " "really really really really long line...".format('\n')) text = wrap_lines(msg) self.assertEqual(text.count('\n'), 3)
def yesno(self, message: str, yes_label: str = "Yes", no_label: str = "No", default: Optional[bool] = None, cli_flag: Optional[str] = None, force_interactive: bool = False, **unused_kwargs: Any) -> bool: """Query the user with a yes/no question. Yes and No label must begin with different letters, and must contain at least one letter each. :param str message: question for the user :param str yes_label: Label of the "Yes" parameter :param str no_label: Label of the "No" parameter :param default: default value to return (if one exists) :param str cli_flag: option used to set this value with the CLI :param bool force_interactive: True if it's safe to prompt the user because it won't cause any workflow regressions :returns: True for "Yes", False for "No" :rtype: bool """ return_default = self._return_default(message, default, cli_flag, force_interactive) if return_default is not None: return return_default message = util.wrap_lines(message) self.outfile.write("{0}{frame}{msg}{0}{frame}".format( os.linesep, frame=SIDE_FRAME + os.linesep, msg=message)) self.outfile.flush() while True: ans = util.input_with_timeout("{yes}/{no}: ".format( yes=util.parens_around_char(yes_label), no=util.parens_around_char(no_label))) # Couldn't get pylint indentation right with elif # elif doesn't matter in this situation if (ans.startswith(yes_label[0].lower()) or ans.startswith(yes_label[0].upper())): return True if (ans.startswith(no_label[0].lower()) or ans.startswith(no_label[0].upper())): return False