261 lines
8.7 KiB
Python
261 lines
8.7 KiB
Python
# -*- coding:utf-8 -*-
|
|
#############################################################################
|
|
# Copyright (c) 2023 Huawei Technologies Co.,Ltd.
|
|
#
|
|
# openGauss is licensed under Mulan PSL v2.
|
|
# You can use this software according to the terms
|
|
# and conditions of the Mulan PSL v2.
|
|
# You may obtain a copy of Mulan PSL v2 at:
|
|
#
|
|
# http://license.coscl.org.cn/MulanPSL2
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OF ANY KIND,
|
|
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
# See the Mulan PSL v2 for more details.
|
|
# ----------------------------------------------------------------------------
|
|
# Description : Provides a series of methods for dialogue, question and input.
|
|
#############################################################################
|
|
|
|
import os
|
|
from gspylib.common.GaussLog import GaussLog
|
|
|
|
|
|
class DialogError(Exception):
|
|
def __init__(self, complete_question, msg):
|
|
self.complete_question = complete_question
|
|
self.msg = msg
|
|
|
|
def __str__(self):
|
|
return self.msg
|
|
|
|
|
|
class DialogUtil(object):
|
|
"""
|
|
Provides a set of interfaces for dialogue and interactive questioning.
|
|
|
|
Each interface has its own label.
|
|
|
|
If it is a question, you can select whether it is required, and the
|
|
required question will be marked with an '*'.
|
|
"""
|
|
@staticmethod
|
|
def Message(message):
|
|
"""
|
|
:param message: message
|
|
:return: NA
|
|
"""
|
|
complete_message = f'[ Message ] {message}\n'
|
|
GaussLog.printMessage(complete_message)
|
|
|
|
@staticmethod
|
|
def yesOrNot(question, required=True, max_retry=99999):
|
|
"""
|
|
raise a question, and want a yes or not.
|
|
|
|
example:
|
|
*[ yesOrNot ] Am I handsome? (y/n)? y
|
|
|
|
:param question: question
|
|
:param required: must input something. if not, we can return None
|
|
:param max_retry: max retry times
|
|
:return: True, False, None
|
|
"""
|
|
question_tag = '{0}[ yesOrNot ]'.format('*' if required else '')
|
|
complete_question = '{0} {1}(y/n)? '.format(
|
|
question_tag, question
|
|
)
|
|
answer = input(complete_question)
|
|
while True:
|
|
if not required and answer == '':
|
|
return
|
|
|
|
if answer.lower() in ('y', 'n'):
|
|
return answer.lower() == 'y'
|
|
|
|
max_retry -= 1
|
|
if max_retry < 0:
|
|
raise DialogError(complete_question, 'Too many failed retry.')
|
|
|
|
answer = input('Please input y or n: ')
|
|
|
|
@staticmethod
|
|
def singleAnswerQuestion(question, options, required=True, max_retry=99999):
|
|
"""
|
|
raise a question, and want an option.
|
|
|
|
example:
|
|
*[ Single Answer Question ] What would you like for dinner?
|
|
A. carrot
|
|
B. rice
|
|
C. chicken
|
|
Single answer: a
|
|
|
|
:param question: question
|
|
:param options: options to choose.
|
|
:param required: must input something. if not, we can return None
|
|
:param max_retry: max retry times
|
|
:return: the index of option which user choose, or None
|
|
"""
|
|
assert len(options) <= 26
|
|
question_tag = '{0}[ Single Answer Question ]'.format('*' if required else '')
|
|
code_id = [chr(c) for c in range(ord('A'), ord('A') + len(options))]
|
|
question_options = ''
|
|
for i, option in enumerate(options):
|
|
question_options += ' {0}. {1}\n'.format(code_id[i], option)
|
|
|
|
complete_question = "{0} {1}\n{2}Single answer: ".format(
|
|
question_tag, question, question_options)
|
|
answer = input(complete_question)
|
|
while True:
|
|
if not required and answer == '':
|
|
return
|
|
if answer.upper() in code_id:
|
|
return code_id.index(answer.upper())
|
|
|
|
max_retry -= 1
|
|
if max_retry < 0:
|
|
raise DialogError(complete_question, 'Too many failed retry.')
|
|
|
|
answer = input('Please input A~{}:'.format(code_id[-1]))
|
|
|
|
@staticmethod
|
|
def multipleAnswerQuestion(question, options, required=True, max_retry=99999):
|
|
"""
|
|
raise a question, and want an option.
|
|
|
|
example:
|
|
*[ Multiple Answer Question ] What would you like for dinner?
|
|
A. carrot
|
|
B. rice
|
|
C. chicken
|
|
Multiple answer: ac
|
|
|
|
:param question: question
|
|
:param options: options to choose
|
|
:param required: must input something. if not, we can return None
|
|
:param max_retry: max retry times
|
|
:return: the index list of option which user choose, or []
|
|
"""
|
|
assert len(options) <= 26
|
|
code_id = [chr(c) for c in range(ord('A'), ord('A') + len(options))]
|
|
question_options = ''
|
|
for i, option in enumerate(options):
|
|
question_options += ' {0}. {1} \n'.format(code_id[i], option)
|
|
complete_question = "{0}[ Multiple Answer Question ] {1}\n{2}Multiple answer: ".format(
|
|
'*' if required else '', question, question_options)
|
|
|
|
def _analyse_answer(_answer):
|
|
_chosen = set()
|
|
for c in _answer:
|
|
if c == ' ' or c == '\t' or c == ',':
|
|
continue
|
|
if c.upper() not in code_id:
|
|
GaussLog.printMessage(f'Invalid select code: {c}.', end='')
|
|
return
|
|
_chosen.add(ord(c.upper()) - ord('A'))
|
|
_res = list(_chosen)
|
|
_res.sort()
|
|
if required and len(_res) == 0:
|
|
GaussLog.printMessage('Please make at least one choice.')
|
|
return
|
|
|
|
return _res
|
|
|
|
answer = input(complete_question)
|
|
while True:
|
|
res = _analyse_answer(answer)
|
|
if res is not None:
|
|
return res
|
|
|
|
max_retry -= 1
|
|
if max_retry < 0:
|
|
raise DialogError(complete_question, 'Too many failed retry.')
|
|
|
|
answer = input('Please input A~{}:'.format(code_id[-1]))
|
|
|
|
@staticmethod
|
|
def askANumber(question, check_func=None, required=True, max_retry=99999):
|
|
"""
|
|
ask a number.
|
|
|
|
for example:
|
|
*[ Input number ] How old are you?
|
|
Please answer: 1000
|
|
|
|
:param question: question
|
|
:param check_func: Verify that the number entered is legitimate. Otherwise, return an error msg
|
|
:param required: must input something. if not, we can return None
|
|
:param max_retry: max retry times
|
|
:return: the number, or None
|
|
"""
|
|
complete_question = '{0}[ Input number ] {1}\nPlease answer: '.format(
|
|
'*' if required else '', question
|
|
)
|
|
answer = input(complete_question)
|
|
while True:
|
|
retry_msg = None
|
|
if not required and answer == '':
|
|
return
|
|
|
|
if not answer.isdigit():
|
|
retry_msg = 'Invalid integer, please again: '
|
|
elif check_func is not None:
|
|
errmsg = check_func(int(answer))
|
|
if errmsg is None:
|
|
return int(answer)
|
|
retry_msg = f'{errmsg}. please again: '
|
|
else:
|
|
return int(answer)
|
|
|
|
max_retry -= 1
|
|
if max_retry < 0:
|
|
raise DialogError(complete_question, 'Too many failed retry.')
|
|
|
|
answer = input(retry_msg)
|
|
|
|
@staticmethod
|
|
def askAPath(question, check_access=None, required=True, max_retry=99999):
|
|
"""
|
|
ask a path.
|
|
|
|
for example:
|
|
*[ Input path ] Where is the file?
|
|
Please input the path: /home/user/abc
|
|
|
|
:param question: question
|
|
:param check_access: check the path is access.
|
|
:param required: must input something. if not, we can return None
|
|
:param max_retry: max retry times
|
|
:return: the path, or None
|
|
"""
|
|
complete_question = '{0}[ Input path ] {1} \nPlease input the path: '.format(
|
|
'*' if required else '', question
|
|
)
|
|
answer = input(complete_question)
|
|
while True:
|
|
retry_msg = None
|
|
if not required and answer == '':
|
|
return
|
|
|
|
if check_access and not os.access(answer, os.F_OK):
|
|
retry_msg = 'Could not access path, please again: '
|
|
else:
|
|
return answer
|
|
|
|
max_retry -= 1
|
|
if max_retry < 0:
|
|
raise DialogError(complete_question, 'Too many failed retry.')
|
|
|
|
answer = input(retry_msg)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
res = DialogUtil.multipleAnswerQuestion(
|
|
'test question',
|
|
['x', 'xx', 'xxx']
|
|
)
|
|
GaussLog.printMessage(res)
|
|
|