diff --git a/docs/src/whatsnew/3.16/3.16.rst b/docs/src/whatsnew/3.16/3.16.rst index 45cd3ed0a6..05a87597b5 100644 --- a/docs/src/whatsnew/3.16/3.16.rst +++ b/docs/src/whatsnew/3.16/3.16.rst @@ -160,6 +160,8 @@ v3.16 (13 Aug 2026) - :fa:`code-pull-request` :pull:`7223`: :user:`trexfeathers` updated Iris to be compatible with Matplotlib version 3.11. +- :fa:`code-pull-request` :pull:`7262`: :user:`trexfeathers` updated Iris' metadata handling to be compatible with python-xxhash version 4.0 . + 📚 Documentation diff --git a/lib/iris/common/metadata.py b/lib/iris/common/metadata.py index c24f240217..cf8a8de1e8 100644 --- a/lib/iris/common/metadata.py +++ b/lib/iris/common/metadata.py @@ -96,6 +96,10 @@ def hexdigest(item): parts = (item.shape, xxh64_hexdigest(item)) item = str(parts) + # xxhash 4.0+: str is no longer accepted; encode to bytes first. + if isinstance(item, str): + item = item.encode() + try: # Calculate single-shot hash to avoid allocating state on the heap result = xxh64_hexdigest(item) @@ -104,7 +108,7 @@ def hexdigest(item): # string representation of the provided item instead, but # also fold in the object type... parts = (type(item), item) - result = xxh64_hexdigest(str(parts)) + result = xxh64_hexdigest(str(parts).encode()) return result diff --git a/lib/iris/tests/unit/common/metadata/test_hexdigest.py b/lib/iris/tests/unit/common/metadata/test_hexdigest.py index 0ce0dcd706..05285dc34f 100644 --- a/lib/iris/tests/unit/common/metadata/test_hexdigest.py +++ b/lib/iris/tests/unit/common/metadata/test_hexdigest.py @@ -21,7 +21,7 @@ def _setup(self): @staticmethod def _ndarray(value): parts = str((value.shape, xxh64_hexdigest(value))) - return xxh64_hexdigest(parts) + return xxh64_hexdigest(parts.encode()) @staticmethod def _masked(value): @@ -32,11 +32,11 @@ def _masked(value): xxh64_hexdigest(value.mask), ) ) - return xxh64_hexdigest(parts) + return xxh64_hexdigest(parts.encode()) def test_string(self): value = "hello world" - self.hasher.update(value) + self.hasher.update(value.encode()) expected = self.hasher.hexdigest() assert hexdigest(value) == expected @@ -111,7 +111,7 @@ def test_masked_array_reshape_not_flat(self): class TestNotBytesLikeObject: def _expected(self, value): parts = str((type(value), value)) - return xxh64_hexdigest(parts) + return xxh64_hexdigest(parts.encode()) def test_int(self): value = 123