You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
4.3 KiB
146 lines
4.3 KiB
# Copyright 2016 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""User input handlers."""
|
|
|
|
|
|
class InputError(Exception):
|
|
"""An error with a user provided input."""
|
|
|
|
|
|
class _InputHandler(object):
|
|
"""An input handler base class."""
|
|
|
|
def get_choices_supplements(self):
|
|
"""Returns a pair of supplement strings representing input choices.
|
|
|
|
@return: A pair consisting of a detailed representation of available
|
|
choices, and a corresponding concise descriptor of available
|
|
input choices with optional default.
|
|
"""
|
|
input_choices, default = self._get_input_choices_and_default()
|
|
if input_choices:
|
|
input_choices = '[%s]' % input_choices
|
|
if default is not None:
|
|
input_choices += ' (default: %s)' % default
|
|
|
|
return self._get_choices_details(), input_choices
|
|
|
|
|
|
def _get_input_choices_and_default(self):
|
|
"""Returns an input choices descriptor and a default (if any)."""
|
|
raise NotImplementedError
|
|
|
|
|
|
def _get_choices_details(self):
|
|
"""Returns a detailed description (string) of input choices."""
|
|
raise NotImplementedError
|
|
|
|
|
|
def process(self, input_str):
|
|
"""Returns the result of processing the user input.
|
|
|
|
@param input_str: The user input.
|
|
|
|
@return: The result of processing the input.
|
|
|
|
@raise InputError: Provided input is invalid.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
|
|
class PauseInputHandler(_InputHandler):
|
|
"""A quiet input handler that just returns on any input."""
|
|
|
|
# Interface overrides.
|
|
#
|
|
def _get_input_choices_and_default(self):
|
|
return None, None
|
|
|
|
|
|
def _get_choices_details(self):
|
|
return None
|
|
|
|
|
|
def process(self, input_str):
|
|
pass
|
|
|
|
|
|
class YesNoInputHandler(_InputHandler):
|
|
"A yes/no input handler with optional default."""
|
|
|
|
def __init__(self, default=None):
|
|
"""Initializes the input handler.
|
|
|
|
@param default: The Boolean value to return by default.
|
|
"""
|
|
self._default = default
|
|
self._input_choices = '%s/%s' % ('Y' if default is True else 'y',
|
|
'N' if default is False else 'n')
|
|
|
|
|
|
# Interface overrides.
|
|
#
|
|
def _get_input_choices_and_default(self):
|
|
# We highlight the default by uppercasing the corresponding choice
|
|
# directly, so no need to return a default separately.
|
|
return self._input_choices, None
|
|
|
|
|
|
def _get_choices_details(self):
|
|
return None
|
|
|
|
|
|
def process(self, input_str):
|
|
input_str = input_str.lower().strip()
|
|
if input_str == 'y':
|
|
return True
|
|
if input_str == 'n':
|
|
return False
|
|
if not input_str and self._default is not None:
|
|
return self._default
|
|
raise InputError
|
|
|
|
|
|
class MultipleChoiceInputHandler(_InputHandler):
|
|
"""A multiple choice input handler with optional default."""
|
|
|
|
def __init__(self, choices, default=None):
|
|
"""Initializes the input handler.
|
|
|
|
@param choices: An iterable of input choices.
|
|
@param default: Index of default choice (integer).
|
|
"""
|
|
max_idx = len(choices)
|
|
if not (default is None or default in range(1, max_idx + 1)):
|
|
raise ValueError('Default choice is not a valid index')
|
|
self._choices = choices
|
|
self._idx_range = '1-%d' % max_idx if max_idx > 1 else str(max_idx)
|
|
self._default = None if default is None else str(default)
|
|
|
|
|
|
# Interface overrides.
|
|
#
|
|
def _get_input_choices_and_default(self):
|
|
return self._idx_range, self._default
|
|
|
|
|
|
def _get_choices_details(self):
|
|
return '\n'.join(['%d) %s' % (idx, choice)
|
|
for idx, choice in enumerate(self._choices, 1)])
|
|
|
|
|
|
def process(self, input_str):
|
|
"""Returns the index (zero-based) and value of the chosen option."""
|
|
input_str = input_str or self._default
|
|
if input_str:
|
|
try:
|
|
input_idx = int(input_str) - 1
|
|
if input_idx in range(len(self._choices)):
|
|
return input_idx, self._choices[input_idx]
|
|
except ValueError:
|
|
pass
|
|
|
|
raise InputError
|