diff --git a/atools/memoize_decorator.py b/atools/memoize_decorator.py
index 1e54ea3..e757e35 100644
--- a/atools/memoize_decorator.py
+++ b/atools/memoize_decorator.py
@@ -6,7 +6,7 @@ from datetime import timedelta
 import inspect
 from time import time
 from threading import Lock as SyncLock
-from typing import Any, Optional, Tuple, Union
+from typing import Any, Optional, Union
 
 
 class _MemoZeroValue:
@@ -74,15 +74,15 @@ class _MemoizeState:
         self._memos = OrderedDict()
         self._expire_order = deque() if self._expire_order is not None else None
 
-    def make_key(self, *args, **kwargs) -> Tuple:
+    def make_key(self, *args, **kwargs) -> int:
         """Returns all params (args, kwargs, and missing default kwargs) for function as kwargs."""
         args_as_kwargs = {}
         for k, v in zip(self._default_kwargs, args):
             args_as_kwargs[k] = v
 
-        return tuple(ChainMap(args_as_kwargs, kwargs, self._default_kwargs).values())
+        return hash(tuple(ChainMap(args_as_kwargs, kwargs, self._default_kwargs).values()))
 
-    def get_memo(self, key) -> _Memo:
+    def get_memo(self, key: int) -> _Memo:
         try:
             memo = self._memos[key] = self._memos.pop(key)
             if self._duration is not None and memo.expire_time < time():
diff --git a/setup.py b/setup.py
index 3a2fd23..d029798 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from setuptools import setup
 
 setup(
     name='atools',
-    version='0.6.0',
+    version='0.6.1',
     packages=['', 'atools'],
     python_requires='>=3.6',
     url='https://github.com/cevans87/atools',

Memoize decorator keeps input objects alive while cached
The hash key created to memoize function calls is a tuple of the inputs. It should instead be a hash of that tuple so that none of the objects in the tuple are accidentally kept from being garbage collected.
diff --git a/test/test_memoize_decorator.py b/test/test_memoize_decorator.py
index f1f515d..877f0a9 100644
--- a/test/test_memoize_decorator.py
+++ b/test/test_memoize_decorator.py
@@ -5,6 +5,7 @@ from atools import async_test_case, memoize
 from datetime import timedelta
 import unittest
 from unittest.mock import call, MagicMock, patch
+from weakref import ref
 
 
 @async_test_case
@@ -465,11 +466,21 @@ class TestMemoize(unittest.TestCase):
 
         self.assertEqual(foo_a, foo_b)
 
-    #async def test_memoize_does_not_stop_object_cleanup(self) -> None:
-    #    # TODO make an object, memoize a funciton with that object, and then convert local
-    #    #  variable to a weakref. Assert that the object is cleaned up.
+    async def test_memoize_does_not_stop_object_cleanup(self) -> None:
+        class Foo:
+            pass
+
+        @memoize
+        def foo(_: Foo) -> None:
+            ...
+
+        f = Foo()
+        foo(f)
 
-    #    raise Exception()
+        r = ref(f)
+        assert r() is not None
+        del f
+        assert r() is None
 
 
 if __name__ == '__main__':

pip install -e .[u2f]
parse_log_pytest
requirements.txt
nose mock pytest
apt-get update apt-get install -y gcc
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
-e git+https://github.com/cevans87/atools.git@5667eef829897574b59a23787fc281c8bf55688d#egg=atools
attrs==22.2.0
certifi==2021.5.30
dataclasses==0.8
importlib-metadata==4.8.3
iniconfig==1.1.1
mock==5.2.0
nose==1.3.7
packaging==21.3
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
tomli==1.2.3
typing_extensions==4.1.1
zipp==3.6.0

name: atools
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - dataclasses==0.8
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - mock==5.2.0
      - nose==1.3.7
      - packaging==21.3
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - zipp==3.6.0
prefix: /opt/conda/envs/atools

test/test_memoize_decorator.py::TestMemoize::test_memoize_does_not_stop_object_cleanup
test/test_memoize_decorator.py::TestMemoize::test_args_overlaps_kwargs_raises test/test_memoize_decorator.py::TestMemoize::test_async test/test_memoize_decorator.py::TestMemoize::test_async_does_not_sync_lock test/test_memoize_decorator.py::TestMemoize::test_async_exception test/test_memoize_decorator.py::TestMemoize::test_async_herd_waits_for_return test/test_memoize_decorator.py::TestMemoize::test_async_locks_async test/test_memoize_decorator.py::TestMemoize::test_async_no_event_loop_does_not_raise test/test_memoize_decorator.py::TestMemoize::test_async_reset test/test_memoize_decorator.py::TestMemoize::test_async_size test/test_memoize_decorator.py::TestMemoize::test_async_thundering_herd test/test_memoize_decorator.py::TestMemoize::test_class_function test/test_memoize_decorator.py::TestMemoize::test_expire_current_call test/test_memoize_decorator.py::TestMemoize::test_expire_head_of_line_refresh_does_not_stop_eviction test/test_memoize_decorator.py::TestMemoize::test_expire_le_zero_raises test/test_memoize_decorator.py::TestMemoize::test_expire_old_call test/test_memoize_decorator.py::TestMemoize::test_expire_old_item_does_not_expire_new test/test_memoize_decorator.py::TestMemoize::test_keyword_same_as_default test/test_memoize_decorator.py::TestMemoize::test_memoizes_class test/test_memoize_decorator.py::TestMemoize::test_memoizes_class_with_metaclass test/test_memoize_decorator.py::TestMemoize::test_reset_all_resets_class_decorators test/test_memoize_decorator.py::TestMemoize::test_reset_all_resets_function_decorators test/test_memoize_decorator.py::TestMemoize::test_size_le_zero_raises test/test_memoize_decorator.py::TestMemoize::test_sync_does_not_async_lock test/test_memoize_decorator.py::TestMemoize::test_sync_exception test/test_memoize_decorator.py::TestMemoize::test_sync_locks_sync test/test_memoize_decorator.py::TestMemoize::test_sync_reset test/test_memoize_decorator.py::TestMemoize::test_sync_size test/test_memoize_decorator.py::TestMemoize::test_with_property test/test_memoize_decorator.py::TestMemoize::test_zero_args
atools/memoize_decorator.py setup.py
atools/memoize_decorator.py setup.py