docs: def InterpolateKbAttributes(pattern, knowledge_base, ignore_errors=False):
    """Interpolate all knowledgebase attributes in pattern.
  
    Args:
      pattern: A string with potential interpolation markers. For example:
        "/home/%%users.username%%/Downloads/"
      knowledge_base: The knowledge_base to interpolate parameters from.
      ignore_errors: Set this to true to log errors instead of raising.
  
    Raises:
      KnowledgeBaseInterpolationError: If there are any interpolation problems
        and the `ignore_errors` flag is not set.
  
    Yields:
      All unique strings generated by expanding the pattern.
    """
    # TODO(hanuszczak): Control flow feels a bit awkward here because of error
    # handling that tries not to break any functionality. With the new utilities
    # it should be possible to improve the code, changing the behaviour to a more
    # sane one.
    missing_attr_names = set()
  
    interpolator = interpolation.Interpolator(pattern)
  
    for vid in interpolator.Vars():
      attr_name = str(vid).lower()
  
      value = getattr(knowledge_base, attr_name, None)
      if not value:
        missing_attr_names.add(attr_name)
        continue
  
      interpolator.BindVar(attr_name, value)
  
    for scope_id in interpolator.Scopes():
      scope_name = str(scope_id).lower()
  
      kb_structs = getattr(knowledge_base, scope_name, None)
      if not kb_structs:
        missing_attr_names.add(scope_name)
        continue
  
      bound = False
  
      for kb_struct in kb_structs:
        bindings = {}
  
        for var_id in interpolator.ScopeVars(scope_id):
          attr_name = str(var_id).lower()
  
          value = getattr(kb_struct, attr_name, None)
          if value:
            bindings[var_id] = value
  
        if len(bindings) == len(interpolator.ScopeVars(scope_id)):
          interpolator.BindScope(scope_id, bindings)
          bound = True
  
      if not bound:
        missing_attr_names.add(scope_name)
  
    if missing_attr_names:
      message = "Some attributes could not be located in the knowledgebase: {}"
      message = message.format(", ".join(missing_attr_names))
      if not ignore_errors:
        raise KnowledgeBaseInterpolationError(message)
      else:
        logging.error(message)
        return
  
    for result in interpolator.Interpolate():
      yield result