From cfe8e7b3e43a71e866c81f253d02fe71b100b185 Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Wed, 11 Jun 2025 16:48:32 +0300 Subject: [PATCH 01/12] Wrap Profile --- tiledb/__init__.py | 3 ++ tiledb/libtiledb/CMakeLists.txt | 1 + tiledb/libtiledb/profile.cc | 61 ++++++++++++++++++++++ tiledb/libtiledb/tiledbcpp.cc | 2 + tiledb/profile.py | 90 +++++++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+) create mode 100644 tiledb/libtiledb/profile.cc create mode 100644 tiledb/profile.py diff --git a/tiledb/__init__.py b/tiledb/__init__.py index 33d2aa6419..2d66839d09 100644 --- a/tiledb/__init__.py +++ b/tiledb/__init__.py @@ -25,6 +25,9 @@ from .current_domain import CurrentDomain from .ndrectangle import NDRectangle +if libtiledb_version()[0] == 2 and libtiledb_version()[1] >= 29: + from .profile import Profile + del libtiledb_version # no longer needed from .array import Array diff --git a/tiledb/libtiledb/CMakeLists.txt b/tiledb/libtiledb/CMakeLists.txt index 8fd2072bc2..59a63cda95 100644 --- a/tiledb/libtiledb/CMakeLists.txt +++ b/tiledb/libtiledb/CMakeLists.txt @@ -16,6 +16,7 @@ pybind11_add_module( group.cc metadata.h object.cc + profile.cc query.cc schema.cc subarray.cc diff --git a/tiledb/libtiledb/profile.cc b/tiledb/libtiledb/profile.cc new file mode 100644 index 0000000000..ca728c4479 --- /dev/null +++ b/tiledb/libtiledb/profile.cc @@ -0,0 +1,61 @@ +#include +#include + +#include +#include +#include + +#include "common.h" + +namespace libtiledbcpp { + +using namespace tiledb; +using namespace tiledbpy::common; +namespace py = pybind11; + +void init_profile(py::module& m) { +#if TILEDB_VERSION_MAJOR >= 2 && TILEDB_VERSION_MINOR >= 29 + py::class_(m, "Profile") + + .def( + py::init, std::optional>(), + py::arg("name") = std::nullopt, + py::arg("dir") = std::nullopt) + + .def(py::init()) + + .def_property_readonly("_name", &tiledb::Profile::name) + + .def_property_readonly("_dir", &tiledb::Profile::dir) + + .def( + "_set_param", + &tiledb::Profile::set_param, + py::arg("param"), + py::arg("value")) + + .def("_get_param", &tiledb::Profile::get_param, py::arg("param")) + + .def("_save", &tiledb::Profile::save) + + .def_static( + "_load", + py::overload_cast< + std::optional, + std::optional>(&tiledb::Profile::load), + py::arg("name") = std::nullopt, + py::arg("dir") = std::nullopt) + + .def_static( + "_remove", + py::overload_cast< + std::optional, + std::optional>(&tiledb::Profile::remove), + py::arg("name") = std::nullopt, + py::arg("dir") = std::nullopt) + + .def("_dump", &tiledb::Profile::dump); +#endif +} + +} // namespace libtiledbcpp diff --git a/tiledb/libtiledb/tiledbcpp.cc b/tiledb/libtiledb/tiledbcpp.cc index 8b576ab721..4dd0d915db 100644 --- a/tiledb/libtiledb/tiledbcpp.cc +++ b/tiledb/libtiledb/tiledbcpp.cc @@ -29,6 +29,7 @@ void init_filestore(py::module& m); void init_filter(py::module&); void init_group(py::module&); void init_object(py::module& m); +void init_profile(py::module& m); void init_query(py::module& m); void init_schema(py::module&); void init_subarray(py::module&); @@ -50,6 +51,7 @@ PYBIND11_MODULE(libtiledb, m) { init_filter(m); init_group(m); init_object(m); + init_profile(m); init_query(m); init_schema(m); init_subarray(m); diff --git a/tiledb/profile.py b/tiledb/profile.py new file mode 100644 index 0000000000..7a851fd281 --- /dev/null +++ b/tiledb/profile.py @@ -0,0 +1,90 @@ +import tiledb.libtiledb as lt + + +class Profile(lt.Profile): + """ + Represents a TileDB profile. + """ + + def __init__(self, name: str = None, dir: str = None): + """Class representing a TileDB profile. + + :param name: The name of the profile. + :param dir: The directory of the profile. + :raises tiledb.TileDBError: + """ + super().__init__(name, dir) + + @property + def name(self): + """The name of the profile. + + :rtype: str + """ + return self._name + + @property + def dir(self): + """The directory of the profile. + + :rtype: str + """ + return self._dir + + def __repr__(self): + """String representation of the profile. + + :rtype: str + """ + return self._dump() + + def __setitem__(self, param: str, value: str): + """Sets a parameter for the profile. + + :param param: The parameter name. + :param value: The parameter value. + :raises tiledb.TileDBError: + """ + self._set_param(param, value) + + def __getitem__(self, param: str): + """Gets a parameter for the profile. + + :param param: The parameter name. + :raises tiledb.TileDBError: + """ + return self._get_param(param) + + def save(self): + """Saves the profile to storage. + + :raises tiledb.TileDBError: + """ + self._save() + + @classmethod + def load(cls, name: str = None, dir: str = None) -> "Profile": + """Loads a profile from storage. + + :param name: The name of the profile. + :param dir: The directory of the profile. + :return: The loaded profile. + :rtype: tiledb.Profile + :raises tiledb.TileDBError: + """ + # This is a workaround for the from_pybind11 method due to the fact + # that this class does not inherit from CtxMixin, as is commonly done. + lt_obj = lt.Profile._load(name, dir) + py_obj = cls.__new__(cls) + lt.Profile.__init__(py_obj, lt_obj) + return py_obj + + @classmethod + def remove(cls, name: str = None, dir: str = None): + """Removes a profile from storage. + + :param name: The name of the profile. + :param dir: The directory of the profile. + :raises tiledb.TileDBError: + """ + lt.Profile._remove(name, dir) From 7b5f9f9308466578063bbeb99f42870fc0d91bab Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Wed, 11 Jun 2025 16:52:01 +0300 Subject: [PATCH 02/12] Add tests --- tiledb/tests/test_profile.py | 138 +++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 tiledb/tests/test_profile.py diff --git a/tiledb/tests/test_profile.py b/tiledb/tests/test_profile.py new file mode 100644 index 0000000000..a2f9fa672c --- /dev/null +++ b/tiledb/tests/test_profile.py @@ -0,0 +1,138 @@ +import json +from pathlib import Path + +import pytest + +import tiledb +import tiledb.libtiledb as lt + +from .common import DiskTestCase + +if not (lt.version()[0] == 2 and lt.version()[1] >= 29): + pytest.skip( + "Profile is only available in TileDB 2.29 and later", + allow_module_level=True, + ) + +""" +Due to the nature of Profiles, they are touching the filesystem, +so we need to be careful and not affect the user's Profiles. +Thus we use DiskTestCase to create temporary directories. +""" + + +class ProfileTestCase(DiskTestCase): + def setup_method(self): + super().setup_method() + self.profile1 = tiledb.Profile( + dir=self.path("profile1_dir") + ) # profile with custom directory + self.profile2 = tiledb.Profile( + "profile2_name", self.path("profile2_dir") + ) # named profile with custom directory + + +class ProfileTest(ProfileTestCase): + def test_profile_name(self): + assert self.profile1.name == "default" + assert self.profile2.name == "profile2_name" + + def test_profile_dir(self): + assert Path(self.profile1.dir) == Path(self.path("profile1_dir")) + assert Path(self.profile2.dir) == Path(self.path("profile2_dir")) + + def test_profile_set_get_param(self): + username = "my_username" + server_address = "https://my.address" + + self.profile1["rest.username"] = username + assert self.profile1["rest.username"] == username + + self.profile1["rest.server_address"] = server_address + assert self.profile1["rest.server_address"] == server_address + + def test_profile_repr(self): + password = "testing_the_password" + payer_namespace = "testing_the_namespace" + server_address = "https://testing_the_address.com" + token = "testing_the_token" + username = "testing_the_username" + + self.profile1["rest.password"] = password + self.profile1["rest.payer_namespace"] = payer_namespace + self.profile1["rest.server_address"] = server_address + self.profile1["rest.token"] = token + self.profile1["rest.username"] = username + + goal_dict = { + "default": { + "rest.password": password, + "rest.payer_namespace": payer_namespace, + "rest.server_address": server_address, + "rest.token": token, + "rest.username": username, + } + } + + assert goal_dict == json.loads(repr(self.profile1)) + + def test_profile_save_load_remove(self): + token = "testing_the_token_for_profile2" + payer_namespace = "testing_the_namespace_for_profile2" + default_server_address = "https://api.tiledb.com" + + self.profile2["rest.token"] = token + self.profile2["rest.payer_namespace"] = payer_namespace + + # save the profile + self.profile2.save() + + # load the profile + loaded_profile = tiledb.Profile.load("profile2_name", self.path("profile2_dir")) + + # check that the loaded profile has the same parameters + assert loaded_profile.name == "profile2_name" + assert Path(loaded_profile.dir) == Path(self.path("profile2_dir")) + assert loaded_profile["rest.username"] == "" + assert loaded_profile["rest.password"] == "" + assert loaded_profile["rest.server_address"] == default_server_address + assert loaded_profile["rest.token"] == token + assert loaded_profile["rest.payer_namespace"] == payer_namespace + + # remove the profile + tiledb.Profile.remove("profile2_name", self.path("profile2_dir")) + + +class ConfigWithProfileTest(ProfileTestCase): + def test_config_with_profile(self): + username = "username_coming_from_profile" + password = "password_coming_from_profile" + server_address = "https://profile_address.com" + + # Create a profile and set some parameters + profile = tiledb.Profile(dir=self.path("profile_with_config_dir")) + profile["rest.username"] = username + profile["rest.password"] = password + profile["rest.server_address"] = server_address + + # Save the profile + profile.save() + + # ----- + # The above is done only once, so we can use the same profile later + # ----- + + # Create a config and set the profile directory + config = tiledb.Config() + config["profile_dir"] = self.path("profile_with_config_dir") + # Test that the config parameters are set correctly + assert config["rest.username"] == username + assert config["rest.password"] == password + assert config["rest.server_address"] == server_address + + # Alternatively, we can set the profile details directly in the Config constructor + config2 = tiledb.Config({"profile_dir": self.path("profile_with_config_dir")}) + # Test that the config parameters are set correctly + assert config2["rest.username"] == username + assert config2["rest.password"] == password + assert config2["rest.server_address"] == server_address From 61548ca6b49c74a517bfb2cc681a8e71b4ed7cdd Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Wed, 11 Jun 2025 16:52:05 +0300 Subject: [PATCH 03/12] Add example --- examples/profile.py | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 examples/profile.py diff --git a/examples/profile.py b/examples/profile.py new file mode 100644 index 0000000000..d392336efd --- /dev/null +++ b/examples/profile.py @@ -0,0 +1,76 @@ +# query_condition_sparse.py +# +# LICENSE +# +# The MIT License +# +# Copyright (c) 2025 TileDB, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +# This example demonstrates how to create, save, and use profiles in TileDB. +# It also shows how to remove profiles when they are no longer needed. + +import tiledb + + +def create_and_save_profiles(): + p1 = tiledb.Profile() + p1["rest.token"] = "my_token" + p1.save() + + p2 = tiledb.Profile("my_profile_name") + p2["rest.server_address"] = "https://my.address" + p2.save() + + +def use_profiles(): + # Create a config object. This will use the default profile. + cfg = tiledb.Config() + print("rest.token:", cfg["rest.token"]) + + # Create a config object using a specific profile name. + cfg_with_profile = tiledb.Config({"profile_name": "my_profile_name"}) + print("rest.server_address:", cfg_with_profile["rest.server_address"]) + + # Use on of the profile to create a context. + ctx = tiledb.Ctx(cfg_with_profile) + + # Use the context to create a new array. The REST credentials from the profile will be used. + array_name = "tiledb://my_workspace/my_teamspace/my_array" + dom = tiledb.Domain(tiledb.Dim(name="d", domain=(1, 10), tile=5, dtype="int32")) + schema = tiledb.ArraySchema( + domain=dom, sparse=False, attrs=[tiledb.Attr(name="a", dtype="float64")] + ) + tiledb.Array.create(array_name, schema, ctx=ctx) + + +def remove_profiles(): + # Remove the default profile + tiledb.Profile.remove() + + # Remove a specific profile by name + tiledb.Profile.remove("my_profile_name") + + +if __name__ == "__main__": + create_and_save_profiles() + use_profiles() + remove_profiles() From b2485a00d359119a97500b89bf49b654220dcd4f Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Mon, 16 Jun 2025 15:45:49 +0300 Subject: [PATCH 04/12] Raise `KeyError` exception for params not found --- tiledb/profile.py | 10 ++++++++-- tiledb/tests/test_profile.py | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tiledb/profile.py b/tiledb/profile.py index 7a851fd281..be809c5cb1 100644 --- a/tiledb/profile.py +++ b/tiledb/profile.py @@ -47,13 +47,19 @@ def __setitem__(self, param: str, value: str): """ self._set_param(param, value) - def __getitem__(self, param: str): + def __getitem__(self, param: str, raise_keyerror: bool = True): """Gets a parameter for the profile. :param param: The parameter name. :raises tiledb.TileDBError: """ - return self._get_param(param) + try: + return self._get_param(param) + except Exception: + if raise_keyerror: + raise KeyError(param) + else: + return None def save(self): """Saves the profile to storage. diff --git a/tiledb/tests/test_profile.py b/tiledb/tests/test_profile.py index a2f9fa672c..f0420f9719 100644 --- a/tiledb/tests/test_profile.py +++ b/tiledb/tests/test_profile.py @@ -63,6 +63,9 @@ def test_profile_repr(self): self.profile1["rest.server_address"] = server_address self.profile1["rest.token"] = token self.profile1["rest.username"] = username + with pytest.raises(KeyError): + # This should raise KeyError because the profile does not have this parameter + self.profile1["rest.non_existent_param"] goal_dict = { "default": { From 55628420b88bc43cb255845f50f1d7ef964a9905 Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Wed, 18 Jun 2025 16:23:56 +0300 Subject: [PATCH 05/12] Remove assertions with default Profile values --- tiledb/tests/test_profile.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tiledb/tests/test_profile.py b/tiledb/tests/test_profile.py index f0420f9719..8e37688df7 100644 --- a/tiledb/tests/test_profile.py +++ b/tiledb/tests/test_profile.py @@ -82,7 +82,6 @@ def test_profile_repr(self): def test_profile_save_load_remove(self): token = "testing_the_token_for_profile2" payer_namespace = "testing_the_namespace_for_profile2" - default_server_address = "https://api.tiledb.com" self.profile2["rest.token"] = token self.profile2["rest.payer_namespace"] = payer_namespace @@ -96,9 +95,6 @@ def test_profile_save_load_remove(self): # check that the loaded profile has the same parameters assert loaded_profile.name == "profile2_name" assert Path(loaded_profile.dir) == Path(self.path("profile2_dir")) - assert loaded_profile["rest.username"] == "" - assert loaded_profile["rest.password"] == "" - assert loaded_profile["rest.server_address"] == default_server_address assert loaded_profile["rest.token"] == token assert loaded_profile["rest.payer_namespace"] == payer_namespace From c7df25e86c16ea3cc427d31a3f4a9902643d3dd4 Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Thu, 19 Jun 2025 14:07:01 +0300 Subject: [PATCH 06/12] Mimic config getters --- tiledb/profile.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tiledb/profile.py b/tiledb/profile.py index be809c5cb1..3e9b9e4f28 100644 --- a/tiledb/profile.py +++ b/tiledb/profile.py @@ -47,10 +47,25 @@ def __setitem__(self, param: str, value: str): """ self._set_param(param, value) - def __getitem__(self, param: str, raise_keyerror: bool = True): + def __getitem__(self, param: str): """Gets a parameter for the profile. :param param: The parameter name. + :return: The parameter value. + :rtype: str + :raises KeyError: If the parameter does not exist. + :raises tiledb.TileDBError: + """ + return self.get(param, raise_keyerror=True) + + def get(self, param: str, raise_keyerror: bool = True): + """Gets a parameter for the profile. + + :param param: The parameter name. + :param raise_keyerror: Whether to raise a KeyError if the parameter does not exist. + :return: The parameter value or None if it does not exist and raise_keyerror is False. + :rtype: str or None + :raises KeyError: If the parameter does not exist and raise_keyerror is True. :raises tiledb.TileDBError: """ try: From 89dae3ad2e7769dc7cd65f7da606aeb44658bea1 Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Tue, 24 Jun 2025 16:39:06 +0300 Subject: [PATCH 07/12] Update based on libtiledb latest --- tiledb/profile.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tiledb/profile.py b/tiledb/profile.py index 3e9b9e4f28..255a2e8e12 100644 --- a/tiledb/profile.py +++ b/tiledb/profile.py @@ -68,13 +68,11 @@ def get(self, param: str, raise_keyerror: bool = True): :raises KeyError: If the parameter does not exist and raise_keyerror is True. :raises tiledb.TileDBError: """ - try: - return self._get_param(param) - except Exception: - if raise_keyerror: - raise KeyError(param) - else: - return None + val = self._get_param(param) + if val is None and raise_keyerror: + raise KeyError(param) + + return val def save(self): """Saves the profile to storage. From 2a8af741b4008f66beefffbd16d27700e50f716a Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Mon, 21 Jul 2025 17:46:27 +0300 Subject: [PATCH 08/12] Bump to libtiledb 2.28.1-rc1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4af2b04ea7..0b50b47364 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,8 +46,8 @@ if (NOT TileDB_FOUND) message(STATUS "Downloading TileDB default version ...") # Download latest release fetch_prebuilt_tiledb( - VERSION 2.28.0 - RELLIST_HASH SHA256=40c8a0b5b7ddfe6150e3ce390fd95761d2b7d5910ea3fd5c7dfb67d431e64660 + VERSION 2.28.1-rc1 + RELLIST_HASH SHA256=af1840944e71172463bbf5811ec4426db573c2baf4b708f1eb2c0546e2a3121e ) endif() find_package(TileDB REQUIRED) From 5516e0feac409f334198e7c5bff4098cff250b42 Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Mon, 21 Jul 2025 17:55:56 +0300 Subject: [PATCH 09/12] Correct libtiledb versions --- tiledb/__init__.py | 2 +- tiledb/libtiledb/profile.cc | 5 ++++- tiledb/tests/test_profile.py | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tiledb/__init__.py b/tiledb/__init__.py index 2d66839d09..eec386e350 100644 --- a/tiledb/__init__.py +++ b/tiledb/__init__.py @@ -25,7 +25,7 @@ from .current_domain import CurrentDomain from .ndrectangle import NDRectangle -if libtiledb_version()[0] == 2 and libtiledb_version()[1] >= 29: +if libtiledb_version() >= (2, 28, 1): from .profile import Profile del libtiledb_version # no longer needed diff --git a/tiledb/libtiledb/profile.cc b/tiledb/libtiledb/profile.cc index ca728c4479..70c388f6dc 100644 --- a/tiledb/libtiledb/profile.cc +++ b/tiledb/libtiledb/profile.cc @@ -14,7 +14,10 @@ using namespace tiledbpy::common; namespace py = pybind11; void init_profile(py::module& m) { -#if TILEDB_VERSION_MAJOR >= 2 && TILEDB_VERSION_MINOR >= 29 +#if TILEDB_VERSION_MAJOR > 2 || \ + (TILEDB_VERSION_MAJOR == 2 && TILEDB_VERSION_MINOR > 28) || \ + (TILEDB_VERSION_MAJOR == 2 && TILEDB_VERSION_MINOR == 28 && \ + TILEDB_VERSION_PATCH >= 1) py::class_(m, "Profile") .def( diff --git a/tiledb/tests/test_profile.py b/tiledb/tests/test_profile.py index 8e37688df7..a8f7ee618e 100644 --- a/tiledb/tests/test_profile.py +++ b/tiledb/tests/test_profile.py @@ -8,9 +8,9 @@ from .common import DiskTestCase -if not (lt.version()[0] == 2 and lt.version()[1] >= 29): +if lt.version() < (2, 28, 1): pytest.skip( - "Profile is only available in TileDB 2.29 and later", + "Profile is only available in TileDB 2.28.1 and later", allow_module_level=True, ) From 00788e12ff830339b3c108282189998a68bb91a1 Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Tue, 22 Jul 2025 13:56:23 +0300 Subject: [PATCH 10/12] Example: fetch CI credentials --- examples/profile.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/examples/profile.py b/examples/profile.py index d392336efd..8aafb4d4a9 100644 --- a/examples/profile.py +++ b/examples/profile.py @@ -28,12 +28,21 @@ # This example demonstrates how to create, save, and use profiles in TileDB. # It also shows how to remove profiles when they are no longer needed. +import datetime +import os +import random +import string + import tiledb +tiledb_token = os.getenv("TILEDB_TOKEN") +tiledb_namespace = os.getenv("TILEDB_NAMESPACE") +s3_bucket = os.getenv("S3_BUCKET") + def create_and_save_profiles(): p1 = tiledb.Profile() - p1["rest.token"] = "my_token" + p1["rest.token"] = tiledb_token p1.save() p2 = tiledb.Profile("my_profile_name") @@ -54,12 +63,19 @@ def use_profiles(): ctx = tiledb.Ctx(cfg_with_profile) # Use the context to create a new array. The REST credentials from the profile will be used. - array_name = "tiledb://my_workspace/my_teamspace/my_array" + # Useful to include the datetime in the array name to handle multiple consecutive runs of the test. + # Random letters are added to the end to ensure that conflicts are avoided, especially in CI environments where multiple tests may run in parallel. + array_name = ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + + "-" + + "".join(random.choice(string.ascii_letters) for _ in range(5)) + ) + uri = f"tiledb://{tiledb_namespace}/s3://{s3_bucket}/{array_name}" dom = tiledb.Domain(tiledb.Dim(name="d", domain=(1, 10), tile=5, dtype="int32")) schema = tiledb.ArraySchema( domain=dom, sparse=False, attrs=[tiledb.Attr(name="a", dtype="float64")] ) - tiledb.Array.create(array_name, schema, ctx=ctx) + tiledb.Array.create(uri, schema, ctx=ctx) def remove_profiles(): From f55f15c27319daf860a55559a12d4a783f3cdc92 Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Tue, 22 Jul 2025 14:57:08 +0300 Subject: [PATCH 11/12] Pass env --- tiledb/tests/test_examples.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tiledb/tests/test_examples.py b/tiledb/tests/test_examples.py index 4941347385..baa053a3a3 100644 --- a/tiledb/tests/test_examples.py +++ b/tiledb/tests/test_examples.py @@ -42,6 +42,9 @@ def test_examples(self, path): else: with tempfile.TemporaryDirectory() as tmpdir: try: + # Create environment with current env vars + env = os.environ.copy() + subprocess.run( [sys.executable, path], cwd=tmpdir, @@ -49,6 +52,7 @@ def test_examples(self, path): stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf8", + env=env, ) except subprocess.CalledProcessError as ex: pytest.fail(ex.stderr, pytrace=False) From 3ee07a9c824786239060ad6297c55ee1767a4a8c Mon Sep 17 00:00:00 2001 From: Agisilaos Kounelis Date: Tue, 22 Jul 2025 15:09:06 +0300 Subject: [PATCH 12/12] Fix --- examples/profile.py | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/examples/profile.py b/examples/profile.py index 8aafb4d4a9..d252951ebb 100644 --- a/examples/profile.py +++ b/examples/profile.py @@ -1,4 +1,4 @@ -# query_condition_sparse.py +# profile.py # # LICENSE # @@ -40,27 +40,19 @@ s3_bucket = os.getenv("S3_BUCKET") -def create_and_save_profiles(): - p1 = tiledb.Profile() +def create_and_save_profile(): + p1 = tiledb.Profile("my_profile_name") p1["rest.token"] = tiledb_token p1.save() - p2 = tiledb.Profile("my_profile_name") - p2["rest.server_address"] = "https://my.address" - p2.save() - -def use_profiles(): +def use_profile(): # Create a config object. This will use the default profile. - cfg = tiledb.Config() + cfg = tiledb.Config({"profile_name": "my_profile_name"}) print("rest.token:", cfg["rest.token"]) - # Create a config object using a specific profile name. - cfg_with_profile = tiledb.Config({"profile_name": "my_profile_name"}) - print("rest.server_address:", cfg_with_profile["rest.server_address"]) - # Use on of the profile to create a context. - ctx = tiledb.Ctx(cfg_with_profile) + ctx = tiledb.Ctx(cfg) # Use the context to create a new array. The REST credentials from the profile will be used. # Useful to include the datetime in the array name to handle multiple consecutive runs of the test. @@ -78,15 +70,12 @@ def use_profiles(): tiledb.Array.create(uri, schema, ctx=ctx) -def remove_profiles(): +def remove_profile(): # Remove the default profile - tiledb.Profile.remove() - - # Remove a specific profile by name tiledb.Profile.remove("my_profile_name") if __name__ == "__main__": - create_and_save_profiles() - use_profiles() - remove_profiles() + create_and_save_profile() + use_profile() + remove_profile()