def prompt_array(msg, item_type, help_string=None): verify_is_a_tty() while True: value = _input(f'{msg}\nPlease enter one or more space-seperated {item_type}s: ') if value == '?' and help_string is not None: print(help_string) continue ans = [] values = value.split() for v in values: try: if item_type == 'string': ans.append(value) elif item_type == 'boolean': ans.append(value.lower() == 'true') elif item_type == 'integer': v_int = int(value) ans.append(v_int) elif item_type == 'number': v_float = float(value) ans.append(v_float) else: logger.warning("Unrecognized type '%s'. Interpretting as string.", item_type) ans.append(value) except ValueError: logger.warning('%s is not a valid %s', v, item_type) return ans
def verify_is_a_tty_or_raise_error(error_msg=None): """ Verifies interactive environment raises NoTTYException with the error_msg string if the environment is non-interative """ try: verify_is_a_tty() except NoTTYException: raise NoTTYException(error_msg)
def try_verify_is_a_tty(): """ Return True for TTY and False for non-TTY terminals """ try: verify_is_a_tty() return True except NoTTYException: return False
def prompt_number(msg, help_string=None): verify_is_a_tty() while True: value = _input(msg) if value == '?' and help_string is not None: print(help_string) continue try: return float(value) except ValueError: logger.warning('%s is not a valid number', value)
def prompt_user_friendly_choice_list(msg, a_list, default=1, help_string=None): """Prompt user to select from a list of possible choices. :param msg:A message displayed to the user before the choice list :type msg: str :param a_list:The list of choices (list of strings or list of dicts with 'name' & 'desc') "type a_list: list :param default:The default option that should be chosen if user doesn't enter a choice :type default: int :returns: The list index of the item chosen. """ verify_is_a_tty() options = '\n'.join([ ' [{}] {}{}'.format( i + 1, x['name'] if isinstance(x, dict) and 'name' in x else x, ' - ' + x['desc'] if isinstance(x, dict) and 'desc' in x else '') for i, x in enumerate(a_list) ]) allowed_vals = list(range(1, len(a_list) + 1)) linesToDelete = len(a_list) + 1 while True: val = _input( '{}\n{}\nPlease enter a choice [Default choice({})]: '.format( msg, options, default)) if val == '?' and help_string is not None: for x in range(0, linesToDelete): delete_last_line() print('Please enter a choice [Default choice({})]: {}'.format( default, '?')) print(help_string) continue if not val: val = '{}'.format(default) try: ans = int(val) if ans in allowed_vals: for x in range(0, linesToDelete): delete_last_line() print('Please enter a choice [Default choice({})]: {}'.format( default, a_list[ans - 1])) # array index is 0-based, user input is 1-based return ans - 1 raise ValueError except ValueError: for x in range(0, linesToDelete): delete_last_line() print('Please enter a choice [Default choice({})]: {}'.format( default, val)) logger.warning('Valid values are %s', allowed_vals)
def prompt_multi_choice_list(msg, a_list, default=1, help_string=None): """Prompt user to select from a list of possible choices. :param msg:A message displayed to the user before the choice list :type msg: str :param a_list:The list of choices (list of strings or list of dicts with 'name' & 'desc') "type a_list: list :param default:The default option that should be chosen if user doesn't enter a choice :type default: int :returns: A list of indexs of the items chosen. """ verify_is_a_tty() options = '\n'.join([f" [{i + 1}] " f"{x['name'] if isinstance(x, dict) and 'name' in x else x}" f"{' - ' + x['desc'] if isinstance(x, dict) and 'desc' in x else ''}" for i, x in enumerate(a_list)]) allowed_vals = list(range(1, len(a_list) + 1)) while True: val = _input(f'{msg}\n{options}\nPlease enter one or more space-seperated choices [Default choice({default})]: ') if val == '?' and help_string is not None: print(help_string) continue if not val: val = f'{default}' try: anss = [] vals = val.split() for v in vals: ans = int(v) if ans in allowed_vals: # array index is 0-based, user input is 1-based anss.append(ans - 1) else: raise ValueError return anss except ValueError: logger.warning('Valid values are %s', allowed_vals)
import subprocess import platform from azure.cli.core.azclierror import UnclassifiedUserFault # pylint: disable=ungrouped-imports logger.warning( "New Azure CLI version available. Running 'az upgrade' to update automatically." ) update_all = az_cli.config.getboolean( 'auto-upgrade', 'all', True) prompt = az_cli.config.getboolean('auto-upgrade', 'prompt', True) cmd = ['az', 'upgrade', '--all', str(update_all)] if prompt: from knack.prompting import verify_is_a_tty, NoTTYException # pylint: disable=ungrouped-imports az_upgrade_run = True try: verify_is_a_tty() except NoTTYException: az_upgrade_run = False err_msg = "Unable to prompt for auto upgrade as no tty available. " \ "Run 'az config set auto-upgrade.prompt=no' to allow auto upgrade with no prompt." logger.warning(err_msg) telemetry.set_exception( UnclassifiedUserFault(err_msg), fault_type='auto-upgrade-failed') else: upgrade_exit_code = subprocess.call( cmd, shell=platform.system() == 'Windows') else: import os devnull = open(os.devnull, 'w') cmd.append('-y')
def test_no_tty_should_raise_exception(self, _): with self.assertRaises(NoTTYException): verify_is_a_tty()
def test_tty_no_exception(self, _): verify_is_a_tty()
def verify_is_a_tty_or_raise_error(error_msg=None): try: verify_is_a_tty() except NoTTYException: raise NoTTYException(error_msg)