Skip to content

[WIP] Wrap Profile #2189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tiledb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
from .current_domain import CurrentDomain
from .ndrectangle import NDRectangle

if libtiledb_version()[0] == 2 and libtiledb_version()[1] >= 28:
from .profile import Profile

del libtiledb_version # no longer needed

from .array import Array
Expand Down
1 change: 1 addition & 0 deletions tiledb/libtiledb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pybind11_add_module(
group.cc
metadata.h
object.cc
profile.cc
query.cc
schema.cc
subarray.cc
Expand Down
52 changes: 52 additions & 0 deletions tiledb/libtiledb/profile.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <tiledb/tiledb>
#include <tiledb/tiledb_experimental>

#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <pybind11/stl.h>

#include "common.h"

namespace libtiledbcpp {

using namespace tiledb;
using namespace tiledbpy::common;
namespace py = pybind11;

void init_profile(py::module& m) {
py::class_<tiledb::Profile>(m, "Profile")

.def(
py::init<std::optional<std::string>, std::optional<std::string>>(),
py::keep_alive<1, 2>())

.def(py::init<Profile>())

.def_property_readonly("_name", &tiledb::Profile::get_name)

.def_property_readonly("_homedir", &tiledb::Profile::get_homedir)

.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::string>,
std::optional<std::string>>(&tiledb::Profile::load),
py::arg("name") = std::nullopt,
py::arg("homedir") = std::nullopt)

.def("_remove", &tiledb::Profile::remove)

.def("_dump", &tiledb::Profile::dump);
}

} // namespace libtiledbcpp
2 changes: 2 additions & 0 deletions tiledb/libtiledb/tiledbcpp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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&);
Expand All @@ -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);
Expand Down
91 changes: 91 additions & 0 deletions tiledb/profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import tiledb.libtiledb as lt


class Profile(lt.Profile):
"""
Represents a TileDB profile.
"""

def __init__(self, name: str = None, homedir: str = None):
"""Class representing a TileDB profile.

:param name: The name of the profile.
:param homedir: The home directory of the profile.
:raises tiledb.TileDBError:
"""
super().__init__(name, homedir)

@property
def name(self):
"""The name of the profile.

:rtype: str
"""
return self._name

@property
def homedir(self):
"""The home directory of the profile.

:rtype: str
"""
return self._homedir

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, homedir: str = None) -> "Profile":
"""Loads a profile from storage.

:param name: The name of the profile.
:param homedir: The home 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, homedir)
py_obj = cls.__new__(cls)
lt.Profile.__init__(py_obj, lt_obj)
return py_obj

def remove(self):
"""Removes the profile from storage.

:raises tiledb.TileDBError:
"""
self._remove()

def dump(self):
"""Dumps the profile."""
print(self._dump(), "\n")
88 changes: 88 additions & 0 deletions tiledb/tests/test_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
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] >= 28):
pytest.skip(
"Profile is only available in TileDB 2.28 and later",
allow_module_level=True,
)


class ProfileTestCase(DiskTestCase):
def setup_method(self):
super().setup_method()
self.profile1 = tiledb.Profile() # default profile
self.profile2 = tiledb.Profile("test_profile") # named profile
self.profile3 = tiledb.Profile(
homedir=self.path("profile3_dir")
) # profile with custom home directory
self.profile4 = tiledb.Profile(
"test_profile", self.path("profile4_dir")
) # named profile with custom home directory


class ProfileTest(ProfileTestCase):
def test_profile_name(self):
assert self.profile1.name == "default"
assert self.profile2.name == "test_profile"
assert self.profile3.name == "default"
assert self.profile4.name == "test_profile"

def test_profile_homedir(self):
assert Path(self.profile1.homedir) == Path.home()
assert Path(self.profile2.homedir) == Path.home()
assert Path(self.profile3.homedir) == Path(self.path("profile3_dir"))
assert Path(self.profile4.homedir) == Path(self.path("profile4_dir"))

def test_profile_set_get_param(self):
self.profile1["rest.username"] = "my_username"
assert self.profile1["rest.username"] == "my_username"

self.profile3["rest.server_address"] = "https://myaddress.com"
assert self.profile3["rest.server_address"] == "https://myaddress.com"

def test_profile_repr(self):
self.profile1["rest.password"] = "testing_the_password"
self.profile1["rest.payer_namespace"] = "testing_the_namespace"
self.profile1["rest.server_address"] = "https://testing_the_address.com"
self.profile1["rest.token"] = "testing_the_token"
self.profile1["rest.username"] = "testing_the_username"

import json

goal_dict = {
"default": {
"rest.password": "testing_the_password",
"rest.payer_namespace": "testing_the_namespace",
"rest.server_address": "https://testing_the_address.com",
"rest.token": "testing_the_token",
"rest.username": "testing_the_username",
}
}

assert goal_dict == json.loads(repr(self.profile1))

def test_profile_set_save_load_get(self):
self.profile4["rest.token"] = "testing_the_token_for_profile4"
self.profile4["rest.payer_namespace"] = "testing_the_namespace_for_profile4"

# save the profile
self.profile4.save()

# load
new_profile = tiledb.Profile.load("test_profile", self.path("profile4_dir"))
assert new_profile.name == "test_profile"
assert new_profile.homedir == self.path("profile4_dir")
assert new_profile["rest.username"] == ""
assert new_profile["rest.password"] == ""
assert new_profile["rest.server_address"] == "https://api.tiledb.com"
assert new_profile["rest.token"] == "testing_the_token_for_profile4"
assert (
new_profile["rest.payer_namespace"] == "testing_the_namespace_for_profile4"
)
Loading