Skip to content

Commit

Permalink
[python] Centralize sparse/dense pybind11 shape methods (#3261)
Browse files Browse the repository at this point in the history
* [python] Centralize sparse/dense `pybind11` shape methods

* Another logic-simplifier

* more
  • Loading branch information
johnkerl authored Oct 30, 2024
1 parent 467af01 commit 7a9c67e
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 61 deletions.
10 changes: 3 additions & 7 deletions apis/python/src/tiledbsoma/_dense_nd_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from ._arrow_types import pyarrow_to_carrow_type
from ._common_nd_array import NDArray
from ._exception import SOMAError, map_exception_for_create
from ._flags import NEW_SHAPE_FEATURE_FLAG_ENABLED
from ._flags import DENSE_ARRAYS_CAN_HAVE_CURRENT_DOMAIN, NEW_SHAPE_FEATURE_FLAG_ENABLED
from ._tdb_handles import DenseNDArrayWrapper
from ._types import OpenTimestamp, Slice
from ._util import dense_indices_to_shape
Expand Down Expand Up @@ -105,11 +105,7 @@ def create(
dim_name = f"soma_dim_{dim_idx}"
pa_field = pa.field(dim_name, pa.int64())

if NEW_SHAPE_FEATURE_FLAG_ENABLED and clib.embedded_version_triple() >= (
2,
27,
0,
):
if NEW_SHAPE_FEATURE_FLAG_ENABLED and DENSE_ARRAYS_CAN_HAVE_CURRENT_DOMAIN:
dim_capacity, dim_extent = cls._dim_capacity_and_extent(
dim_name,
# The user specifies current domain -- this is the max domain
Expand Down Expand Up @@ -341,7 +337,7 @@ def resize(self, newshape: Sequence[Union[int, None]]) -> None:
"""Supported for ``SparseNDArray``; scheduled for implementation for
``DenseNDArray`` in TileDB-SOMA 1.15
"""
if clib.embedded_version_triple() >= (2, 27, 0):
if DENSE_ARRAYS_CAN_HAVE_CURRENT_DOMAIN:
self._handle.resize(newshape)
else:
raise NotImplementedError("Not implemented for libtiledbsoma < 2.27.0")
Expand Down
4 changes: 4 additions & 0 deletions apis/python/src/tiledbsoma/_flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@

import os

import tiledbsoma.pytiledbsoma as clib

# This is temporary for
# https://github.com/single-cell-data/TileDB-SOMA/issues/2407. It will be
# removed once https://github.com/single-cell-data/TileDB-SOMA/issues/2407 is
# complete.

NEW_SHAPE_FEATURE_FLAG_ENABLED = os.getenv("SOMA_PY_NEW_SHAPE") != "false"

DENSE_ARRAYS_CAN_HAVE_CURRENT_DOMAIN = clib.embedded_version_triple() >= (2, 27, 0)
5 changes: 3 additions & 2 deletions apis/python/src/tiledbsoma/_tdb_handles.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

from . import pytiledbsoma as clib
from ._exception import DoesNotExistError, SOMAError, is_does_not_exist_error
from ._flags import DENSE_ARRAYS_CAN_HAVE_CURRENT_DOMAIN
from ._types import METADATA_TYPES, Metadatum, OpenTimestamp, StatusAndReason
from .options._soma_tiledb_context import SOMATileDBContext

Expand Down Expand Up @@ -643,7 +644,7 @@ def tiledbsoma_has_upgraded_shape(self) -> bool:

def resize(self, newshape: Sequence[Union[int, None]]) -> None:
"""Wrapper-class internals"""
if clib.embedded_version_triple() >= (2, 27, 0):
if DENSE_ARRAYS_CAN_HAVE_CURRENT_DOMAIN:
self._handle.resize(newshape)
else:
raise NotImplementedError("Not implemented for libtiledbsoma < 2.27.0")
Expand All @@ -652,7 +653,7 @@ def tiledbsoma_can_resize(
self, newshape: Sequence[Union[int, None]]
) -> StatusAndReason:
"""Wrapper-class internals"""
if clib.embedded_version_triple() >= (2, 27, 0):
if DENSE_ARRAYS_CAN_HAVE_CURRENT_DOMAIN:
return cast(StatusAndReason, self._handle.tiledbsoma_can_resize(newshape))
else:
raise NotImplementedError("Not implemented for libtiledbsoma < 2.27.0")
Expand Down
57 changes: 56 additions & 1 deletion apis/python/src/tiledbsoma/soma_array.cc
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,61 @@ void load_soma_array(py::module& m) {

.def("has_metadata", &SOMAArray::has_metadata)

.def("metadata_num", &SOMAArray::metadata_num);
.def("metadata_num", &SOMAArray::metadata_num)

// These are for SparseNDArray and DenseNDArray both:
// * tiledbsoma_has_upgraded_shape
// * resize
// * can_resize
// * tiledbsoma_upgrade_shape
// * tiledbsoma_can_upgrade_shape
// We don't have CommonNDArray base class in pybind11, and it's probably
// not worth it. These are exposed to the user-facing API only for
// SparseNDArray and DenseNDArray and not for DataFrame.
.def_property_readonly(
"tiledbsoma_has_upgraded_shape", &SOMAArray::has_current_domain)

.def(
"resize",
[](SOMAArray& array, const std::vector<int64_t>& newshape) {
try {
array.resize(newshape, "resize");
} catch (const std::exception& e) {
throw TileDBSOMAError(e.what());
}
},
"newshape"_a)
.def(
"can_resize",
[](SOMAArray& array, const std::vector<int64_t>& newshape) {
try {
return array.can_resize(newshape, "can_resize");
} catch (const std::exception& e) {
throw TileDBSOMAError(e.what());
}
},
"newshape"_a)

.def(
"tiledbsoma_upgrade_shape",
[](SOMAArray& array, const std::vector<int64_t>& newshape) {
try {
array.upgrade_shape(newshape, "tiledbsoma_upgrade_shape");
} catch (const std::exception& e) {
throw TileDBSOMAError(e.what());
}
},
"newshape"_a)
.def(
"tiledbsoma_can_upgrade_shape",
[](SOMAArray& array, const std::vector<int64_t>& newshape) {
try {
return array.can_upgrade_shape(
newshape, "tiledbsoma_can_upgrade_shape");
} catch (const std::exception& e) {
throw TileDBSOMAError(e.what());
}
},
"newshape"_a);
}
} // namespace libtiledbsomacpp
4 changes: 1 addition & 3 deletions apis/python/src/tiledbsoma/soma_dense_ndarray.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@ void load_soma_dense_ndarray(py::module& m) {
.def("write", write)

.def_property_readonly("shape", &SOMADenseNDArray::shape)
.def_property_readonly("maxshape", &SOMADenseNDArray::maxshape)
.def_property_readonly(
"tiledbsoma_has_upgraded_shape", &SOMAArray::has_current_domain);
.def_property_readonly("maxshape", &SOMADenseNDArray::maxshape);
}
} // namespace libtiledbsomacpp
47 changes: 1 addition & 46 deletions apis/python/src/tiledbsoma/soma_sparse_ndarray.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,51 +114,6 @@ void load_soma_sparse_ndarray(py::module& m) {
.def_static("exists", &SOMASparseNDArray::exists)

.def_property_readonly("shape", &SOMASparseNDArray::shape)
.def_property_readonly("maxshape", &SOMASparseNDArray::maxshape)
.def_property_readonly(
"tiledbsoma_has_upgraded_shape", &SOMAArray::has_current_domain)

.def(
"resize",
[](SOMAArray& array, const std::vector<int64_t>& newshape) {
try {
array.resize(newshape, "resize");
} catch (const std::exception& e) {
throw TileDBSOMAError(e.what());
}
},
"newshape"_a)
.def(
"can_resize",
[](SOMAArray& array, const std::vector<int64_t>& newshape) {
try {
return array.can_resize(newshape, "can_resize");
} catch (const std::exception& e) {
throw TileDBSOMAError(e.what());
}
},
"newshape"_a)

.def(
"tiledbsoma_upgrade_shape",
[](SOMAArray& array, const std::vector<int64_t>& newshape) {
try {
array.upgrade_shape(newshape, "tiledbsoma_upgrade_shape");
} catch (const std::exception& e) {
throw TileDBSOMAError(e.what());
}
},
"newshape"_a)
.def(
"tiledbsoma_can_upgrade_shape",
[](SOMAArray& array, const std::vector<int64_t>& newshape) {
try {
return array.can_upgrade_shape(
newshape, "tiledbsoma_can_upgrade_shape");
} catch (const std::exception& e) {
throw TileDBSOMAError(e.what());
}
},
"newshape"_a);
.def_property_readonly("maxshape", &SOMASparseNDArray::maxshape);
}
} // namespace libtiledbsomacpp
4 changes: 2 additions & 2 deletions apis/python/tests/test_shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,15 +210,15 @@ 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:
if tiledbsoma.pytiledbsoma.embedded_version_triple() >= (2, 27, 0):
if tiledbsoma._flags.DENSE_ARRAYS_CAN_HAVE_CURRENT_DOMAIN:
dnda.resize((300, 400))
else:
with pytest.raises(NotImplementedError):
dnda.resize((300, 400))

with tiledbsoma.DenseNDArray.open(uri) as dnda:
assert dnda.non_empty_domain() == ((0, 0), (0, 0))
if tiledbsoma.pytiledbsoma.embedded_version_triple() >= (2, 27, 0):
if tiledbsoma._flags.DENSE_ARRAYS_CAN_HAVE_CURRENT_DOMAIN:
assert dnda.shape == (300, 400)
else:
assert dnda.shape == (100, 200)
Expand Down

0 comments on commit 7a9c67e

Please sign in to comment.