diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ab2afa215..1a4f268ad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,7 +46,7 @@ This release fixes a number of smaller regressions related to `Tabulator` `row_c - Do not mutate layout `Children` inplace ([#7417](https://github.com/holoviz/panel/pull/7403)) - Set `Tabulator` null formatter to empty string ([#7421](https://github.com/holoviz/panel/pull/7421)) - Ensure Tabulator table content does not overflow ([#7425](https://github.com/holoviz/panel/pull/7425)) - +- Ensure `cache` handles hashing of classes and instances correctly ([#7478](https://github.com/holoviz/panel/issues/7478)) ### Compatibility diff --git a/doc/about/releases.md b/doc/about/releases.md index c97a73cfbf..91154380c1 100644 --- a/doc/about/releases.md +++ b/doc/about/releases.md @@ -48,6 +48,7 @@ This release fixes a number of smaller regressions related to `Tabulator` `row_c - Do not mutate layout `Children` inplace ([#7417](https://github.com/holoviz/panel/pull/7403)) - Set `Tabulator` null formatter to empty string ([#7421](https://github.com/holoviz/panel/pull/7421)) - Ensure Tabulator table content does not overflow ([#7425](https://github.com/holoviz/panel/pull/7425), [#7431](https://github.com/holoviz/panel/pull/7431)) +- Ensure `cache` handles hashing of classes and instances correctly ([#7478](https://github.com/holoviz/panel/issues/7478)) ### Compatibility diff --git a/panel/io/cache.py b/panel/io/cache.py index 5392e53d95..db51f41572 100644 --- a/panel/io/cache.py +++ b/panel/io/cache.py @@ -266,7 +266,7 @@ def _generate_hash_inner(obj): f'{obj!r} with following error: {type(e).__name__}("{e}").' ) from e return output - if hasattr(obj, '__reduce__'): + if hasattr(obj, '__reduce__') and inspect.isclass(obj): h = hashlib.new("md5") try: reduce_data = obj.__reduce__() diff --git a/panel/tests/io/test_cache.py b/panel/tests/io/test_cache.py index e4aa495520..9031702b27 100644 --- a/panel/tests/io/test_cache.py +++ b/panel/tests/io/test_cache.py @@ -17,9 +17,7 @@ diskcache = None diskcache_available = pytest.mark.skipif(diskcache is None, reason="requires diskcache") -from panel.io.cache import ( - _find_hash_func, _generate_hash, cache, is_equal, -) +from panel.io.cache import _generate_hash, cache, is_equal from panel.io.state import set_curdoc, state from panel.tests.util import serve_and_wait @@ -28,7 +26,7 @@ ################ def hashes_equal(v1, v2): - a, b = _find_hash_func(v1)(v1), _find_hash_func(v2)(v2) + a, b = _generate_hash(v1), _generate_hash(v2) return a == b def test_str_hash(): @@ -52,6 +50,11 @@ def test_none_hash(): assert hashes_equal(None, None) assert not hashes_equal(None, False) +def test_object_hash(): + obj1, obj2 = object(), object() + assert hashes_equal(obj1, obj1) + assert not hashes_equal(obj1, obj2) + def test_bytes_hash(): assert hashes_equal(b'0', b'0') assert not hashes_equal(b'0', b'1') @@ -70,10 +73,11 @@ def test_list_hash(): assert not hashes_equal([0], [1]) assert not hashes_equal(['a', ['b']], ['a', ['c']]) +def test_list_hash_recursive(): # Recursion l = [0] l.append(l) - assert hashes_equal(l, list(l)) + assert hashes_equal(list(l), list(l)) def test_tuple_hash(): assert hashes_equal((0,), (0,)) @@ -88,10 +92,10 @@ def test_dict_hash(): assert not hashes_equal({'a': 0}, {'a': 1}) assert not hashes_equal({'a': {'b': 0}}, {'a': {'b': 1}}) - # Recursion +def test_dict_hash_recursive(): d = {'a': {}} d['a'] = d - assert hashes_equal(d, dict(d)) + assert hashes_equal(dict(d), dict(d)) def test_stringio_hash(): sio1, sio2 = io.StringIO(), io.StringIO()