Skip to content

Commit

Permalink
unit-test mods [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
johnkerl committed Sep 8, 2024
1 parent afdc38d commit 0dcc849
Show file tree
Hide file tree
Showing 19 changed files with 316 additions and 112 deletions.
6 changes: 3 additions & 3 deletions apis/python/src/tiledbsoma/_common_nd_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ def maxshape(self) -> Tuple[int, ...]:
return cast(Tuple[int, ...], tuple(self._handle.maxshape))

@property
def has_upgraded_shape(self) -> bool:
def tiledbsoma_has_upgraded_shape(self) -> bool:
"""Returns true if the array has the upgraded resizeable shape feature
from TileDB-SOMA 1.14: the array was created with this support, or it has
had ``.upgrade_shape`` applied to it.
had ``.tiledbsoma_upgrade_shape`` applied to it.
Lifecycle:
Maturing.
"""
return self._handle.has_upgraded_shape
return self._handle.tiledbsoma_has_upgraded_shape

@classmethod
def _dim_capacity_and_extent(
Expand Down
6 changes: 3 additions & 3 deletions apis/python/src/tiledbsoma/_dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,15 +407,15 @@ def _maybe_soma_joinid_maxshape(self) -> Optional[int]:
return self._handle.maybe_soma_joinid_maxshape

@property
def has_upgraded_domain(self) -> bool:
def tiledbsoma_has_upgraded_domain(self) -> bool:
"""Returns true if the array has the upgraded resizeable domain feature
from TileDB-SOMA 1.14: the array was created with this support, or it has
had ``.upgrade_domain`` applied to it.
had ``.tiledbsoma_upgrade_domain`` applied to it.
Lifecycle:
Maturing.
"""
return self._handle.has_upgraded_domain
return self._handle.tiledbsoma_has_upgraded_domain

def __len__(self) -> int:
"""Returns the number of rows in the dataframe. Same as ``df.count``."""
Expand Down
6 changes: 6 additions & 0 deletions apis/python/src/tiledbsoma/_dense_nd_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,12 @@ def write(
clib_dense_array.consolidate_and_vacuum()
return self

def resize(self, newshape: Sequence[Union[int, None]]) -> None:
"""Comment me please thx"""
# TODO: support current domain for dense arrays once we have core support.
# https://github.com/single-cell-data/TileDB-SOMA/issues/2955
raise NotImplementedError()

@classmethod
def _dim_capacity_and_extent(
cls,
Expand Down
12 changes: 2 additions & 10 deletions apis/python/src/tiledbsoma/_sparse_nd_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,19 +295,11 @@ def read(

def resize(self, newshape: Sequence[Union[int, None]]) -> None:
"""Comment me please thx"""
# For core 2.26 we'll implement this for sparse and dense.
# For core 2.25 we'll implement this only for dense.
# We'll leave this common accessor here, but raise
# NotImplementedError in DenseNDArray until 2.26.
self._handle.resize(newshape)

def upgrade_shape(self, newshape: Sequence[Union[int, None]]) -> None:
def tiledbsoma_upgrade_shape(self, newshape: Sequence[Union[int, None]]) -> None:
"""Comment me please thx"""
# For core 2.26 we'll implement this for sparse and dense.
# For core 2.25 we'll implement this only for dense.
# We'll leave this common accessor here, but raise
# NotImplementedError in DenseNDArray until 2.26.
self._handle.upgrade_shape(newshape)
self._handle.tiledbsoma_upgrade_shape(newshape)

def write(
self,
Expand Down
42 changes: 20 additions & 22 deletions apis/python/src/tiledbsoma/_tdb_handles.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,20 +430,20 @@ def maybe_soma_joinid_maxshape(self) -> Optional[int]:
raise NotImplementedError

@property
def has_upgraded_shape(self) -> bool:
def tiledbsoma_has_upgraded_shape(self) -> bool:
"""Not implemented for DataFrame."""
raise NotImplementedError

@property
def has_upgraded_domain(self) -> bool:
def tiledbsoma_has_upgraded_domain(self) -> bool:
"""Only implemented for DataFrame."""
raise NotImplementedError

def resize(self, newshape: Sequence[Union[int, None]]) -> None:
"""Comment me please thx"""
raise NotImplementedError

def upgrade_shape(self, newshape: Sequence[Union[int, None]]) -> None:
def tiledbsoma_upgrade_shape(self, newshape: Sequence[Union[int, None]]) -> None:
"""Comment me please thx"""
raise NotImplementedError

Expand Down Expand Up @@ -483,15 +483,15 @@ def maybe_soma_joinid_maxshape(self) -> Optional[int]:
return cast(Optional[int], self._handle.maybe_soma_joinid_maxshape)

@property
def has_upgraded_domain(self) -> bool:
def tiledbsoma_has_upgraded_domain(self) -> bool:
"""Returns true if the array has the upgraded resizeable domain feature
from TileDB-SOMA 1.14: the array was created with this support, or it has
had ``.upgrade_domain`` applied to it.
had ``.tiledbsoma_upgrade_domain`` applied to it.
Lifecycle:
Maturing.
"""
return cast(bool, self._handle.has_upgraded_domain)
return cast(bool, self._handle.tiledbsoma_has_upgraded_domain)


class DenseNDArrayWrapper(SOMAArrayWrapper[clib.SOMADenseNDArray]):
Expand All @@ -500,15 +500,21 @@ class DenseNDArrayWrapper(SOMAArrayWrapper[clib.SOMADenseNDArray]):
_ARRAY_WRAPPED_TYPE = clib.SOMADenseNDArray

@property
def has_upgraded_shape(self) -> bool:
def tiledbsoma_has_upgraded_shape(self) -> bool:
"""Returns true if the array has the upgraded resizeable shape feature
from TileDB-SOMA 1.14: the array was created with this support, or it has
had ``.upgrade_shape`` applied to it.
had ``.tiledbsoma_upgrade_shape`` applied to it.
Lifecycle:
Maturing.
"""
return cast(bool, self._handle.has_upgraded_shape)
return cast(bool, self._handle.tiledbsoma_has_upgraded_shape)

def resize(self, newshape: Sequence[Union[int, None]]) -> None:
"""Comment me please thx"""
# TODO: support current domain for dense arrays once we have core support.
# https://github.com/single-cell-data/TileDB-SOMA/issues/2955
raise NotImplementedError()


class SparseNDArrayWrapper(SOMAArrayWrapper[clib.SOMASparseNDArray]):
Expand All @@ -521,31 +527,23 @@ def nnz(self) -> int:
return int(self._handle.nnz())

@property
def has_upgraded_shape(self) -> bool:
def tiledbsoma_has_upgraded_shape(self) -> bool:
"""Returns true if the array has the upgraded resizeable shape feature
from TileDB-SOMA 1.14: the array was created with this support, or it has
had ``.upgrade_shape`` applied to it.
had ``.tiledbsoma_upgrade_shape`` applied to it.
Lifecycle:
Maturing.
"""
return cast(bool, self._handle.has_upgraded_shape)
return cast(bool, self._handle.tiledbsoma_has_upgraded_shape)

def resize(self, newshape: Sequence[Union[int, None]]) -> None:
"""Comment me please thx"""
# For core 2.26 we'll implement this for sparse and dense.
# For core 2.25 we'll implement this only for dense.
# We'll leave this common accessor here, but raise
# NotImplementedError in DenseNDArray until 2.26.
self._handle.resize(newshape)

def upgrade_shape(self, newshape: Sequence[Union[int, None]]) -> None:
def tiledbsoma_upgrade_shape(self, newshape: Sequence[Union[int, None]]) -> None:
"""Comment me please thx"""
# For core 2.26 we'll implement this for sparse and dense.
# For core 2.25 we'll implement this only for dense.
# We'll leave this common accessor here, but raise
# NotImplementedError in DenseNDArray until 2.26.
self._handle.upgrade_shape(newshape)
self._handle.tiledbsoma_upgrade_shape(newshape)


class _DictMod(enum.Enum):
Expand Down
2 changes: 1 addition & 1 deletion apis/python/src/tiledbsoma/soma_dataframe.cc
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,6 @@ void load_soma_dataframe(py::module& m) {
"maybe_soma_joinid_maxshape",
&SOMADataFrame::maybe_soma_joinid_maxshape)
.def_property_readonly(
"has_upgraded_domain", &SOMAArray::has_current_domain);
"tiledbsoma_has_upgraded_domain", &SOMAArray::has_current_domain);
}
} // namespace libtiledbsomacpp
2 changes: 1 addition & 1 deletion apis/python/src/tiledbsoma/soma_dense_ndarray.cc
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,6 @@ void load_soma_dense_ndarray(py::module& m) {
.def_property_readonly("shape", &SOMADenseNDArray::shape)
.def_property_readonly("maxshape", &SOMADenseNDArray::maxshape)
.def_property_readonly(
"has_upgraded_shape", &SOMAArray::has_current_domain);
"tiledbsoma_has_upgraded_shape", &SOMAArray::has_current_domain);
}
} // namespace libtiledbsomacpp
4 changes: 2 additions & 2 deletions apis/python/src/tiledbsoma/soma_sparse_ndarray.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ void load_soma_sparse_ndarray(py::module& m) {
.def_property_readonly("shape", &SOMASparseNDArray::shape)
.def_property_readonly("maxshape", &SOMASparseNDArray::maxshape)
.def_property_readonly(
"has_upgraded_shape", &SOMAArray::has_current_domain)
"tiledbsoma_has_upgraded_shape", &SOMAArray::has_current_domain)

.def(
"resize",
Expand All @@ -129,7 +129,7 @@ void load_soma_sparse_ndarray(py::module& m) {
"newshape"_a)

.def(
"upgrade_shape",
"tiledbsoma_upgrade_shape",
[](SOMAArray& array, const std::vector<int64_t>& newshape) {
try {
array.upgrade_shape(newshape);
Expand Down
4 changes: 3 additions & 1 deletion apis/python/tests/test_dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ def test_dataframe(tmp_path, arrow_schema):
assert len(sdf) == 5

# More to come on https://github.com/single-cell-data/TileDB-SOMA/issues/2407
assert sdf.has_upgraded_domain == soma._new_shape_feature_flag_enabled()
assert (
sdf.tiledbsoma_has_upgraded_domain == soma._new_shape_feature_flag_enabled()
)

with pytest.raises(AttributeError):
assert sdf.shape is None
Expand Down
106 changes: 83 additions & 23 deletions apis/python/tests/test_shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

import tiledbsoma

from tests._util import maybe_raises


@pytest.mark.parametrize(
"element_dtype",
Expand All @@ -18,32 +16,27 @@
],
)
@pytest.mark.parametrize(
"shape_exc",
"arg_shape",
[
# Note: non-None exceptions are coming on https://github.com/single-cell-data/TileDB-SOMA/issues/2407
[(100,), None],
[(100, 200), None],
[(100, 200, 300), None],
(100,),
(100, 200),
(100, 200, 300),
],
)
def test_sparse_nd_array_basics(
tmp_path,
element_dtype,
shape_exc,
arg_shape,
):
uri = tmp_path.as_posix()
arg_shape, arg_create_exc = shape_exc
ndim = len(arg_shape)

# Create the array
with maybe_raises(arg_create_exc):
snda = tiledbsoma.SparseNDArray.create(
uri,
type=element_dtype,
shape=arg_shape,
)
if arg_create_exc is not None:
return
tiledbsoma.SparseNDArray.create(
uri,
type=element_dtype,
shape=arg_shape,
)

assert tiledbsoma.SparseNDArray.exists(uri)

Expand All @@ -53,7 +46,10 @@ def test_sparse_nd_array_basics(
assert snda.shape == arg_shape

# More to come on https://github.com/single-cell-data/TileDB-SOMA/issues/2407
assert snda.has_upgraded_shape == tiledbsoma._new_shape_feature_flag_enabled()
assert (
snda.tiledbsoma_has_upgraded_shape
== tiledbsoma._new_shape_feature_flag_enabled()
)

# Before current-domain support: shape is maxshape.
#
Expand Down Expand Up @@ -102,23 +98,79 @@ def test_sparse_nd_array_basics(

# Test reads out of bounds
with tiledbsoma.SparseNDArray.open(uri) as snda:
# https://github.com/single-cell-data/TileDB-SOMA/issues/2407
coords = tuple(arg_shape[i] + 10 for i in range(ndim))
with pytest.raises(tiledbsoma.SOMAError):
coords = tuple(arg_shape[i] + 10 for i in range(ndim))
snda.read(coords).tables().concat()

# Test writes out of bounds
with tiledbsoma.SparseNDArray.open(uri, "w") as snda:
with pytest.raises(tiledbsoma.SOMAError):
dikt = {"soma_data": [30]}
dikt = {name: [shape + 20] for name, shape in zip(dim_names, arg_shape)}
dikt["soma_data"] = [30]
table = pa.Table.from_pydict(dikt)
snda.write(table)

with tiledbsoma.SparseNDArray.open(uri) as snda:
assert snda.shape == arg_shape
if not tiledbsoma._new_shape_feature_flag_enabled():
assert snda.shape == snda.maxshape

if tiledbsoma._new_shape_feature_flag_enabled():

# Test resize down
new_shape = tuple([arg_shape[i] - 50 for i in range(ndim)])
with tiledbsoma.SparseNDArray.open(uri, "w") as snda:
# TODO: check draft spec
# with pytest.raises(ValueError):
with pytest.raises(tiledbsoma.SOMAError):
snda.resize(new_shape)

with tiledbsoma.SparseNDArray.open(uri) as snda:
assert snda.shape == arg_shape

# Test resize too big
new_shape = tuple([4_000_000_000 for i in range(ndim)])
# TODO: check draft spec
# with pytest.raises(ValueError):
with pytest.raises(tiledbsoma.SOMAError):
with tiledbsoma.SparseNDArray.open(uri, "w") as snda:
snda.resize(new_shape)
with tiledbsoma.SparseNDArray.open(uri) as snda:
assert snda.shape == arg_shape

# Test writes out of bounds
with tiledbsoma.SparseNDArray.open(uri, "w") as snda:
with pytest.raises(tiledbsoma.SOMAError):
dikt = {name: [shape + 20] for name, shape in zip(dim_names, arg_shape)}
dikt["soma_data"] = [30]
table = pa.Table.from_pydict(dikt)
snda.write(table)

# Test reasonable resize
new_shape = tuple([arg_shape[i] + 50 for i in range(ndim)])
with tiledbsoma.SparseNDArray.open(uri, "w") as snda:
snda.resize(new_shape)

dikt = {}
for i in range(ndim):
dikt[dim_names[i]] = [arg_shape[i] + 20]
dikt["soma_data"] = pa.array([34.5], type=element_dtype)
table = pa.Table.from_pydict(dikt)

# Re-test writes out of old bounds, within new bounds
with tiledbsoma.SparseNDArray.open(uri, "w") as snda:
# Implicitly checking there's no raise
snda.write(table)

# Re-test reads out of old bounds, within new bounds
with tiledbsoma.SparseNDArray.open(uri) as snda:
assert snda.shape == new_shape

coords = tuple([(arg_shape[i] + 20,) for i in range(ndim)])
# Implicitly checking there's no raise
readback = snda.read(coords).tables().concat()
assert readback == table

with tiledbsoma.SparseNDArray.open(uri) as snda:
assert snda.shape == new_shape


## Pending 2.27 timeframe for dense support for current domain, including resize
Expand All @@ -134,6 +186,14 @@ def test_dense_nd_array_basics(tmp_path):

assert dnda.non_empty_domain() == ((0, 0), (0, 0))

with tiledbsoma.DenseNDArray.open(uri, "w") as dnda:
with pytest.raises(NotImplementedError):
dnda.resize((300, 400))

with tiledbsoma.DenseNDArray.open(uri) as dnda:
assert dnda.non_empty_domain() == ((0, 0), (0, 0))
assert dnda.shape == (100, 200)


@pytest.mark.parametrize(
"soma_joinid_domain",
Expand Down
Loading

0 comments on commit 0dcc849

Please sign in to comment.