docs: def user_input(prompt="", choices=None, default=None, choices_str="",
                 required=False):
      """
      Python2/3-compatible input method handling choices and default value.
      
      :param prompt:   prompt message
      :param choices:  list of possible choices or lambda function
      :param default:  default value
      :param required: make non-null user input mandatory
      :return:         handled user input
      """
      if type(choices) in [list, tuple, set]:
          choices = list(map(str, choices))
          choices_str = " {%s}" % (choices_str or \
                                   '|'.join(list(map(str, choices))))
          # consider choices of the form ["(Y)es", "(N)o"] ;
          #  in this case, we want the choices to be ['y', 'n'] for the sake of
          #  simplicity for the user
          m = list(map(lambda x: CHOICE_REGEX.match(x), choices))
          choices = [x.group(1).lower() if x else c for x, c in zip(m, choices)]
          # this way, if using ["Yes", "No"], choices will remain so
          _check = lambda v: v in choices
      elif is_lambda(choices):
          _check = choices
      else:
          _check = lambda v: True
      prompt += "{}{}\n".format(choices_str, [" [{}]".format(default), ""]\
                                             [default is None and required])
      user_input, first = None, True
      while not user_input:
          user_input = std_input(["", prompt][first] + " >> ")
          first = False
          if type(choices) in [list, tuple, set]:
              choices = list(map(lambda x: x.lower(), choices))
              user_input = user_input.lower()
          if user_input == "" and default is not None and _check(default):
              return str(default)
          if user_input != "" and _check(user_input):
              return user_input
          if not required:
              return