Skip to content

feat: accessors#2290

Open
flying-sheep wants to merge 51 commits intomainfrom
pa/acc
Open

feat: accessors#2290
flying-sheep wants to merge 51 commits intomainfrom
pa/acc

Conversation

@flying-sheep
Copy link
Member

@flying-sheep flying-sheep commented Jan 8, 2026

User API design

  1. create AdPath instances by descending into a central accessor constant A:
    (A[:, :], lambda ad: ad.X),
    (A[:, "gene-3"], lambda ad: ad[:, "gene-3"].X.flatten()),
    (A["cell-5", :], lambda ad: ad["cell-5"].X.flatten()),
    (A.obs["type"], lambda ad: ad.obs["type"]),
    (A.obs.index, lambda ad: ad.obs.index.values),
    (A.layers["a"][:, :], lambda ad: ad.layers["a"].copy().toarray()),
    (
    A.layers["a"][:, "gene-18"],
    lambda ad: ad[:, "gene-18"].layers["a"].copy().toarray().flatten(),
    ),
    (
    A.layers["a"]["cell-77", :],
    lambda ad: ad["cell-77"].layers["a"].copy().toarray().flatten(),
    ),
    (A.obsm["umap"][0], lambda ad: ad.obsm["umap"][:, 0]),
    (A.obsm["umap"][1], lambda ad: ad.obsm["umap"][:, 1]),
    (A.varp["cons"]["gene-46", :], lambda ad: ad.varp["cons"][46, :].toarray()),
    (A.varp["cons"][:, "gene-46"], lambda ad: ad.varp["cons"][:, 46].toarray()),
  2. Inspect AdPath instance, e.g. to figure out which axes the resulting vector spans:
    pytest.param(A.obsm["c"][:, 0], {"obs"}, id="obsm"),
    pytest.param(A.varp["d"][:, :], ("var", "var"), id="varp"),
    pytest.param(A.varp["d"][:, "c2"], {"var"}, id="varp-col"),
    ],
    )
    def test_axes(ad_path: AdPath, axes: Collection[Literal["obs", "var"]]) -> None:
    assert ad_path.axes == axes
  3. Call AdPath instance to extract a vector (see 1. for examples)

subclassing

… is a direct goal of this, as people should be able to use AdPath subclasses. This means that

  1. the AdPath API is minimal and inspection can be done through .acc (could be even more minimal by just putting it all into a container?):
    acc: VecAcc[Self, I]
    idx: I
    @cached_property
    def axes(self) -> Axes:
  2. It’s trivial to create a new AdAcc constant that produces your own AdPath subclass:
    A = AdAcc(path_class=AdPath)
  3. The data flow is easy to understand:
    1. User uses VecAcc.__getitem__ to get an AdPath or a list of them. In that process,
      1. __getitem__ calls process_idx which verifies and simplifies the index
      2. axes, __repr__, and idx_repr get called too to validate things work
    2. The public API of AdPath can be used, which basically just delegates to VecAcc’s axes, __repr__, idx_repr, and __call__

So in the end everything except for __call__ is validated, i.e. VecAcc.__getitem__ raises exceptions on misuse

class VecAcc[P: AdPath[I], I](abc.ABC): # type: ignore
path_class: type[P]
def process_idx(self, idx: Any, /) -> I:
self.axes(idx)
return idx
def __getitem__(self, idx: Any, /) -> P:
idx = self.process_idx(idx)
return self.path_class(self, idx) # type: ignore
@abc.abstractmethod
def axes(self, idx: I, /) -> Axes: ...
@abc.abstractmethod
def __repr__(self, /) -> str: ...
@abc.abstractmethod
def idx_repr(self, idx: I, /) -> str: ...
@abc.abstractmethod
def __call__(self, adata: AnnData, idx: I, /) -> Vector: ...

TODO:

  • serialization
  • docs (especially data flow)
    • nomenclature: “vector” vs “array”, “accessor”, “vector accessor”, “reference”, “path”, … get it straight!
      Especially since we already call these accessors! Instance namespaces (adata.custom) #1869
  • Array types: fix typing and test with all array types we support
  • improve __contains__ so it doesn’t try to access the array
  • add JSON schema
    • also add it to docs (linked from from_json/to_json)
    • and test it
  • terminology: axis → dim
  • (maybe) runtime autocompletion (__dir__)

@codecov
Copy link

codecov bot commented Jan 8, 2026

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
6173 3 6170 1162
View the top 3 failed test(s) by shortest run time
tests.accessors.test_get::test_get_values[A.obs.index-pd.DataFrame]
Stack Traces | 0.003s run time
adata = AnnData object with n_obs × n_vars = 100 × 50
    obs: 'type'
    var: 'grp'
    obsm: 'umap'
    layers: 'a'
    varp: 'cons'
request = <SubRequest 'get_test_params' for <Function test_get_values[A.obs.index-pd.DataFrame]>>

    #x1B[0m#x1B[37m@pytest#x1B[39;49;00m.fixture(#x1B[90m#x1B[39;49;00m
        params=[#x1B[90m#x1B[39;49;00m
            pytest.param(#x1B[90m#x1B[39;49;00m
                (ad_ref, ad_expected, *typ.values, convert),#x1B[90m#x1B[39;49;00m
                marks=typ.marks,#x1B[90m#x1B[39;49;00m
                #x1B[96mid#x1B[39;49;00m=#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mad_ref#x1B[33m}#x1B[39;49;00m#x1B[33m-#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mtyp.id#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m,#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m paths, types, convert #x1B[95min#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
                (ND_PATHS, ND_TYPES, convert_ndarrays),#x1B[90m#x1B[39;49;00m
                (DF_PATHS, DF_TYPES, convert_dataframes),#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m ad_ref, ad_expected #x1B[95min#x1B[39;49;00m paths#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m typ #x1B[95min#x1B[39;49;00m types#x1B[90m#x1B[39;49;00m
        ]#x1B[90m#x1B[39;49;00m
    )#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mget_test_params#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
        adata: AnnData, request: pytest.FixtureRequest#x1B[90m#x1B[39;49;00m
    ) -> #x1B[96mtuple#x1B[39;49;00m[AnnData, AdRef, #x1B[96mtype#x1B[39;49;00m[Array], Array]:#x1B[90m#x1B[39;49;00m
        ad_ref, ad_expected, convert_array, type_expected_1d, type_expected_2d, convert = (#x1B[90m#x1B[39;49;00m
            request.param#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m
        convert(adata, convert_array)#x1B[90m#x1B[39;49;00m
        #x1B[94mreturn#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
            adata,#x1B[90m#x1B[39;49;00m
            ad_ref,#x1B[90m#x1B[39;49;00m
            type_expected_1d #x1B[94mif#x1B[39;49;00m #x1B[96mlen#x1B[39;49;00m(ad_ref.dims) == #x1B[94m1#x1B[39;49;00m #x1B[94melse#x1B[39;49;00m type_expected_2d,#x1B[90m#x1B[39;49;00m
>           _expected2np(ad_expected(adata), ad_ref),#x1B[90m#x1B[39;49;00m
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:185: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

expected = <ArrowStringArray>
[ 'cell-0',  'cell-1',  'cell-2',  'cell-3',  'cell-4',  'cell-5',  'cell-6',
  'cell-7',  'cell-8'...l-91', 'cell-92', 'cell-93', 'cell-94', 'cell-95', 'cell-96', 'cell-97',
 'cell-98', 'cell-99']
Length: 100, dtype: str
ad_ref = A.obs.index

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92m_expected2np#x1B[39;49;00m(expected: Array, ad_ref: AdRef, /) -> np.ndarray:#x1B[90m#x1B[39;49;00m
        ndim = #x1B[96mlen#x1B[39;49;00m(ad_ref.dims)#x1B[90m#x1B[39;49;00m
        #x1B[94mmatch#x1B[39;49;00m expected:#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m np.ndarray():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m expected.flatten() #x1B[94mif#x1B[39;49;00m ndim == #x1B[94m1#x1B[39;49;00m #x1B[94melse#x1B[39;49;00m expected#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m sp.sparray() | sp.spmatrix():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m _expected2np(expected.toarray(), ad_ref)#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m pd.Series() | XDataArray():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m expected.to_numpy()#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m DaskArray():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m _expected2np(expected.compute(), ad_ref)#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m CupyArray() | CupyCSRMatrix() | CupyCSCMatrix():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m _expected2np(expected.get(), ad_ref)#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[94m_#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
>               pytest.fail(#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33munhandled expected type #x1B[39;49;00m#x1B[33m{#x1B[39;49;00m#x1B[96mtype#x1B[39;49;00m(expected)#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE               Failed: unhandled expected type <class 'pandas.arrays.ArrowStringArray'>#x1B[0m

#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:156: Failed
tests.accessors.test_get::test_get_values[A.obsm['umap'][:, 0]-sp.csr_array]
Stack Traces | 0.006s run time
adata = AnnData object with n_obs × n_vars = 100 × 50
    obs: 'type'
    var: 'grp'
    obsm: 'umap'
    layers: 'a'
    varp: 'cons'
request = <SubRequest 'get_test_params' for <Function test_get_values[A.obsm['umap'][:, 0]-sp.csr_array]>>

    #x1B[0m#x1B[37m@pytest#x1B[39;49;00m.fixture(#x1B[90m#x1B[39;49;00m
        params=[#x1B[90m#x1B[39;49;00m
            pytest.param(#x1B[90m#x1B[39;49;00m
                (ad_ref, ad_expected, *typ.values, convert),#x1B[90m#x1B[39;49;00m
                marks=typ.marks,#x1B[90m#x1B[39;49;00m
                #x1B[96mid#x1B[39;49;00m=#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mad_ref#x1B[33m}#x1B[39;49;00m#x1B[33m-#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mtyp.id#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m,#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m paths, types, convert #x1B[95min#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
                (ND_PATHS, ND_TYPES, convert_ndarrays),#x1B[90m#x1B[39;49;00m
                (DF_PATHS, DF_TYPES, convert_dataframes),#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m ad_ref, ad_expected #x1B[95min#x1B[39;49;00m paths#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m typ #x1B[95min#x1B[39;49;00m types#x1B[90m#x1B[39;49;00m
        ]#x1B[90m#x1B[39;49;00m
    )#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mget_test_params#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
        adata: AnnData, request: pytest.FixtureRequest#x1B[90m#x1B[39;49;00m
    ) -> #x1B[96mtuple#x1B[39;49;00m[AnnData, AdRef, #x1B[96mtype#x1B[39;49;00m[Array], Array]:#x1B[90m#x1B[39;49;00m
        ad_ref, ad_expected, convert_array, type_expected_1d, type_expected_2d, convert = (#x1B[90m#x1B[39;49;00m
            request.param#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m
        convert(adata, convert_array)#x1B[90m#x1B[39;49;00m
        #x1B[94mreturn#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
            adata,#x1B[90m#x1B[39;49;00m
            ad_ref,#x1B[90m#x1B[39;49;00m
            type_expected_1d #x1B[94mif#x1B[39;49;00m #x1B[96mlen#x1B[39;49;00m(ad_ref.dims) == #x1B[94m1#x1B[39;49;00m #x1B[94melse#x1B[39;49;00m type_expected_2d,#x1B[90m#x1B[39;49;00m
>           _expected2np(ad_expected(adata), ad_ref),#x1B[90m#x1B[39;49;00m
                         ^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:185: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:48: in <lambda>
    #x1B[0m(A.obsm[#x1B[33m"#x1B[39;49;00m#x1B[33mumap#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m][#x1B[94m0#x1B[39;49;00m], #x1B[94mlambda#x1B[39;49;00m ad: ad.obsm[#x1B[33m"#x1B[39;49;00m#x1B[33mumap#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m][:, #x1B[94m0#x1B[39;49;00m]),#x1B[90m#x1B[39;49;00m
                                   ^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31m../../../..../anndata/88DSKUwu/hatch-test.min/lib/python3.12.../scipy/sparse/_index.py#x1B[0m:69: in __getitem__
    #x1B[0m#x1B[96mself#x1B[39;49;00m._raise_on_1d_array_slice()#x1B[90m#x1B[39;49;00m
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <100x2 sparse array of type '<class 'numpy.float64'>'
	with 200 stored elements in Compressed Sparse Row format>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92m_raise_on_1d_array_slice#x1B[39;49;00m(#x1B[96mself#x1B[39;49;00m):#x1B[90m#x1B[39;49;00m
    #x1B[90m    #x1B[39;49;00m#x1B[33m"""We do not currently support 1D sparse arrays.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    This function is called each time that a 1D array would#x1B[39;49;00m
    #x1B[33m    result, raising an error instead.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    Once 1D sparse arrays are implemented, it should be removed.#x1B[39;49;00m
    #x1B[33m    """#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        #x1B[94mfrom#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[04m#x1B[96mscipy#x1B[39;49;00m#x1B[04m#x1B[96m.#x1B[39;49;00m#x1B[04m#x1B[96msparse#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[94mimport#x1B[39;49;00m sparray#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[94mif#x1B[39;49;00m #x1B[96misinstance#x1B[39;49;00m(#x1B[96mself#x1B[39;49;00m, sparray):#x1B[90m#x1B[39;49;00m
>           #x1B[94mraise#x1B[39;49;00m #x1B[96mNotImplementedError#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
                #x1B[33m'#x1B[39;49;00m#x1B[33mWe have not yet implemented 1D sparse slices; #x1B[39;49;00m#x1B[33m'#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                #x1B[33m'#x1B[39;49;00m#x1B[33mplease index using explicit indices, e.g. `x[:, [0]]`#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE           NotImplementedError: We have not yet implemented 1D sparse slices; please index using explicit indices, e.g. `x[:, [0]]`#x1B[0m

#x1B[1m#x1B[31m../../../..../anndata/88DSKUwu/hatch-test.min/lib/python3.12.../scipy/sparse/_index.py#x1B[0m:46: NotImplementedError
tests.accessors.test_get::test_get_values[A.obsm['umap'][:, 1]-sp.csr_array]
Stack Traces | 0.006s run time
adata = AnnData object with n_obs × n_vars = 100 × 50
    obs: 'type'
    var: 'grp'
    obsm: 'umap'
    layers: 'a'
    varp: 'cons'
request = <SubRequest 'get_test_params' for <Function test_get_values[A.obsm['umap'][:, 1]-sp.csr_array]>>

    #x1B[0m#x1B[37m@pytest#x1B[39;49;00m.fixture(#x1B[90m#x1B[39;49;00m
        params=[#x1B[90m#x1B[39;49;00m
            pytest.param(#x1B[90m#x1B[39;49;00m
                (ad_ref, ad_expected, *typ.values, convert),#x1B[90m#x1B[39;49;00m
                marks=typ.marks,#x1B[90m#x1B[39;49;00m
                #x1B[96mid#x1B[39;49;00m=#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mad_ref#x1B[33m}#x1B[39;49;00m#x1B[33m-#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mtyp.id#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m,#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m paths, types, convert #x1B[95min#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
                (ND_PATHS, ND_TYPES, convert_ndarrays),#x1B[90m#x1B[39;49;00m
                (DF_PATHS, DF_TYPES, convert_dataframes),#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m ad_ref, ad_expected #x1B[95min#x1B[39;49;00m paths#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m typ #x1B[95min#x1B[39;49;00m types#x1B[90m#x1B[39;49;00m
        ]#x1B[90m#x1B[39;49;00m
    )#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mget_test_params#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
        adata: AnnData, request: pytest.FixtureRequest#x1B[90m#x1B[39;49;00m
    ) -> #x1B[96mtuple#x1B[39;49;00m[AnnData, AdRef, #x1B[96mtype#x1B[39;49;00m[Array], Array]:#x1B[90m#x1B[39;49;00m
        ad_ref, ad_expected, convert_array, type_expected_1d, type_expected_2d, convert = (#x1B[90m#x1B[39;49;00m
            request.param#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m
        convert(adata, convert_array)#x1B[90m#x1B[39;49;00m
        #x1B[94mreturn#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
            adata,#x1B[90m#x1B[39;49;00m
            ad_ref,#x1B[90m#x1B[39;49;00m
            type_expected_1d #x1B[94mif#x1B[39;49;00m #x1B[96mlen#x1B[39;49;00m(ad_ref.dims) == #x1B[94m1#x1B[39;49;00m #x1B[94melse#x1B[39;49;00m type_expected_2d,#x1B[90m#x1B[39;49;00m
>           _expected2np(ad_expected(adata), ad_ref),#x1B[90m#x1B[39;49;00m
                         ^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:185: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:49: in <lambda>
    #x1B[0m(A.obsm[#x1B[33m"#x1B[39;49;00m#x1B[33mumap#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m][#x1B[94m1#x1B[39;49;00m], #x1B[94mlambda#x1B[39;49;00m ad: ad.obsm[#x1B[33m"#x1B[39;49;00m#x1B[33mumap#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m][:, #x1B[94m1#x1B[39;49;00m]),#x1B[90m#x1B[39;49;00m
                                   ^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31m../../../..../anndata/88DSKUwu/hatch-test.min/lib/python3.12.../scipy/sparse/_index.py#x1B[0m:69: in __getitem__
    #x1B[0m#x1B[96mself#x1B[39;49;00m._raise_on_1d_array_slice()#x1B[90m#x1B[39;49;00m
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <100x2 sparse array of type '<class 'numpy.float64'>'
	with 200 stored elements in Compressed Sparse Row format>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92m_raise_on_1d_array_slice#x1B[39;49;00m(#x1B[96mself#x1B[39;49;00m):#x1B[90m#x1B[39;49;00m
    #x1B[90m    #x1B[39;49;00m#x1B[33m"""We do not currently support 1D sparse arrays.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    This function is called each time that a 1D array would#x1B[39;49;00m
    #x1B[33m    result, raising an error instead.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    Once 1D sparse arrays are implemented, it should be removed.#x1B[39;49;00m
    #x1B[33m    """#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        #x1B[94mfrom#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[04m#x1B[96mscipy#x1B[39;49;00m#x1B[04m#x1B[96m.#x1B[39;49;00m#x1B[04m#x1B[96msparse#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[94mimport#x1B[39;49;00m sparray#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[94mif#x1B[39;49;00m #x1B[96misinstance#x1B[39;49;00m(#x1B[96mself#x1B[39;49;00m, sparray):#x1B[90m#x1B[39;49;00m
>           #x1B[94mraise#x1B[39;49;00m #x1B[96mNotImplementedError#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
                #x1B[33m'#x1B[39;49;00m#x1B[33mWe have not yet implemented 1D sparse slices; #x1B[39;49;00m#x1B[33m'#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                #x1B[33m'#x1B[39;49;00m#x1B[33mplease index using explicit indices, e.g. `x[:, [0]]`#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE           NotImplementedError: We have not yet implemented 1D sparse slices; please index using explicit indices, e.g. `x[:, [0]]`#x1B[0m

#x1B[1m#x1B[31m../../../..../anndata/88DSKUwu/hatch-test.min/lib/python3.12.../scipy/sparse/_index.py#x1B[0m:46: NotImplementedError
tests.accessors.test_get::test_get_values[A.obs.index-xr.Dataset]
Stack Traces | 0.007s run time
adata = AnnData object with n_obs × n_vars = 100 × 50
    obs: 'type'
    var: 'grp'
    obsm: 'umap'
    layers: 'a'
    varp: 'cons'
request = <SubRequest 'get_test_params' for <Function test_get_values[A.obs.index-xr.Dataset]>>

    #x1B[0m#x1B[37m@pytest#x1B[39;49;00m.fixture(#x1B[90m#x1B[39;49;00m
        params=[#x1B[90m#x1B[39;49;00m
            pytest.param(#x1B[90m#x1B[39;49;00m
                (ad_ref, ad_expected, *typ.values, convert),#x1B[90m#x1B[39;49;00m
                marks=typ.marks,#x1B[90m#x1B[39;49;00m
                #x1B[96mid#x1B[39;49;00m=#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mad_ref#x1B[33m}#x1B[39;49;00m#x1B[33m-#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mtyp.id#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m,#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m paths, types, convert #x1B[95min#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
                (ND_PATHS, ND_TYPES, convert_ndarrays),#x1B[90m#x1B[39;49;00m
                (DF_PATHS, DF_TYPES, convert_dataframes),#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m ad_ref, ad_expected #x1B[95min#x1B[39;49;00m paths#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m typ #x1B[95min#x1B[39;49;00m types#x1B[90m#x1B[39;49;00m
        ]#x1B[90m#x1B[39;49;00m
    )#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mget_test_params#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
        adata: AnnData, request: pytest.FixtureRequest#x1B[90m#x1B[39;49;00m
    ) -> #x1B[96mtuple#x1B[39;49;00m[AnnData, AdRef, #x1B[96mtype#x1B[39;49;00m[Array], Array]:#x1B[90m#x1B[39;49;00m
        ad_ref, ad_expected, convert_array, type_expected_1d, type_expected_2d, convert = (#x1B[90m#x1B[39;49;00m
            request.param#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m
        convert(adata, convert_array)#x1B[90m#x1B[39;49;00m
        #x1B[94mreturn#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
            adata,#x1B[90m#x1B[39;49;00m
            ad_ref,#x1B[90m#x1B[39;49;00m
            type_expected_1d #x1B[94mif#x1B[39;49;00m #x1B[96mlen#x1B[39;49;00m(ad_ref.dims) == #x1B[94m1#x1B[39;49;00m #x1B[94melse#x1B[39;49;00m type_expected_2d,#x1B[90m#x1B[39;49;00m
>           _expected2np(ad_expected(adata), ad_ref),#x1B[90m#x1B[39;49;00m
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:185: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

expected = <ArrowStringArray>
[ 'cell-0',  'cell-1',  'cell-2',  'cell-3',  'cell-4',  'cell-5',  'cell-6',
  'cell-7',  'cell-8'...l-91', 'cell-92', 'cell-93', 'cell-94', 'cell-95', 'cell-96', 'cell-97',
 'cell-98', 'cell-99']
Length: 100, dtype: str
ad_ref = A.obs.index

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92m_expected2np#x1B[39;49;00m(expected: Array, ad_ref: AdRef, /) -> np.ndarray:#x1B[90m#x1B[39;49;00m
        ndim = #x1B[96mlen#x1B[39;49;00m(ad_ref.dims)#x1B[90m#x1B[39;49;00m
        #x1B[94mmatch#x1B[39;49;00m expected:#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m np.ndarray():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m expected.flatten() #x1B[94mif#x1B[39;49;00m ndim == #x1B[94m1#x1B[39;49;00m #x1B[94melse#x1B[39;49;00m expected#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m sp.sparray() | sp.spmatrix():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m _expected2np(expected.toarray(), ad_ref)#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m pd.Series() | XDataArray():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m expected.to_numpy()#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m DaskArray():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m _expected2np(expected.compute(), ad_ref)#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m CupyArray() | CupyCSRMatrix() | CupyCSCMatrix():#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m _expected2np(expected.get(), ad_ref)#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[94m_#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
>               pytest.fail(#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33munhandled expected type #x1B[39;49;00m#x1B[33m{#x1B[39;49;00m#x1B[96mtype#x1B[39;49;00m(expected)#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE               Failed: unhandled expected type <class 'pandas.arrays.ArrowStringArray'>#x1B[0m

#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:156: Failed
tests.accessors.test_get::test_get_values[A.varp['cons']['gene-46', :]-sp.csr_array]
Stack Traces | 0.008s run time
adata = AnnData object with n_obs × n_vars = 100 × 50
    obs: 'type'
    var: 'grp'
    obsm: 'umap'
    layers: 'a'
    varp: 'cons'
request = <SubRequest 'get_test_params' for <Function test_get_values[A.varp['cons']['gene-46', :]-sp.csr_array]>>

    #x1B[0m#x1B[37m@pytest#x1B[39;49;00m.fixture(#x1B[90m#x1B[39;49;00m
        params=[#x1B[90m#x1B[39;49;00m
            pytest.param(#x1B[90m#x1B[39;49;00m
                (ad_ref, ad_expected, *typ.values, convert),#x1B[90m#x1B[39;49;00m
                marks=typ.marks,#x1B[90m#x1B[39;49;00m
                #x1B[96mid#x1B[39;49;00m=#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mad_ref#x1B[33m}#x1B[39;49;00m#x1B[33m-#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mtyp.id#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m,#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m paths, types, convert #x1B[95min#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
                (ND_PATHS, ND_TYPES, convert_ndarrays),#x1B[90m#x1B[39;49;00m
                (DF_PATHS, DF_TYPES, convert_dataframes),#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m ad_ref, ad_expected #x1B[95min#x1B[39;49;00m paths#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m typ #x1B[95min#x1B[39;49;00m types#x1B[90m#x1B[39;49;00m
        ]#x1B[90m#x1B[39;49;00m
    )#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mget_test_params#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
        adata: AnnData, request: pytest.FixtureRequest#x1B[90m#x1B[39;49;00m
    ) -> #x1B[96mtuple#x1B[39;49;00m[AnnData, AdRef, #x1B[96mtype#x1B[39;49;00m[Array], Array]:#x1B[90m#x1B[39;49;00m
        ad_ref, ad_expected, convert_array, type_expected_1d, type_expected_2d, convert = (#x1B[90m#x1B[39;49;00m
            request.param#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m
        convert(adata, convert_array)#x1B[90m#x1B[39;49;00m
        #x1B[94mreturn#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
            adata,#x1B[90m#x1B[39;49;00m
            ad_ref,#x1B[90m#x1B[39;49;00m
            type_expected_1d #x1B[94mif#x1B[39;49;00m #x1B[96mlen#x1B[39;49;00m(ad_ref.dims) == #x1B[94m1#x1B[39;49;00m #x1B[94melse#x1B[39;49;00m type_expected_2d,#x1B[90m#x1B[39;49;00m
>           _expected2np(ad_expected(adata), ad_ref),#x1B[90m#x1B[39;49;00m
                         ^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:185: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:50: in <lambda>
    #x1B[0m(A.varp[#x1B[33m"#x1B[39;49;00m#x1B[33mcons#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m][#x1B[33m"#x1B[39;49;00m#x1B[33mgene-46#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, :], #x1B[94mlambda#x1B[39;49;00m ad: ad.varp[#x1B[33m"#x1B[39;49;00m#x1B[33mcons#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m][#x1B[94m46#x1B[39;49;00m, :]),#x1B[90m#x1B[39;49;00m
                                              ^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31m../../../..../anndata/88DSKUwu/hatch-test.min/lib/python3.12.../scipy/sparse/_index.py#x1B[0m:59: in __getitem__
    #x1B[0m#x1B[96mself#x1B[39;49;00m._raise_on_1d_array_slice()#x1B[90m#x1B[39;49;00m
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <50x50 sparse array of type '<class 'numpy.float64'>'
	with 25 stored elements in Compressed Sparse Row format>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92m_raise_on_1d_array_slice#x1B[39;49;00m(#x1B[96mself#x1B[39;49;00m):#x1B[90m#x1B[39;49;00m
    #x1B[90m    #x1B[39;49;00m#x1B[33m"""We do not currently support 1D sparse arrays.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    This function is called each time that a 1D array would#x1B[39;49;00m
    #x1B[33m    result, raising an error instead.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    Once 1D sparse arrays are implemented, it should be removed.#x1B[39;49;00m
    #x1B[33m    """#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        #x1B[94mfrom#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[04m#x1B[96mscipy#x1B[39;49;00m#x1B[04m#x1B[96m.#x1B[39;49;00m#x1B[04m#x1B[96msparse#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[94mimport#x1B[39;49;00m sparray#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[94mif#x1B[39;49;00m #x1B[96misinstance#x1B[39;49;00m(#x1B[96mself#x1B[39;49;00m, sparray):#x1B[90m#x1B[39;49;00m
>           #x1B[94mraise#x1B[39;49;00m #x1B[96mNotImplementedError#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
                #x1B[33m'#x1B[39;49;00m#x1B[33mWe have not yet implemented 1D sparse slices; #x1B[39;49;00m#x1B[33m'#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                #x1B[33m'#x1B[39;49;00m#x1B[33mplease index using explicit indices, e.g. `x[:, [0]]`#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE           NotImplementedError: We have not yet implemented 1D sparse slices; please index using explicit indices, e.g. `x[:, [0]]`#x1B[0m

#x1B[1m#x1B[31m../../../..../anndata/88DSKUwu/hatch-test.min/lib/python3.12.../scipy/sparse/_index.py#x1B[0m:46: NotImplementedError
tests.accessors.test_get::test_get_values[A.varp['cons'][:, 'gene-46']-sp.csr_array]
Stack Traces | 0.008s run time
adata = AnnData object with n_obs × n_vars = 100 × 50
    obs: 'type'
    var: 'grp'
    obsm: 'umap'
    layers: 'a'
    varp: 'cons'
request = <SubRequest 'get_test_params' for <Function test_get_values[A.varp['cons'][:, 'gene-46']-sp.csr_array]>>

    #x1B[0m#x1B[37m@pytest#x1B[39;49;00m.fixture(#x1B[90m#x1B[39;49;00m
        params=[#x1B[90m#x1B[39;49;00m
            pytest.param(#x1B[90m#x1B[39;49;00m
                (ad_ref, ad_expected, *typ.values, convert),#x1B[90m#x1B[39;49;00m
                marks=typ.marks,#x1B[90m#x1B[39;49;00m
                #x1B[96mid#x1B[39;49;00m=#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mad_ref#x1B[33m}#x1B[39;49;00m#x1B[33m-#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mtyp.id#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m,#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m paths, types, convert #x1B[95min#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
                (ND_PATHS, ND_TYPES, convert_ndarrays),#x1B[90m#x1B[39;49;00m
                (DF_PATHS, DF_TYPES, convert_dataframes),#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m ad_ref, ad_expected #x1B[95min#x1B[39;49;00m paths#x1B[90m#x1B[39;49;00m
            #x1B[94mfor#x1B[39;49;00m typ #x1B[95min#x1B[39;49;00m types#x1B[90m#x1B[39;49;00m
        ]#x1B[90m#x1B[39;49;00m
    )#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mget_test_params#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
        adata: AnnData, request: pytest.FixtureRequest#x1B[90m#x1B[39;49;00m
    ) -> #x1B[96mtuple#x1B[39;49;00m[AnnData, AdRef, #x1B[96mtype#x1B[39;49;00m[Array], Array]:#x1B[90m#x1B[39;49;00m
        ad_ref, ad_expected, convert_array, type_expected_1d, type_expected_2d, convert = (#x1B[90m#x1B[39;49;00m
            request.param#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m
        convert(adata, convert_array)#x1B[90m#x1B[39;49;00m
        #x1B[94mreturn#x1B[39;49;00m (#x1B[90m#x1B[39;49;00m
            adata,#x1B[90m#x1B[39;49;00m
            ad_ref,#x1B[90m#x1B[39;49;00m
            type_expected_1d #x1B[94mif#x1B[39;49;00m #x1B[96mlen#x1B[39;49;00m(ad_ref.dims) == #x1B[94m1#x1B[39;49;00m #x1B[94melse#x1B[39;49;00m type_expected_2d,#x1B[90m#x1B[39;49;00m
>           _expected2np(ad_expected(adata), ad_ref),#x1B[90m#x1B[39;49;00m
                         ^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:185: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
#x1B[1m#x1B[31mtests/accessors/test_get.py#x1B[0m:51: in <lambda>
    #x1B[0m(A.varp[#x1B[33m"#x1B[39;49;00m#x1B[33mcons#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m][:, #x1B[33m"#x1B[39;49;00m#x1B[33mgene-46#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m], #x1B[94mlambda#x1B[39;49;00m ad: ad.varp[#x1B[33m"#x1B[39;49;00m#x1B[33mcons#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m][:, #x1B[94m46#x1B[39;49;00m]),#x1B[90m#x1B[39;49;00m
                                              ^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31m../../../..../anndata/88DSKUwu/hatch-test.min/lib/python3.12.../scipy/sparse/_index.py#x1B[0m:69: in __getitem__
    #x1B[0m#x1B[96mself#x1B[39;49;00m._raise_on_1d_array_slice()#x1B[90m#x1B[39;49;00m
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <50x50 sparse array of type '<class 'numpy.float64'>'
	with 25 stored elements in Compressed Sparse Row format>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92m_raise_on_1d_array_slice#x1B[39;49;00m(#x1B[96mself#x1B[39;49;00m):#x1B[90m#x1B[39;49;00m
    #x1B[90m    #x1B[39;49;00m#x1B[33m"""We do not currently support 1D sparse arrays.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    This function is called each time that a 1D array would#x1B[39;49;00m
    #x1B[33m    result, raising an error instead.#x1B[39;49;00m
    #x1B[33m#x1B[39;49;00m
    #x1B[33m    Once 1D sparse arrays are implemented, it should be removed.#x1B[39;49;00m
    #x1B[33m    """#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        #x1B[94mfrom#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[04m#x1B[96mscipy#x1B[39;49;00m#x1B[04m#x1B[96m.#x1B[39;49;00m#x1B[04m#x1B[96msparse#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[94mimport#x1B[39;49;00m sparray#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[94mif#x1B[39;49;00m #x1B[96misinstance#x1B[39;49;00m(#x1B[96mself#x1B[39;49;00m, sparray):#x1B[90m#x1B[39;49;00m
>           #x1B[94mraise#x1B[39;49;00m #x1B[96mNotImplementedError#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
                #x1B[33m'#x1B[39;49;00m#x1B[33mWe have not yet implemented 1D sparse slices; #x1B[39;49;00m#x1B[33m'#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                #x1B[33m'#x1B[39;49;00m#x1B[33mplease index using explicit indices, e.g. `x[:, [0]]`#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
            )#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE           NotImplementedError: We have not yet implemented 1D sparse slices; please index using explicit indices, e.g. `x[:, [0]]`#x1B[0m

#x1B[1m#x1B[31m../../../..../anndata/88DSKUwu/hatch-test.min/lib/python3.12.../scipy/sparse/_index.py#x1B[0m:46: NotImplementedError
tests.test_base::test_convenience
Stack Traces | 0.008s run time
#x1B[0m#x1B[37m@pytest#x1B[39;49;00m.mark.filterwarnings(#x1B[33m"#x1B[39;49;00m#x1B[33mignore:Use anndata.acc.A instead of:FutureWarning#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_convenience#x1B[39;49;00m() -> #x1B[94mNone#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
        adata = adata_sparse.copy()#x1B[90m#x1B[39;49;00m
        adata.layers[#x1B[33m"#x1B[39;49;00m#x1B[33mx2#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m] = adata.X * #x1B[94m2#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        adata.var[#x1B[33m"#x1B[39;49;00m#x1B[33manno2#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m] = [#x1B[33m"#x1B[39;49;00m#x1B[33mp1#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mp2#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mp3#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m]#x1B[90m#x1B[39;49;00m
        adata.raw = adata.copy()#x1B[90m#x1B[39;49;00m
        adata.X = adata.X / #x1B[94m2#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        adata_dense = adata.copy()#x1B[90m#x1B[39;49;00m
        adata_dense.X = adata_dense.X.toarray()#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92massert_same_op_result#x1B[39;49;00m(a1, a2, op):#x1B[90m#x1B[39;49;00m
            r1 = op(a1)#x1B[90m#x1B[39;49;00m
            r2 = op(a2)#x1B[90m#x1B[39;49;00m
            #x1B[94massert#x1B[39;49;00m np.all(r1 == r2)#x1B[90m#x1B[39;49;00m
            #x1B[94massert#x1B[39;49;00m #x1B[96mtype#x1B[39;49;00m(r1) #x1B[95mis#x1B[39;49;00m #x1B[96mtype#x1B[39;49;00m(r2)#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[94massert#x1B[39;49;00m np.allclose(adata.obs_vector(#x1B[33m"#x1B[39;49;00m#x1B[33mb#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m), np.array([#x1B[94m1.0#x1B[39;49;00m, #x1B[94m2.5#x1B[39;49;00m]))#x1B[90m#x1B[39;49;00m
        #x1B[94massert#x1B[39;49;00m np.allclose(adata.raw.obs_vector(#x1B[33m"#x1B[39;49;00m#x1B[33mc#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m), np.array([#x1B[94m3#x1B[39;49;00m, #x1B[94m6#x1B[39;49;00m]))#x1B[90m#x1B[39;49;00m
        #x1B[94massert#x1B[39;49;00m np.all(adata.obs_vector(#x1B[33m"#x1B[39;49;00m#x1B[33manno1#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m) == np.array([#x1B[33m"#x1B[39;49;00m#x1B[33mc1#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mc2#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m]))#x1B[90m#x1B[39;49;00m
        #x1B[94massert#x1B[39;49;00m np.allclose(adata.var_vector(#x1B[33m"#x1B[39;49;00m#x1B[33ms1#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m), np.array([#x1B[94m0#x1B[39;49;00m, #x1B[94m1.0#x1B[39;49;00m, #x1B[94m1.5#x1B[39;49;00m]))#x1B[90m#x1B[39;49;00m
>       #x1B[94massert#x1B[39;49;00m np.allclose(adata.raw.var_vector(#x1B[33m"#x1B[39;49;00m#x1B[33ms2#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m), np.array([#x1B[94m0#x1B[39;49;00m, #x1B[94m5#x1B[39;49;00m, #x1B[94m6#x1B[39;49;00m]))#x1B[90m#x1B[39;49;00m
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[31mtests/test_base.py#x1B[0m:624: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
#x1B[1m#x1B[.../anndata/_core/raw.py#x1B[0m:193: in var_vector
    #x1B[0m#x1B[94mreturn#x1B[39;49;00m _get_vector_ambiguous(#x1B[96mself#x1B[39;49;00m, k, #x1B[33m"#x1B[39;49;00m#x1B[33mvar#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mobs#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[.../anndata/_core/index.py#x1B[0m:372: in _get_vector_ambiguous
    #x1B[0m#x1B[94mreturn#x1B[39;49;00m ref(adata)  #x1B[90m# type: ignore  (accessors don’t officially support Raw, but it works for the tested cases)#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
           ^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[.../anndata/acc/__init__.py#x1B[0m:134: in __call__
    #x1B[0m#x1B[94mreturn#x1B[39;49;00m #x1B[96mself#x1B[39;49;00m.acc.get(adata, #x1B[96mself#x1B[39;49;00m.idx)#x1B[90m#x1B[39;49;00m
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = A.layers['obs'], adata = <anndata._core.raw.Raw object at 0x7f1167e259d0>
idx = ('s2', slice(None, None, None))

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mget#x1B[39;49;00m(#x1B[96mself#x1B[39;49;00m, adata: AnnData, idx: Idx2D, /) -> Array:#x1B[90m#x1B[39;49;00m
>       arr = adata[idx].X #x1B[94mif#x1B[39;49;00m #x1B[96mself#x1B[39;49;00m.k #x1B[95mis#x1B[39;49;00m #x1B[94mNone#x1B[39;49;00m #x1B[94melse#x1B[39;49;00m adata[idx].layers[#x1B[96mself#x1B[39;49;00m.k]#x1B[90m#x1B[39;49;00m
                                                  ^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       AttributeError: 'Raw' object has no attribute 'layers'#x1B[0m

#x1B[1m#x1B[.../anndata/acc/__init__.py#x1B[0m:269: 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.

@flying-sheep flying-sheep added this to the 0.13.0 milestone Jan 15, 2026
@flying-sheep flying-sheep marked this pull request as ready for review February 6, 2026 14:30
@flying-sheep
Copy link
Member Author

@ilan-gold I didn’t update the docs since your last review, but the rest should be finished now!

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.

Reference paths / accessors

2 participants