docs: def FanOut(self, obj, parent=None):
      """Expand values from various attribute types.
  
      Strings are returned as is.
      Dictionaries are returned with a key string, and an expanded set of values.
      Other iterables are expanded until they flatten out.
      Other items are returned in string format.
  
      Args:
        obj: The object to expand out.
        parent: The parent object: Used to short-circuit infinite recursion.
  
      Returns:
        a list of expanded values as strings.
      """
      # Catch cases where RDFs are iterable but return themselves.
      if parent and obj == parent:
        results = [utils.SmartUnicode(obj).strip()]
      elif isinstance(obj, (string_types, rdf_structs.EnumNamedValue)):
        results = [utils.SmartUnicode(obj).strip()]
      elif isinstance(obj, rdf_protodict.DataBlob):
        results = self.FanOut(obj.GetValue())
      elif isinstance(obj, (collections.Mapping, rdf_protodict.Dict)):
        results = []
        # rdf_protodict.Dict only has items, not iteritems.
        for k, v in iteritems(obj):
          expanded_v = [utils.SmartUnicode(r) for r in self.FanOut(v)]
          results.append("%s:%s" % (utils.SmartUnicode(k), ",".join(expanded_v)))
      elif isinstance(obj, (collections.Iterable,
                            rdf_structs.RepeatedFieldHelper)):
        results = []
        for rslt in [self.FanOut(o, obj) for o in obj]:
          results.extend(rslt)
      else:
        results = [utils.SmartUnicode(obj).strip()]
      return results