docs: def hashstr(data, hashlen=HASH_LEN, alphabet=ALPHABET):
      """
      python -c "import utool as ut; print(ut.hashstr('abcd'))"
  
      Args:
          data (hashable):
          hashlen (int): (default = 16)
          alphabet (list): list of characters:
  
      Returns:
          str: hashstr
  
      CommandLine:
          python -m utool.util_hash --test-hashstr
          python3 -m utool.util_hash --test-hashstr
          python3 -m utool.util_hash --test-hashstr:2
          python -m utool.util_hash hashstr:3
          python3 -m utool.util_hash hashstr:3
  
  
      Example0:
          >>> # ENABLE_DOCTEST
          >>> from utool.util_hash import *  # NOQA
          >>> data = 'foobar'
          >>> hashlen = 16
          >>> alphabet = ALPHABET_41
          >>> text = hashstr(data, hashlen, alphabet)
          >>> result = ('text = %s' % (str(text),))
          >>> print(result)
          text = mi5yum60mbxhyp+x
  
      Example1:
          >>> # ENABLE_DOCTEST
          >>> from utool.util_hash import *  # NOQA
          >>> data = ''
          >>> hashlen = 16
          >>> alphabet = ALPHABET_41
          >>> text = hashstr(data, hashlen, alphabet)
          >>> result = ('text = %s' % (str(text),))
          >>> print(result)
          text = 0000000000000000
  
      Example2:
          >>> # ENABLE_DOCTEST
          >>> from utool.util_hash import *  # NOQA
          >>> import numpy as np
          >>> data = np.array([1, 2, 3])
          >>> hashlen = 16
          >>> alphabet = ALPHABET_41
          >>> text = hashstr(data, hashlen, alphabet)
          >>> result = ('text = %s' % (str(text),))
          >>> print(result)
          text = z5lqw0bzt4dmb9yy
  
      Example2:
          >>> # ENABLE_DOCTEST
          >>> from utool.util_hash import *  # NOQA
          >>> import numpy as np
          >>> from uuid import UUID
          >>> data = (UUID('7cd0197b-1394-9d16-b1eb-0d8d7a60aedc'), UUID('c76b54a5-adb6-7f16-f0fb-190ab99409f8'))
          >>> hashlen = 16
          >>> alphabet = ALPHABET_41
          >>> text = hashstr_arr(data, 'label')
          >>> result = ('text = %s' % (str(text),))
          >>> print(result)
  
  
      Example3:
          >>> # DISABLE_DOCTEST
          >>> # UNSTABLE_DOCTEST
          >>> from utool.util_hash import *  # NOQA
          >>> import numpy as np
          >>> data = np.array(['a', 'b'], dtype=object)
          >>> text = hashstr(data, alphabet=ALPHABET_27)
          >>> result = ('text = %s' % (str(text),))
          >>> print(result)
  
      Ignore:
          data = np.array(['a', 'b'], dtype=object)
          data.tobytes()
          data = np.array(['a', 'b'])
          data = ['a', 'b']
          data = np.array([1, 2, 3])
          import hashlib
          from six.moves import cPickle as pickle
          pickle.dumps(data, protocol=2)
  
          python2 -c "import hashlib, numpy; print(hashlib.sha1('ab').hexdigest())"
          python3 -c "import hashlib, numpy; print(hashlib.sha1('ab'.encode('utf8')).hexdigest())"
  
          python2 -c "import hashlib, numpy; print(hashlib.sha1('ab').hexdigest())"
          python3 -c "import hashlib, numpy; print(hashlib.sha1(b'ab').hexdigest())"
  
          python2 -c "import hashlib, numpy; print(hashlib.sha1(numpy.array([1, 2])).hexdigest())"
          python3 -c "import hashlib, numpy; print(hashlib.sha1(numpy.array([1, 2])).hexdigest())"
  
          # TODO: numpy arrays of strings must be encoded to bytes first in python3
          python2 -c "import hashlib, numpy; print(hashlib.sha1(numpy.array(['a', 'b'])).hexdigest())"
          python3 -c "import hashlib, numpy; print(hashlib.sha1(numpy.array([b'a', b'b'])).hexdigest())"
  
          python -c "import hashlib, numpy; print(hashlib.sha1(numpy.array(['a', 'b'], dtype=object)).hexdigest())"
          python -c "import hashlib, numpy; print(hashlib.sha1(numpy.array(['a', 'b'], dtype=object)).hexdigest())"
      """
      if util_type.HAVE_NUMPY and isinstance(data, np.ndarray):
          if data.dtype.kind == 'O':
              msg = '[ut] hashing ndarrays with dtype=object is unstable'
              warnings.warn(msg, RuntimeWarning)
              # but tobytes is ok, but differs between python 2 and 3 for objects
              data = data.dumps()
              # data = data.tobytes()
      if isinstance(data, tuple):
          # should instead do
          if False:
              hasher = hashlib.sha512()
              items = data
              for item in items:
                  if isinstance(item, uuid.UUID):
                      hasher.update(item.bytes)
                  else:
                      hasher.update(item)
              text = hasher.hexdigest()
              hashstr2 = convert_hexstr_to_bigbase(text, alphabet, bigbase=len(alphabet))
              # Truncate
              text = hashstr2[:hashlen]
              return text
          else:
              msg = '[ut] hashing tuples with repr is not a good idea. FIXME'
              # warnings.warn(msg, RuntimeWarning)
              data = repr(data)  # Hack?
  
      # convert unicode into raw bytes
      if isinstance(data, six.text_type):
          data = data.encode('utf-8')
  
      if isinstance(data, stringlike) and len(data) == 0:
          # Make a special hash for empty data
          text = (alphabet[0] * hashlen)
      else:
          # Get a 128 character hex string
          text = hashlib.sha512(data).hexdigest()
          # Shorten length of string (by increasing base)
          hashstr2 = convert_hexstr_to_bigbase(text, alphabet, bigbase=len(alphabet))
          # Truncate
          text = hashstr2[:hashlen]
      return text