fix(ArraySpec): proper and robust equality semantics for ArraySpec by checking fill_value for byte-identicality, fixes #3054.#4183
Conversation
… checking fill_value for byte-identicality, fixes zarr-developers#3054.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4183 +/- ##
=======================================
Coverage 93.84% 93.85%
=======================================
Files 91 91
Lines 12549 12561 +12
=======================================
+ Hits 11777 11789 +12
Misses 772 772
🚀 New features to boost your workflow:
|
|
Should I add a test case that non-ArraySpec comparison raises as requested by the codecov plugin? IMO this is a trivial case.. |
|
Thanks, this is a great fix. I will leave a few comments, but IMO this is good to go
only if you feel like it. |
| ] | ||
|
|
||
|
|
||
| class TestArraySpecHashEq: |
There was a problem hiding this comment.
i don't know why we need a class here. IMO plain functions and data are simpler
| ] | ||
|
|
||
|
|
||
| # Mutations: each mutate kwargs to an uneqal version |
There was a problem hiding this comment.
| # Mutations: each mutate kwargs to an uneqal version | |
| # Mutations: each mutate kwargs to an unequal version |
| base = _make_spec(**kwargs) | ||
| variant = _make_spec(**{**kwargs, **mutate(kwargs)}) | ||
| assert base != variant | ||
| assert hash(base) != hash(variant) |
There was a problem hiding this comment.
hashes collisions between unequal objects can occur, right? so maybe we just need to check that they are unequal, and not that the hashes differ?
|
can you update the stale comment in |
Summary
ArraySpecdescribes the exact layout for an array. The previously auto-generated__eq__and__hash__methods from@dataclassdid not reflect this correctly due to thefill_valueattribute.Specifically:
nan != nanand thusArraySpec(**kwargs) != ArraySpec(**kwargs)if the fill value is nan (although it they are in fact identical as they have the same fill).np.datetime64('NaT')which is also not self-equalfloat(-0.0) == float(0.0)despite these two fill_value's being different float numbers. They would result in different arrays in memory and on disk.np.void, such as from a structured dtype,hash(ArraySpec(...))failed outright, because (mutable)np.voids are not hashable. (Issue sharding codec use of lru caching fails with numpy void scalars #3054).This PR fixes all of the above by comparing
fill_valueusing byte-identity, which should be the correct semantics for a fill value. It also adds a comprehensive test suite for the equality and hash semantics ofArraySpecwhich was non-existent before.Before this fix/PR, the following (newly added) tests failed:
With the fix applied, all tests pass. Also, before this fix, the following valid zarr code would throw an exception:
This PR fixes the above.
Behavioral Changes (summarized):
For reviewers
#3054 discusses getting rid of the lru cache entirely. This is an orthogonal design decision in my opinion. While this PR fixes the exception, it does not remove the lru cache. Instead, it ensures that
ArraySpechas robust hash semantics in the first place which is a good thing regardless of #3054 and whether an lru cache is used or not.Author attestation
TODO
docs/user-guide/*.mdchanges/