def stringify(s, stype=None, fn=None):
    ''' Converts elements of a complex data structure to strings

    The data structure can be a multi-tiered one - with tuples and lists etc
    This method will loop through each and convert everything to string.
    For example - it can be -
    [[{'a1': {'a2': {'a3': ('a4', timedelta(0, 563)), 'a5': {'a6': datetime()}}}}]]
    which will be converted to -
    [[{'a1': {'a2': {'a3': ('a4', '0:09:23'), 'a5': {'a6': '2009-05-27 16:19:52.401500' }}}}]]

    @param stype: If only one type of data element needs to be converted to
        string without affecting others, stype can be used.
        In the earlier example, if it is called with stringify(s, stype=datetime.timedelta)
        the result would be
        [[{'a1': {'a2': {'a3': ('a4', '0:09:23'), 'a5': {'a6': datetime() }}}}]]

    Also, even though the name is stringify, any function can be run on it, based on
    parameter fn. If fn is None, it will be stringified.

    '''

    if type(s) in [list, set, dict, tuple]:
        if isinstance(s, dict):
            for k in s:
                s[k] = stringify(s[k], stype, fn)
        elif type(s) in [list, set]:
            for i, k in enumerate(s):
                s[i] = stringify(k, stype, fn)
        else: #tuple
            tmp = []
            for k in s:
                tmp.append(stringify(k, stype, fn))
            s = tuple(tmp)
    else:
        if fn:
            if not stype or (stype == type(s)):
                return fn(s)
        else:
            # To do str(s). But, str() can fail on unicode. So, use .encode instead
            if not stype or (stype == type(s)):
                try:
                    return six.text_type(s)
                    #return s.encode('ascii', 'replace')
                except AttributeError:
                    return str(s)
                except __HOLE__:
                    return s.decode('ascii', 'replace')
    return s
dataset/ETHPy150Open kra3/py-ga-mob/pyga/utils.py/stringify