diff --git a/apis/python/src/tiledbsoma/_dataframe.py b/apis/python/src/tiledbsoma/_dataframe.py index c9ffd29d8f..c5fcd71a4d 100644 --- a/apis/python/src/tiledbsoma/_dataframe.py +++ b/apis/python/src/tiledbsoma/_dataframe.py @@ -340,7 +340,7 @@ def read( handle = self._handle._handle - context = handle.ctx() + context = handle.context() if platform_config is not None: config = context.tiledb_config.copy() config.update(platform_config or {}) @@ -353,7 +353,7 @@ def read( sr = clib.SOMADataFrame.open( uri=handle.uri, mode=clib.OpenMode.read, - ctx=context, + context=context, column_names=column_names or [], result_order=_util.to_clib_result_order(result_order), timestamp=ts, diff --git a/apis/python/src/tiledbsoma/_tdb_handles.py b/apis/python/src/tiledbsoma/_tdb_handles.py index 44e49824ef..9a49b3e91d 100644 --- a/apis/python/src/tiledbsoma/_tdb_handles.py +++ b/apis/python/src/tiledbsoma/_tdb_handles.py @@ -54,38 +54,39 @@ def open( open_mode = clib.OpenMode.read if mode == "r" else clib.OpenMode.write timestamp_ms = context._open_timestamp_ms(timestamp) - try: - soma_object = clib.SOMAObject.open( - uri, open_mode, context.native_context, (0, timestamp_ms) - ) - - if open_mode == clib.OpenMode.read and soma_object.type == "SOMADataFrame": - return DataFrameWrapper._from_soma_object(soma_object, context) - - # This object still uses tiledb-py and must be handled below - if soma_object.type in ( - "SOMADataFrame", - "SOMASparseNDArray", - "SOMADenseNDArray", - ): - return ArrayWrapper.open(uri, mode, context, timestamp) - if soma_object.type in ("SOMACollection", "SOMAExperiment", "SOMAMeasurement"): - return GroupWrapper.open(uri, mode, context, timestamp) - except (SOMAError, RuntimeError): - # TODO on Linux this throws a SOMAError but on macOS a RuntimeError - pass - - # We avoid needing to create a tiledb.Ctx() unless necessary - # This SOMAObject does not have metadata information - # associated with it yet and requires tiledb.object_type to check - - obj_type = tiledb.object_type(uri, ctx=context.tiledb_ctx) + # if there is not a valid SOMAObject at the given URI, this + # returns None + soma_object = clib.SOMAObject.open( + uri, open_mode, context.native_context, (0, timestamp_ms) + ) + + # Avoid creating a TileDB-Py Ctx unless necessary + obj_type = ( + soma_object.type + if soma_object is not None + else tiledb.object_type(uri, ctx=context.tiledb_ctx) + ) + if not obj_type: raise DoesNotExistError(f"{uri!r} does not exist") - if obj_type == "array": + if open_mode == clib.OpenMode.read and obj_type == "SOMADataFrame": + return DataFrameWrapper._from_soma_object(soma_object, context) + + if obj_type in ( + "SOMADataFrame", + "SOMASparseNDArray", + "SOMADenseNDArray", + "array", + ): return ArrayWrapper.open(uri, mode, context, timestamp) - if obj_type == "group": + + if obj_type in ( + "SOMACollection", + "SOMAExperiment", + "SOMAMeasurement", + "group", + ): return GroupWrapper.open(uri, mode, context, timestamp) # Invalid object diff --git a/apis/python/src/tiledbsoma/options/_soma_tiledb_context.py b/apis/python/src/tiledbsoma/options/_soma_tiledb_context.py index 3f2bd73dfc..4e6e3735d2 100644 --- a/apis/python/src/tiledbsoma/options/_soma_tiledb_context.py +++ b/apis/python/src/tiledbsoma/options/_soma_tiledb_context.py @@ -154,15 +154,16 @@ def timestamp(self) -> Optional[datetime.datetime]: @property def native_context(self) -> clib.SOMAContext: """The C++ SOMAContext for this SOMA context.""" - if self._native_context is None: - self._native_context = clib.SOMAContext( - {k: str(self.tiledb_config[k]) for k in self.tiledb_config} - ) - return self._native_context + with self._lock: + if self._native_context is None: + self._native_context = clib.SOMAContext( + {k: str(self.tiledb_config[k]) for k in self.tiledb_config} + ) + return self._native_context @property def tiledb_ctx(self) -> tiledb.Ctx: - """The TileDB Context for this SOMA context.""" + """The TileDB-Py Context for this SOMA context.""" with self._lock: if self._tiledb_ctx is None: if self._initial_config is None: diff --git a/apis/python/src/tiledbsoma/soma_array.cc b/apis/python/src/tiledbsoma/soma_array.cc index 28be65f48a..b295887d0d 100644 --- a/apis/python/src/tiledbsoma/soma_array.cc +++ b/apis/python/src/tiledbsoma/soma_array.cc @@ -199,7 +199,7 @@ void load_soma_array(py::module &m) { auto pa_schema_import = pa.attr("Schema").attr("_import_from_c"); return pa_schema_import(py::capsule(reader.arrow_schema().get())); }) - .def("ctx", &SOMAArray::ctx) + .def("context", &SOMAArray::ctx) // After this are short functions expected to be invoked when the coords // are Python list/tuple, or NumPy arrays. Arrow arrays are in this diff --git a/apis/python/src/tiledbsoma/soma_collection.cc b/apis/python/src/tiledbsoma/soma_collection.cc index a6a83f0480..d493d49ccd 100644 --- a/apis/python/src/tiledbsoma/soma_collection.cc +++ b/apis/python/src/tiledbsoma/soma_collection.cc @@ -51,4 +51,4 @@ void load_soma_collection(py::module &m) { py::class_(m, "SOMAExperiment"); py::class_(m, "SOMAMeasurement"); } -} \ No newline at end of file +} diff --git a/apis/python/src/tiledbsoma/soma_dataframe.cc b/apis/python/src/tiledbsoma/soma_dataframe.cc index 78eb1fde5e..b22e326f78 100644 --- a/apis/python/src/tiledbsoma/soma_dataframe.cc +++ b/apis/python/src/tiledbsoma/soma_dataframe.cc @@ -60,7 +60,7 @@ void load_soma_dataframe(py::module &m) { std::optional>>(&SOMADataFrame::open), "uri"_a, "mode"_a, - "ctx"_a, + "context"_a, py::kw_only(), "column_names"_a = py::none(), "result_order"_a = ResultOrder::automatic, diff --git a/apis/python/src/tiledbsoma/soma_group.cc b/apis/python/src/tiledbsoma/soma_group.cc index 220a66ab33..47964e8518 100644 --- a/apis/python/src/tiledbsoma/soma_group.cc +++ b/apis/python/src/tiledbsoma/soma_group.cc @@ -42,4 +42,4 @@ void load_soma_group(py::module &m) { py::class_(m, "SOMAGroup") .def_property_readonly("type", &SOMAGroup::type); } -} \ No newline at end of file +} diff --git a/apis/python/src/tiledbsoma/soma_object.cc b/apis/python/src/tiledbsoma/soma_object.cc index 8fd8ff130b..6e8784ff25 100644 --- a/apis/python/src/tiledbsoma/soma_object.cc +++ b/apis/python/src/tiledbsoma/soma_object.cc @@ -54,20 +54,24 @@ void load_soma_object(py::module &m) { OpenMode mode, std::shared_ptr ctx, std::optional> timestamp) -> py::object { - auto obj = SOMAObject::open(uri, mode, ctx, timestamp); - if (obj->type() == "SOMADataFrame") - return py::cast(dynamic_cast(*obj)); - else if (obj->type() == "SOMASparseNDArray") - return py::cast(dynamic_cast(*obj)); - else if (obj->type() == "SOMADenseNDArray") - return py::cast(dynamic_cast(*obj)); - else if (obj->type() == "SOMACollection") - return py::cast(dynamic_cast(*obj)); - else if (obj->type() == "SOMAExperiment") - return py::cast(dynamic_cast(*obj)); - else if (obj->type() == "SOMAMeasurement") - return py::cast(dynamic_cast(*obj)); - TPY_ERROR_LOC("Invalid SOMAObject"); + try{ + auto obj = SOMAObject::open(uri, mode, ctx, timestamp); + if (obj->type() == "SOMADataFrame") + return py::cast(dynamic_cast(*obj)); + else if (obj->type() == "SOMASparseNDArray") + return py::cast(dynamic_cast(*obj)); + else if (obj->type() == "SOMADenseNDArray") + return py::cast(dynamic_cast(*obj)); + else if (obj->type() == "SOMACollection") + return py::cast(dynamic_cast(*obj)); + else if (obj->type() == "SOMAExperiment") + return py::cast(dynamic_cast(*obj)); + else if (obj->type() == "SOMAMeasurement") + return py::cast(dynamic_cast(*obj)); + return py::none(); + }catch(...){ + return py::none(); + } }) .def_property_readonly("type", &SOMAObject::type);