From d3596a1bf38c27d4894c3fae3c68e0300cb8f464 Mon Sep 17 00:00:00 2001 From: liammcinroy <1899809+liammcinroy@users.noreply.github.com> Date: Mon, 15 Apr 2024 20:45:22 -0600 Subject: [PATCH 1/4] Make `args_to_key` invertible --- diskcache/core.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/diskcache/core.py b/diskcache/core.py index 7a3d23b..ebfde58 100644 --- a/diskcache/core.py +++ b/diskcache/core.py @@ -402,8 +402,7 @@ def args_to_key(base, args, kwargs, typed, ignore): kwargs = {key: val for key, val in kwargs.items() if key not in ignore} sorted_items = sorted(kwargs.items()) - for item in sorted_items: - key += item + key += tuple(sorted_items) if typed: key += tuple(type(arg) for arg in args) From 3cdf4ce1d8cb5d71f157b62b5f8198c63b0e5624 Mon Sep 17 00:00:00 2001 From: liammcinroy <1899809+liammcinroy@users.noreply.github.com> Date: Mon, 15 Apr 2024 21:46:48 -0600 Subject: [PATCH 2/4] test --- diskcache/core.py | 47 +++++++++++++++++++++++++++++++++++++++++++++- tests/test_core.py | 18 ++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/diskcache/core.py b/diskcache/core.py index ebfde58..b9564ad 100644 --- a/diskcache/core.py +++ b/diskcache/core.py @@ -401,7 +401,6 @@ def args_to_key(base, args, kwargs, typed, ignore): if kwargs: kwargs = {key: val for key, val in kwargs.items() if key not in ignore} sorted_items = sorted(kwargs.items()) - key += tuple(sorted_items) if typed: @@ -413,6 +412,52 @@ def args_to_key(base, args, kwargs, typed, ignore): return key +def key_to_args(key): + """Get the args and kwargs from a cache key. + + :param tuple key: cache key tuple + :return: tuple of args, kwargs + :rtype: tuple pair of tuple and dict + + """ + kwargs_ranges = [] + type_range = None + last_kwargs_start_idx = -1 + last_typed_start_idx = -1 + for idx, val in key: + if last_kwargs_start_idx == -1 and val is None: + last_kwargs_start_idx = idx + 1 + elif last_kwargs_start_idx != -1 and val is not tuple: + kwargs_ranges.append((last_kwargs_start_idx, idx)) + last_kwargs_start_idx = -1 + + if last_typed_start_idx != -1 and val is type: + last_typed_start_idx = idx + elif last_typed_start_idx != -1 and val is not type: + last_typed_start_idx = -1 + + if last_kwargs_start_idx != -1: + kwargs_ranges.append(last_kwargs_start_idx, len(key)) + elif last_type_idx != -1: + type_range = (last_type_idx, len(key)) + + if type_range is not None: + num_args_kwargs = type_range[1] - type_range[0] + kwargs_range = [ + (start, end) + for start, end in kwargs_ranges + if (start - 2) + (end - start) == num_args_kwargs + ][-1] + else: + kwargs_range = kwargs_ranges[-1] + + start, end = kwargs_range + args = key[1: start - 1] + kwargs = key[start:end] + + return (args, dict(kwargs)) + + class Cache: """Disk and file backed cache.""" diff --git a/tests/test_core.py b/tests/test_core.py index 788afef..271f0e5 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1405,3 +1405,21 @@ def test(*args, **kwargs): assert len(cache) == 3 for key in cache: assert cache[key] == 6 + + +def test_memoize_args_to_key_invertible(cache): + @cache.memoize() + def test(*args, **kwargs): + return (args, kwargs) + + cache.clear() + assert test() + assert test(0) + assert test(a=0) + assert test(0, 1, 2, a=0, b=1, c=2) + assert test(None, "fake kwarg start", None) + assert test(None, "fake kwarg start", None, a=0) + assert test(bool, bytes, float, int, str) + for key in cache: + assert dc.key_to_args(key) == cache[key] + From 5b669f221cbc84eaa3cd3fe9becd028b18e7ee4d Mon Sep 17 00:00:00 2001 From: liammcinroy <1899809+liammcinroy@users.noreply.github.com> Date: Tue, 16 Apr 2024 06:48:53 -0600 Subject: [PATCH 3/4] tests --- diskcache/core.py | 35 ++++++++++++++++++----------------- tests/test_core.py | 18 ++++++++++++------ 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/diskcache/core.py b/diskcache/core.py index b9564ad..d84cfbc 100644 --- a/diskcache/core.py +++ b/diskcache/core.py @@ -413,7 +413,8 @@ def args_to_key(base, args, kwargs, typed, ignore): def key_to_args(key): - """Get the args and kwargs from a cache key. + """Get the args and kwargs from a cache key's tail (i.e. everything + following the base of the key). :param tuple key: cache key tuple :return: tuple of args, kwargs @@ -422,37 +423,37 @@ def key_to_args(key): """ kwargs_ranges = [] type_range = None - last_kwargs_start_idx = -1 - last_typed_start_idx = -1 - for idx, val in key: - if last_kwargs_start_idx == -1 and val is None: - last_kwargs_start_idx = idx + 1 - elif last_kwargs_start_idx != -1 and val is not tuple: + last_kwargs_start_idx = last_typed_start_idx = None + for idx, val in enumerate(key): + if last_kwargs_start_idx is not None and not isinstance(val, tuple): kwargs_ranges.append((last_kwargs_start_idx, idx)) - last_kwargs_start_idx = -1 + last_kwargs_start_idx = None + if last_kwargs_start_idx is None and val is None: + last_kwargs_start_idx = idx + 1 - if last_typed_start_idx != -1 and val is type: + val_is_type = isinstance(val, type) + if last_typed_start_idx is not None and not val_is_type: + last_typed_start_idx = None + if last_typed_start_idx is None and val_is_type: last_typed_start_idx = idx - elif last_typed_start_idx != -1 and val is not type: - last_typed_start_idx = -1 - if last_kwargs_start_idx != -1: - kwargs_ranges.append(last_kwargs_start_idx, len(key)) - elif last_type_idx != -1: - type_range = (last_type_idx, len(key)) + if last_kwargs_start_idx is not None: + kwargs_ranges.append((last_kwargs_start_idx, len(key))) + elif last_typed_start_idx is not None: + type_range = (last_typed_start_idx, len(key)) if type_range is not None: num_args_kwargs = type_range[1] - type_range[0] kwargs_range = [ (start, end) for start, end in kwargs_ranges - if (start - 2) + (end - start) == num_args_kwargs + if (start - 1) + (end - start) == num_args_kwargs ][-1] else: kwargs_range = kwargs_ranges[-1] start, end = kwargs_range - args = key[1: start - 1] + args = key[: start - 1] kwargs = key[start:end] return (args, dict(kwargs)) diff --git a/tests/test_core.py b/tests/test_core.py index 271f0e5..094ba0b 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1407,8 +1407,9 @@ def test(*args, **kwargs): assert cache[key] == 6 -def test_memoize_args_to_key_invertible(cache): - @cache.memoize() +@pytest.mark.parametrize('typed', [False, True]) +def test_memoize_args_to_key_invertible(cache, typed): + @cache.memoize(typed=typed) def test(*args, **kwargs): return (args, kwargs) @@ -1417,9 +1418,14 @@ def test(*args, **kwargs): assert test(0) assert test(a=0) assert test(0, 1, 2, a=0, b=1, c=2) - assert test(None, "fake kwarg start", None) - assert test(None, "fake kwarg start", None, a=0) + assert test(None, 'fake kwarg start', None) + assert test(None, 'fake kwarg start', None, a=0) assert test(bool, bytes, float, int, str) for key in cache: - assert dc.key_to_args(key) == cache[key] - + args, kwargs = dc.core.key_to_args(key[1:]) + assert (args, kwargs) == cache[key] + if typed: + expected_key_len = 2 + (2 if typed else 1) * ( + len(args) + len(kwargs) + ) + assert expected_key_len == len(key) From 989753d789ca4676c505214b14fbae83ebc9ca6a Mon Sep 17 00:00:00 2001 From: liammcinroy <1899809+liammcinroy@users.noreply.github.com> Date: Tue, 16 Apr 2024 07:54:41 -0600 Subject: [PATCH 4/4] better test --- tests/test_core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 094ba0b..af0feca 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1418,8 +1418,8 @@ def test(*args, **kwargs): assert test(0) assert test(a=0) assert test(0, 1, 2, a=0, b=1, c=2) - assert test(None, 'fake kwarg start', None) - assert test(None, 'fake kwarg start', None, a=0) + assert test(None, 'fake kwarg start') + assert test(None, 'fake kwarg start', a=0) assert test(bool, bytes, float, int, str) for key in cache: args, kwargs = dc.core.key_to_args(key[1:])