Skip to content

fix: relabel_sequential() for unsigned integer dtypes - #1287

Open
MMatinGerami wants to merge 1 commit into
scverse:mainfrom
MMatinGerami:fix/relabel-sequential-unsigned
Open

MMatinGerami wants to merge 1 commit into
scverse:mainfrom
MMatinGerami:fix/relabel-sequential-unsigned

Conversation

@MMatinGerami

@MMatinGerami MMatinGerami commented Oct 26, 2026 •

Copy link
Copy Markdown

Closes #1215

Problem

relabel_sequential() builds its lookup table with

new_labeling = da.full(max_label + 1, -1, dtype=arr.dtype)

With NumPy 2 (NEP 50) the Python int -1 can no longer be cast to an unsigned dtype, so the function raises OverflowError: Python integer -1 out of bounds for uint16 for every uint8/uint16/uint32/uint64 input. Segmentation masks are almost always unsigned, and map_raster(relabel=True) points users to this function.

import numpy as np, dask.array as da
from spatialdata import relabel_sequential
arr = da.from_array(np.array([[0, 5, 9], [9, 5, 0]], dtype=np.uint16), chunks=(2, 3))
relabel_sequential(arr).compute()
# before: OverflowError: Python integer -1 out of bounds for uint16
# after:  array([[0, 1, 2], [2, 1, 0]], dtype=uint16)

Fix

The fill value is never read: every label present in arr is overwritten by new_labeling[unique_labels] = da.arange(...), and new_labeling[arr] only reads those positions. So the table is now created with da.zeros(max_label + 1, dtype=arr.dtype), which is valid for every integer dtype. Behaviour for signed dtypes is unchanged (same output, same dtype).

Tests

test_relabel_sequential_dtypes is parametrized over uint8, uint16, uint32, uint64, int8, int32, int64 and checks both the values and that the output dtype equals the input dtype. On main the four unsigned cases fail with the OverflowError; with this change all 11 -k relabel tests in tests/core/operations/test_map.py pass (numpy 2.5.4). A changelog entry is added under Unreleased / Fixed.

LLM usage

An LLM coding assistant helped find and draft this fix.

  • I have reviewed, understood and tested every changed line myself.

@codecov

codecov Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.43%. Comparing base (1d5dcbe) to head (8cb7f58).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1287   +/-   ##
=======================================
  Coverage   91.43%   91.43%           
=======================================
  Files          53       53           
  Lines        8395     8395           
=======================================
  Hits         7676     7676           
  Misses        719      719           
Files with missing lines Coverage Δ
src/spatialdata/_core/operations/map.py 98.91% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@MMatinGerami
MMatinGerami force-pushed the fix/relabel-sequential-unsigned branch from 1e70493 to 8cb7f58 Compare October 29, 2026 02:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

relabel_sequential() fails for every unsigned dtype: OverflowError: Python integer -1 out of bounds for uint16

1 participant