Skip to content

Scanpy 1.11.4 may fail to build with the upcoming Numba 0.62.0 #3778

@emilazy

Description

@emilazy

Please make sure these conditions are met

  • I have checked that this issue has not already been reported.
  • I have confirmed this bug exists on the latest version of scanpy.
  • (optional) I have confirmed this bug exists on the main branch of scanpy.

What happened?

When testing the upcoming Numba version ahead of time in Nixpkgs, we found that Scanpy 1.11.4 fails to build due to a Numba type‐checking error. This is caused by stricter checking of range, intended to prevent automatic casting of floats to integers.

I am not sure whether it is intentional that mixing signed and unsigned integers like this also fails, so I’m reporting it on both ends just in case.

Of course, Numba 0.62.0 has not been released yet, so this is not yet an active problem, but I figured it was worth giving notification in case the change is intentional. I see that the relevant range call has moved to a separate library in the current Git version, so I am not sure whether this would reproduce there.

Minimal code sample

N/A

Error output

----------------------------- Captured stderr call -----------------------------
ranking genes
_______________________ test_scale_sparse[no_clip-mask] ________________________
[gw5] linux -- Python 3.13.6 /nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/bin/python3.13

    @pytest.mark.parametrize(
        ("mask_obs", "x", "x_scaled", "x_clipped"),
        [
            pytest.param(
                None, X_original, X_scaled_original, X_scaled_original_clipped, id="no_mask"
            ),
            pytest.param(
                np.array((0, 0, 1, 1, 1, 0, 0), dtype=bool),
                X_for_mask,
                X_scaled_for_mask,
                X_scaled_for_mask_clipped,
                id="mask",
            ),
        ],
    )
    @pytest.mark.parametrize("clip", [False, True], ids=["no_clip", "clip"])
    def test_scale_sparse(*, mask_obs, x, x_scaled, x_clipped, clip):
        max_value, expected = (1, x_clipped) if clip else (None, x_scaled)
        adata = AnnData(sparse.csr_matrix(x).astype(np.float32))  # noqa: TID251
>       sc.pp.scale(adata, mask_obs=mask_obs, zero_center=False, max_value=max_value)

tests/test_scaling.py:146: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/_utils/__init__.py:151: in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
/nix/store/jqrgjm331sgc61528d5wghxcbkxnkqgr-python3.13-legacy-api-wrap-1.4.1/lib/python3.13/site-packages/legacy_api_wrap/__init__.py:82: in fn_compatible
    return fn(*args_all, **kw)
           ^^^^^^^^^^^^^^^^^^^
/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/functools.py:934: in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_scale.py:312: in scale_anndata
    X, adata.var[str_mean_std[0]], adata.var[str_mean_std[1]] = scale(
/nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/_utils/__init__.py:151: in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
/nix/store/jqrgjm331sgc61528d5wghxcbkxnkqgr-python3.13-legacy-api-wrap-1.4.1/lib/python3.13/site-packages/legacy_api_wrap/__init__.py:82: in fn_compatible
    return fn(*args_all, **kw)
           ^^^^^^^^^^^^^^^^^^^
/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/functools.py:934: in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_scale.py:190: in scale_array
    return scale_array_masked(
/nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_scale.py:245: in scale_array_masked
    mean, var = _get_mean_var(x[mask_obs, :])
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py:38: in _get_mean_var
    mean, var = sparse_mean_variance_axis(X, axis=axis)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py:83: in sparse_mean_variance_axis
    return sparse_mean_var_minor_axis(
/nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/_compat.py:170: in wrapper
    return fns[parallel](*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/nix/store/13j4idr9i9pwsq0y71c9c62ggp7g3q74-python3.13-numba-0.62.0-rc1/lib/python3.13/site-packages/numba/core/dispatcher.py:424: in _compile_for_args
    error_rewrite(e, 'typing')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

e = TypingError('Failed in nopython mode pipeline (step: native parfor lowering)\nFailed in full_parfor_gufunc mode pipeli...-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (107)\nDuring: Pass native_parfor_lowering')
issue_type = 'typing'

    def error_rewrite(e, issue_type):
        """
        Rewrite and raise Exception `e` with help supplied based on the
        specified issue_type.
        """
        if config.SHOW_HELP:
            help_msg = errors.error_extras[issue_type]
            e.patch_message('\n'.join((str(e).rstrip(), help_msg)))
        if config.FULL_TRACEBACKS:
            raise e
        else:
>           raise e.with_traceback(None)
E           numba.core.errors.TypingError: Failed in nopython mode pipeline (step: native parfor lowering)
E           Failed in full_parfor_gufunc mode pipeline (step: nopython frontend)
E           No implementation of function Function(<class 'range'>) found for signature:
E            
E            >>> range(uint64, int64, int64)
E            
E           There are 2 candidate implementations:
E            - Of which 2 did not match due to:
E            Type Restricted Function in function 'range': File: unknown: Line unknown.
E              With argument(s): '(uint64, int64, int64)':
E             No match for registered cases:
E              * (int32,) -> range_state_int32
E              * (int32, int32) -> range_state_int32
E              * (int32, int32, int32) -> range_state_int32
E              * (int64,) -> range_state_int64
E              * (int64, int64) -> range_state_int64
E              * (int64, int64, int64) -> range_state_int64
E              * (uint64,) -> range_state_uint64
E              * (uint64, uint64) -> range_state_uint64
E              * (uint64, uint64, uint64) -> range_state_uint64
E           
E           During: resolving callee type: Function(<class 'range'>)
E           During: typing of call at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (108)
E           
E           File "../../nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py", line 108:
E           def sparse_mean_var_minor_axis(
E               <source elided>
E               for i in numba.prange(n_threads):
E                   for r in range(i, rows, n_threads):
E                   ^
E           
E           During: Pass nopython_type_inference
E           During: lowering "id=7[LoopNest(index_variable = parfor_index.54, range = (0, n_threads, 1))]{354: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (112)>, 290: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (108)>, 260: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (107)>, 358: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (113)>, 330: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (109)>, 430: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (109)>, 334: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (109)>, 438: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (109)>, 446: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (108)>, 286: <ir.Block at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (108)>}Var(parfor_index.54, _utils.py:107)" at /nix/store/rfhdmynnh5p039nz4z7483qjmma4x8y5-python3.13-scanpy-1.11.4/lib/python3.13/site-packages/scanpy/preprocessing/_utils.py (107)
E           During: Pass native_parfor_lowering

/nix/store/13j4idr9i9pwsq0y71c9c62ggp7g3q74-python3.13-numba-0.62.0-rc1/lib/python3.13/site-packages/numba/core/dispatcher.py:365: TypingError

Versions

N/A

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions