docs: def make_choice_validator(
          choices, default_key=None, normalizer=None):
      """
      Returns a callable that accepts the choices provided.
  
      Choices should be provided as a list of 2-tuples, where the first
      element is a string that should match user input (the key); the
      second being the value associated with the key.
  
      The callable by default will match, upon complete match the first
      value associated with the result will be returned.  Partial matches
      are supported.
  
      If a default is provided, that value will be returned if the user
      provided input is empty, i.e. the value that is mapped to the empty
      string.
  
      Finally, a normalizer function can be passed.  This normalizes all
      keys and validation value.
      """
  
      def normalize_all(_choices):
          # normalize all the keys for easier comparison
          if normalizer:
              _choices = [(normalizer(key), value) for key, value in choices]
          return _choices
  
      choices = normalize_all(choices)
  
      def choice_validator(value):
          if normalizer:
              value = normalizer(value)
          if not value and default_key:
              value = choices[default_key][0]
          results = []
          for choice, mapped in choices:
              if value == choice:
                  return mapped
              if choice.startswith(value):
                  results.append((choice, mapped))
          if len(results) == 1:
              return results[0][1]
          elif not results:
              raise ValueError('Invalid choice.')
          else:
              raise ValueError(
                  'Choice ambiguous between (%s)' % ', '.join(
                      k for k, v in normalize_all(results))
              )
  
      return choice_validator