# Path: ubelt/util_hash.py
# HASH_VERSION = 2  # type: int
# _ALPHABET_10 = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# _ALPHABET_16 = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
#                 'a', 'b', 'c', 'd', 'e', 'f']
# _ALPHABET_26 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
#                 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
#                 'u', 'v', 'w', 'x', 'y', 'z']
# _ALPHABET_36 = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
#                 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
#                 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
#                 'u', 'v', 'w', 'x', 'y', 'z']
# DEFAULT_ALPHABET = _ALPHABET_16
# DEFAULT_HASHER = hashlib.sha512  # most robust algo, but slower than others
# _COMPATIBLE_HASHABLE_SEQUENCE_TYPES_DEFAULT = True
# _HASHERS = _Hashers()
# _HASHABLE_EXTENSIONS = HashableExtensions()
#         SEP = b'_,_'
#         ITER_PREFIX = b'_[_'
#         ITER_SUFFIX = b'_]_'
# def b(s):
# def _int_to_bytes(int_):
# def _bytes_to_int(bytes_):
#     def __init__(self):
#     def available(self):
#     def _evaluate_registration_queue(self):
#     def __contains__(self, key):
#     def _register_xxhash(self):  # nocover
#     def _register_blake3(self):  # nocover
#     def _register_hashlib(self):
#     def lookup(self, hasher):
# def _rectify_hasher(hasher):
# def _rectify_base(base):
#     def __init__(self):
#     def register(self, hash_types):
#         def _decor_closure(hash_func):
#     def add_iterable_check(self, func):
#     def lookup(self, data):
#     def _register_numpy_extensions(self):
#         def is_object_ndarray(data):
#         def _convert_numpy_array(data):
#         def _convert_numpy_int(data):
#         def _convert_numpy_float(data):
#         def _convert_numpy_random_state(data):
#     def _register_builtin_class_extensions(self):
#         def _convert_uuid(data):
#         def _convert_set(data):
#         def _convert_dict(data):
#         def _convert_ordered_dict(data):
#         def _convert_slice(data):
#     def _register_agressive_extensions(self):  # nocover
#     def _register_torch_extensions(self):  # nocover
#         def _convert_torch_tensor(data):
# def _lazy_init():
#     def __init__(self):
#     def update(self, bytes):
#     def hexdigest(self):
# def _hashable_sequence(data, types=False, extensions=None):
# def _convert_to_hashable(data, types=True, extensions=None):
# def _update_hasher(hasher, data, types=True, extensions=None):
# def _convert_hexstr_base(hexstr, base):
# def _digest_hasher(hasher, base):
# def hash_data(data, hasher=NoParam, base=NoParam, types=False, convert=False,
#               extensions=None):
# def hash_file(fpath, blocksize=1048576, stride=1, maxbytes=None,
#               hasher=NoParam, base=NoParam):
# class _Hashers(object):
# class HashableExtensions(object):
# class _HashTracer(object):


import functools
import sys
from ubelt import util_hash
    >>>     def my_property1(self):
    >>>         return 4
    >>>     #
    >>>     # The property decorator is optional
    >>>     def my_property2(self):
    >>>         return 5
    >>> #
    >>> func(1, 2)
    >>> func(1, 2)
    >>> self = MyClass()
    >>> self.my_method(1, 2)
    >>> self.my_method(1, 2)
    >>> self.my_property1
    >>> self.my_property1
    >>> self.my_property2
    >>> self.my_property2
"""


__all__ = ['memoize', 'memoize_method', 'memoize_property']


def _hashable(item):
    """
    Returns the item if it is naturally hashable, otherwise it tries to use
    ubelt.util_hash.hash_data to make it hashable. Errors if it cannot.
    """
    try:
        hash(item)
    except TypeError:

# Path: ubelt/util_hash.py
# HASH_VERSION = 2  # type: int
# _ALPHABET_10 = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# _ALPHABET_16 = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
#                 'a', 'b', 'c', 'd', 'e', 'f']
# _ALPHABET_26 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
#                 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
#                 'u', 'v', 'w', 'x', 'y', 'z']
# _ALPHABET_36 = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
#                 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
#                 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
#                 'u', 'v', 'w', 'x', 'y', 'z']
# DEFAULT_ALPHABET = _ALPHABET_16
# DEFAULT_HASHER = hashlib.sha512  # most robust algo, but slower than others
# _COMPATIBLE_HASHABLE_SEQUENCE_TYPES_DEFAULT = True
# _HASHERS = _Hashers()
# _HASHABLE_EXTENSIONS = HashableExtensions()
#         SEP = b'_,_'
#         ITER_PREFIX = b'_[_'
#         ITER_SUFFIX = b'_]_'
# def b(s):
# def _int_to_bytes(int_):
# def _bytes_to_int(bytes_):
#     def __init__(self):
#     def available(self):
#     def _evaluate_registration_queue(self):
#     def __contains__(self, key):
#     def _register_xxhash(self):  # nocover
#     def _register_blake3(self):  # nocover
#     def _register_hashlib(self):
#     def lookup(self, hasher):
# def _rectify_hasher(hasher):
# def _rectify_base(base):
#     def __init__(self):
#     def register(self, hash_types):
#         def _decor_closure(hash_func):
#     def add_iterable_check(self, func):
#     def lookup(self, data):
#     def _register_numpy_extensions(self):
#         def is_object_ndarray(data):
#         def _convert_numpy_array(data):
#         def _convert_numpy_int(data):
#         def _convert_numpy_float(data):
#         def _convert_numpy_random_state(data):
#     def _register_builtin_class_extensions(self):
#         def _convert_uuid(data):
#         def _convert_set(data):
#         def _convert_dict(data):
#         def _convert_ordered_dict(data):
#         def _convert_slice(data):
#     def _register_agressive_extensions(self):  # nocover
#     def _register_torch_extensions(self):  # nocover
#         def _convert_torch_tensor(data):
# def _lazy_init():
#     def __init__(self):
#     def update(self, bytes):
#     def hexdigest(self):
# def _hashable_sequence(data, types=False, extensions=None):
# def _convert_to_hashable(data, types=True, extensions=None):
# def _update_hasher(hasher, data, types=True, extensions=None):
# def _convert_hexstr_base(hexstr, base):
# def _digest_hasher(hasher, base):
# def hash_data(data, hasher=NoParam, base=NoParam, types=False, convert=False,
#               extensions=None):
# def hash_file(fpath, blocksize=1048576, stride=1, maxbytes=None,
#               hasher=NoParam, base=NoParam):
# class _Hashers(object):
# class HashableExtensions(object):
# class _HashTracer(object):


# Path: ubelt/util_memoize.py
import functools
import sys
from ubelt import util_hash

    >>>     def my_property1(self):
    >>>         return 4
    >>>     #
    >>>     # The property decorator is optional
    >>>     def my_property2(self):
    >>>         return 5
    >>> #
    >>> func(1, 2)
    >>> func(1, 2)
    >>> self = MyClass()
    >>> self.my_method(1, 2)
    >>> self.my_method(1, 2)
    >>> self.my_property1
    >>> self.my_property1
    >>> self.my_property2
    >>> self.my_property2
"""


__all__ = ['memoize', 'memoize_method', 'memoize_property']


def _hashable(item):
    """
    Returns the item if it is naturally hashable, otherwise it tries to use
    ubelt.util_hash.hash_data to make it hashable. Errors if it cannot.
    """
    try:
        hash(item)
    except TypeError:

        return util_hash.hash_data(item)