r"""
    Get a unique hash depending on the state of the data.

    Args:
        data (object): any sort of loosely organized data
        hashlen (None): (default = None)
        alphabet (None): (default = None)

    Returns:
        str: text -  hash string

    CommandLine:
        python -m utool.util_hash hash_data

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_hash import *  # NOQA
        >>> import utool as ut
        >>> counter = [0]
        >>> failed = []
        >>> def check_hash(input_, want=None):
        >>>     count = counter[0] = counter[0] + 1
        >>>     got = ut.hash_data(input_)
        >>>     print('({}) {}'.format(count, got))
        >>>     if want is not None and not got.startswith(want):
        >>>         failed.append((got, input_, count, want))
        >>> check_hash('1', 'wuvrng')
        >>> check_hash(['1'], 'dekbfpby')
        >>> check_hash(tuple(['1']), 'dekbfpby')
        >>> check_hash(b'12', 'marreflbv')
        >>> check_hash([b'1', b'2'], 'nwfs')
        >>> check_hash(['1', '2', '3'], 'arfrp')
        >>> check_hash(['1', np.array([1,2,3]), '3'], 'uyqwcq')
        >>> check_hash('123', 'ehkgxk')
        >>> check_hash(zip([1, 2, 3], [4, 5, 6]), 'mjcpwa')
        >>> import numpy as np
        >>> rng = np.random.RandomState(0)
        >>> check_hash(rng.rand(100000), 'bdwosuey')
        >>> for got, input_, count, want in failed:
        >>>     print('failed {} on {}'.format(count, input_))
        >>>     print('got={}, want={}'.format(got, want))
        >>> assert not failed

def hash_data(data, hashlen=None, alphabet=None):
    r"""
    Get a unique hash depending on the state of the data.

    Args:
        data (object): any sort of loosely organized data
        hashlen (None): (default = None)
        alphabet (None): (default = None)

    Returns:
        str: text -  hash string

    CommandLine:
        python -m utool.util_hash hash_data

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_hash import *  # NOQA
        >>> import utool as ut
        >>> counter = [0]
        >>> failed = []
        >>> def check_hash(input_, want=None):
        >>>     count = counter[0] = counter[0] + 1
        >>>     got = ut.hash_data(input_)
        >>>     print('({}) {}'.format(count, got))
        >>>     if want is not None and not got.startswith(want):
        >>>         failed.append((got, input_, count, want))
        >>> check_hash('1', 'wuvrng')
        >>> check_hash(['1'], 'dekbfpby')
        >>> check_hash(tuple(['1']), 'dekbfpby')
        >>> check_hash(b'12', 'marreflbv')
        >>> check_hash([b'1', b'2'], 'nwfs')
        >>> check_hash(['1', '2', '3'], 'arfrp')
        >>> check_hash(['1', np.array([1,2,3]), '3'], 'uyqwcq')
        >>> check_hash('123', 'ehkgxk')
        >>> check_hash(zip([1, 2, 3], [4, 5, 6]), 'mjcpwa')
        >>> import numpy as np
        >>> rng = np.random.RandomState(0)
        >>> check_hash(rng.rand(100000), 'bdwosuey')
        >>> for got, input_, count, want in failed:
        >>>     print('failed {} on {}'.format(count, input_))
        >>>     print('got={}, want={}'.format(got, want))
        >>> assert not failed
    """
    if alphabet is None:
        alphabet = ALPHABET_27
    if hashlen is None:
        hashlen = HASH_LEN2
    if isinstance(data, stringlike) and len(data) == 0:
        # Make a special hash for empty data
        text = (alphabet[0] * hashlen)
    else:
        hasher = hashlib.sha512()
        _update_hasher(hasher, data)
        # Get a 128 character hex string
        text = hasher.hexdigest()
        # Shorten length of string (by increasing base)
        hashstr2 = convert_hexstr_to_bigbase(text, alphabet, bigbase=len(alphabet))
        # Truncate
        text = hashstr2[:hashlen]
        return text