code: def query_choice(msg, choices, default=None, descriptions=None, lower=True):
      
      choices = _choices = [str(c) for c in choices]
      if lower:
          _choices = [c.lower() for c in choices]
  
      if default is not None:
          if default not in choices:
              raise Exception("default must be one of the choices")
  
      hints = [(choice if choice != default else choice + "*") for choice in choices]
      if descriptions is not None:
          if len(descriptions) != len(choices):
              raise ValueError("length of descriptions must match length of choices")
          hints = ["{}({})".format(*tpl) for tpl in zip(hints, descriptions)]
      msg += " [{}] ".format(", ".join(hints))
  
      choice = None
      while choice not in _choices:
          if choice is not None:
              print("invalid choice: '{}'\n".format(choice))
          choice = six.moves.input(msg)
          if default is not None and choice == "":
              choice = default
          if lower:
              choice = choice.lower()
  
      return choice
docs: Interactively query a choice from the prompt until the input matches one of the *choices*. The
      prompt can be configured using *msg* and *descriptions*, which, if set, must have the same
      length as *choices*. When *default* is not *None* it must be one of the choices and is used when
      the input is empty. When *lower* is *True*, the input is compared to the choices in lower case.