code: def question(
      self,
      text,
      title=None,
      choices=None,
      default=None,
      hidden=False,
      repeat=None,
  ):
      # Do initial checks first
      if default and choices and default not in choices:
          raise ValueError(
              "default value %r is not among choices: %s"
              % (_get_value(default, hidden), choices)
          )
  
      msg = ""
      if title and not (
          title == self._prev_title
          and time.time() - self._prev_title_time < 5
      ):
          # might not actually get displayed if all in/out redirected
          # self.out.write(title + "\n")
          # so merge into msg for getpass
          msg += title + os.linesep
  
      def mark_default(x):
          return (
              "[%s]" % x if default is not None and x == default else x
          )
  
      if choices is not None:
          msg += "%s (choices: %s)" % (
              text,
              ", ".join(map(mark_default, choices)),
          )
      elif default is not None:
          msg += "{} [{}]".format(text, default)
      else:
          msg += text
      # Like this:
      # Anaconda format:
      #
      # Question? [choice1|choice2]
      # [default] >>> yes
      attempt = 0
      while True:
          attempt += 1
          if attempt >= 100:
              raise RuntimeError(
                  "This is 100th attempt. Something really went wrong"
              )
  
          response = self.input("{}: ".format(msg), hidden=hidden)
          # TODO: dedicated option?  got annoyed by this one
          # multiple times already, typically we are not defining
          # new credentials where repetition would be needed.
          if hidden and repeat is None:
              repeat = hidden and choices is None
  
          if repeat:
              response_r = self.input(
                  "{} (repeat): ".format(msg), hidden=hidden
              )
              if response != response_r:
                  self.error("input mismatch, please start over")
                  continue
  
          if response and "\x03" in response:
              # Ctrl-C is part of the response -> clearly we should not pretend it's all good
              raise KeyboardInterrupt
  
          if not response and default:
              response = default
              break
  
          if choices and response not in choices:
              self.error(
                  "%r is not among choices: %s. Repeat your answer"
                  % (_get_value(response, hidden), choices)
              )
              continue
          break
  
      self._prev_title = title
      self._prev_title_time = time.time()
  
      return response
  
imports: from logging import getLogger
  import os
  import sys
  import time
  import getpass
  from collections import deque
  from copy import copy
  from ..utils import auto_repr
  from ..utils import on_windows
  from .base import InteractiveUI
  from datalad.support.exceptions import CapturedException
label_desc: Use image node_id 3 for calling the DialogUI obj's underlying member method code with example usage: obj.question(text, title, choices, default, hidden, repeat) and returns: response, unknown