Skip to content

Conversation

flying-sheep
Copy link
Member

@flying-sheep flying-sheep commented Oct 9, 2024

TODO:

@flying-sheep flying-sheep changed the title WIP Unify X and layers Oct 9, 2024
Copy link

codecov bot commented Oct 9, 2024

❌ 156 Tests Failed:

Tests completed Failed Passed Skipped
6826 156 6670 1186
View the top 3 failed test(s) by shortest run time
tests.test_deprecations::test_dtype_warning
Stack Traces | 0.002s run time
#x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_dtype_warning#x1B[39;49;00m():#x1B[90m#x1B[39;49;00m
        #x1B[90m# Tests a warning is thrown#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        #x1B[94mwith#x1B[39;49;00m pytest.warns(#x1B[96mFutureWarning#x1B[39;49;00m):#x1B[90m#x1B[39;49;00m
>           a = AnnData(np.ones((#x1B[94m3#x1B[39;49;00m, #x1B[94m3#x1B[39;49;00m)), dtype=np.float32)#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/test_deprecations.py#x1B[0m:81: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args_all = (<[AttributeError("'AnnData' object has no attribute '_is_view'") raised in repr()] AnnData object at 0x7fcca939e090>, array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]]))
kw = {'dtype': <class 'numpy.float32'>}

    #x1B[0m#x1B[37m@wraps#x1B[39;49;00m(fn)#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mfn_compatible#x1B[39;49;00m(*args_all: P.args, **kw: P.kwargs) -> R:#x1B[90m#x1B[39;49;00m
        #x1B[94mif#x1B[39;49;00m #x1B[96mlen#x1B[39;49;00m(args_all) <= n_positional:#x1B[90m#x1B[39;49;00m
>           #x1B[94mreturn#x1B[39;49;00m fn(*args_all, **kw)#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE           TypeError: AnnData.__init__() got an unexpected keyword argument 'dtype'#x1B[0m

#x1B[1m#x1B[31m../../../..../anndata/88DSKUwu/hatch-test.pre/lib/python3.13.../site-packages/legacy_api_wrap/__init__.py#x1B[0m:82: TypeError

#x1B[33mDuring handling of the above exception, another exception occurred:#x1B[0m

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_dtype_warning#x1B[39;49;00m():#x1B[90m#x1B[39;49;00m
        #x1B[90m# Tests a warning is thrown#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
>       #x1B[94mwith#x1B[39;49;00m pytest.warns(#x1B[96mFutureWarning#x1B[39;49;00m):#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       Failed: DID NOT WARN. No warnings of type (<class 'FutureWarning'>,) were emitted.#x1B[0m
#x1B[1m#x1B[31mE        Emitted warnings: [].#x1B[0m

#x1B[1m#x1B[31mtests/test_deprecations.py#x1B[0m:80: Failed
tests.test_views::test_set_scalar_subset_X[np_array-single_int_subset]
Stack Traces | 0.003s run time
matrix_type = <function asarray at 0x7fcce24ebce0>
subset_func = <function single_int_subset at 0x7fccd7106700>

    #x1B[0m#x1B[37m@IGNORE_SPARSE_EFFICIENCY_WARNING#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_set_scalar_subset_X#x1B[39;49;00m(matrix_type, subset_func):#x1B[90m#x1B[39;49;00m
        adata = ad.AnnData(matrix_type(np.zeros((#x1B[94m10#x1B[39;49;00m, #x1B[94m10#x1B[39;49;00m))))#x1B[90m#x1B[39;49;00m
        orig_X_val = adata.X.copy()#x1B[90m#x1B[39;49;00m
        subset_idx = subset_func(adata.obs_names)#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        adata_subset = adata[subset_idx, :]#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
>       adata_subset.X = #x1B[94m1#x1B[39;49;00m#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/test_views.py#x1B[0m:390: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
#x1B[1m#x1B[.../anndata/_core/anndata.py#x1B[0m:595: in X
    #x1B[0m#x1B[96mself#x1B[39;49;00m.layers[#x1B[94mNone#x1B[39;49;00m] = value#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[.../anndata/_core/aligned_mapping.py#x1B[0m:174: in __setitem__
    #x1B[0mvalue = #x1B[96mself#x1B[39;49;00m._validate_value(value, key)  #x1B[90m# Validate before mutating#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[.../anndata/_core/aligned_mapping.py#x1B[0m:86: in _validate_value
    #x1B[0m#x1B[94mif#x1B[39;49;00m #x1B[96mself#x1B[39;49;00m.parent.shape[axis] == axis_len(val, i):#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31m../../../..../uv/python/cpython-3.13.7-linux-x86_64-gnu/lib/python3.13/functools.py#x1B[0m:934: in wrapper
    #x1B[0m#x1B[94mreturn#x1B[39;49;00m dispatch(args[#x1B[94m0#x1B[39;49;00m].#x1B[91m__class__#x1B[39;49;00m)(*args, **kw)#x1B[90m#x1B[39;49;00m
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

x = 1, axis = 0

    #x1B[0m#x1B[37m@singledispatch#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92maxis_len#x1B[39;49;00m(x, axis: Literal[#x1B[94m0#x1B[39;49;00m, #x1B[94m1#x1B[39;49;00m]) -> #x1B[96mint#x1B[39;49;00m | #x1B[94mNone#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
    #x1B[90m    #x1B[39;49;00m#x1B[33m"""\#x1B[39;49;00m
    #x1B[33m    Return the size of an array in dimension `axis`.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    Returns None if `x` is an awkward array with variable length in the requested dimension.#x1B[39;49;00m
    #x1B[33m    """#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
>       #x1B[94mreturn#x1B[39;49;00m x.shape[axis]#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       AttributeError: 'int' object has no attribute 'shape'#x1B[0m

#x1B[1m#x1B[31msrc/anndata/utils.py#x1B[0m:118: AttributeError
tests.test_views::test_set_scalar_subset_X[np_array-slice_int_subset]
Stack Traces | 0.003s run time
matrix_type = <function asarray at 0x7fcce24ebce0>
subset_func = <function slice_int_subset at 0x7fccd7106660>

    #x1B[0m#x1B[37m@IGNORE_SPARSE_EFFICIENCY_WARNING#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_set_scalar_subset_X#x1B[39;49;00m(matrix_type, subset_func):#x1B[90m#x1B[39;49;00m
        adata = ad.AnnData(matrix_type(np.zeros((#x1B[94m10#x1B[39;49;00m, #x1B[94m10#x1B[39;49;00m))))#x1B[90m#x1B[39;49;00m
        orig_X_val = adata.X.copy()#x1B[90m#x1B[39;49;00m
        subset_idx = subset_func(adata.obs_names)#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        adata_subset = adata[subset_idx, :]#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
>       adata_subset.X = #x1B[94m1#x1B[39;49;00m#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/test_views.py#x1B[0m:390: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
#x1B[1m#x1B[.../anndata/_core/anndata.py#x1B[0m:595: in X
    #x1B[0m#x1B[96mself#x1B[39;49;00m.layers[#x1B[94mNone#x1B[39;49;00m] = value#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[.../anndata/_core/aligned_mapping.py#x1B[0m:174: in __setitem__
    #x1B[0mvalue = #x1B[96mself#x1B[39;49;00m._validate_value(value, key)  #x1B[90m# Validate before mutating#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[.../anndata/_core/aligned_mapping.py#x1B[0m:86: in _validate_value
    #x1B[0m#x1B[94mif#x1B[39;49;00m #x1B[96mself#x1B[39;49;00m.parent.shape[axis] == axis_len(val, i):#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31m../../../..../uv/python/cpython-3.13.7-linux-x86_64-gnu/lib/python3.13/functools.py#x1B[0m:934: in wrapper
    #x1B[0m#x1B[94mreturn#x1B[39;49;00m dispatch(args[#x1B[94m0#x1B[39;49;00m].#x1B[91m__class__#x1B[39;49;00m)(*args, **kw)#x1B[90m#x1B[39;49;00m
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

x = 1, axis = 0

    #x1B[0m#x1B[37m@singledispatch#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92maxis_len#x1B[39;49;00m(x, axis: Literal[#x1B[94m0#x1B[39;49;00m, #x1B[94m1#x1B[39;49;00m]) -> #x1B[96mint#x1B[39;49;00m | #x1B[94mNone#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
    #x1B[90m    #x1B[39;49;00m#x1B[33m"""\#x1B[39;49;00m
    #x1B[33m    Return the size of an array in dimension `axis`.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    Returns None if `x` is an awkward array with variable length in the requested dimension.#x1B[39;49;00m
    #x1B[33m    """#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
>       #x1B[94mreturn#x1B[39;49;00m x.shape[axis]#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       AttributeError: 'int' object has no attribute 'shape'#x1B[0m

#x1B[1m#x1B[31msrc/anndata/utils.py#x1B[0m:118: AttributeError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@ilan-gold ilan-gold modified the milestones: 0.12.0, 0.12.1, 0.13.0 Jul 16, 2025
@ilan-gold ilan-gold mentioned this pull request Jul 29, 2025
4 tasks
@ilan-gold
Copy link
Contributor

ilan-gold commented Aug 22, 2025

So re: the backed question, I think the answer is not to get rid of it, but to clarify its behavior. To do that, I think we should merge #1927 first, which may include a breaking change. If we stop allowing overriding of on-disk stores (which currently relies on inheritance form scipy.sparse private methods), then this question becomes much more simplified.

The next step after #1927 would probably be to simplify it. From what I can tell, the reaosn we need to track if the file is open or not is because if writing. If everything were purely read-only, I think it would be less of an issue.

My vision there would be in "backed" mode (after the two above points are implemented), we would simply take the X attribute on-disk, and read it in using ad.io.sparse_dataset with mode="r" and call it a day. That's how layers and other elements handle sparse_dataset so X shouldn't be different


@X.setter
def X(self, value: XDataType | None): # noqa: PLR0912
if value is None:
Copy link
Contributor

@ilan-gold ilan-gold Aug 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a lot of this deleted logic contains things that layers can't currently do. For example, overriding the backing X; currently, if you try to override a part of a view of a layers, it will just actualize and not override the old data. But if you do adata_view.X = 1 it will fill ones in to the parent AnnData object. I'm not sure what the history is there, but it accounts for a pretty big discrepancy in functionality

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.

concat when some values of X are None Unification of X and layers

2 participants