fix: preserve column order in PointsModel.parse() - #1192
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1192 +/- ##
=======================================
Coverage 92.39% 92.40%
=======================================
Files 52 52
Lines 7868 7872 +4
=======================================
+ Hits 7270 7274 +4
Misses 598 598
🚀 New features to boost your workflow:
|
|
Thanks @dylanpulver, well spotted and great fix! |
|
@dylanpulver how did you discover this bug? Was a part of your code dependent of the order of the columns and it changed as the seed (for some reasons) changed? I mention this because the fix will make the code seed invariant, but may change the order of the returned column (in a predictable way this time). This will not impact data correctness, as columns are labeled and can be used independently of the order; but if users were computing some hashes based depending on the column names, for instance to cache/store some intermediate results, those hashes may change (potentially leading to precomputed data being recomputed). |
|
For the maintainers: I created and added the label "todo-add-extra-comments-on-release-notes", so when we auto-generate release notes we remember to add a comment mentioning potential order implications to users. |
PointsModel.parse()appends the non-coordinate columns by iteratingset(data.columns) - {...}, so their order in the returned element follows string hash order and varies withPYTHONHASHSEED.The reordering safeguard at the end of
parse()only fires when the column set is unchanged, which hides this on the common path. Passingcoordinates=to rename coordinate columns changes that set, which skips the safeguard and leaves the order shuffled. Thenp.ndarraypath has no safeguard.This looks like the root cause of #486, closed as not reproducible and suspected to be a dask bug. Column order is not load-bearing for correctness, but it lands in the written Zarr, so two runs of one pipeline produce byte-different stores.
Both loops now walk
data.columns/annotation.columnsin order. I left the safeguard in place because it normalizes the case where the set is unchanged but the coordinate columns were reordered.Sorting the extra columns alphabetically would also be deterministic. I did not, because it discards input order and would change output on the path the safeguard covers.
Measured on the pandas path with six extra columns:
PYTHONHASHSEED0 through 5 gave six distinct column orders before, one order after. The new test fails on 30 of 30 seeds with the source change reverted.Stores written before this keep whatever order they were written with.