1
2 #include <pybind11/numpy.h>
3 #include <pybind11/pybind11.h>
4 #include <pybind11/pytypes.h>
5 #include <pybind11/stl.h>
6
7 #include <exception>
8
9 #define TILEDB_DEPRECATED
10 #define TILEDB_DEPRECATED_EXPORT
11
12 #include "util.h"
13 #include <tiledb/tiledb> // C++
14
15 #if TILEDB_VERSION_MAJOR == 2 && TILEDB_VERSION_MINOR >= 2
16
17 #if !defined(NDEBUG)
18 #include "debug.cc"
19 #endif
20
21 namespace tiledbpy {
22
23 using namespace std;
24 using namespace tiledb;
25 namespace py = pybind11;
26 using namespace pybind11::literals;
27
28 class PyFragmentInfo {
29
30 private:
31 Context ctx_;
32 shared_ptr<FragmentInfo> fi_;
33
34 public:
35 tiledb_ctx_t *c_ctx_;
36
37 public:
38 PyFragmentInfo() = delete;
39
PyFragmentInfo(const string & uri,py::object ctx)40 PyFragmentInfo(const string &uri, py::object ctx) {
41 if (ctx.is(py::none())) {
42 auto tiledblib = py::module::import("tiledb");
43 auto default_ctx = tiledblib.attr("default_ctx");
44 ctx = default_ctx();
45 }
46
47 tiledb_ctx_t *c_ctx_ = (py::capsule)ctx.attr("__capsule__")();
48
49 if (c_ctx_ == nullptr)
50 TPY_ERROR_LOC("Invalid context pointer!");
51
52 ctx_ = Context(c_ctx_, false);
53
54 fi_ = shared_ptr<tiledb::FragmentInfo>(new FragmentInfo(ctx_, uri));
55 }
56
57 template <typename T>
for_all_fid(T (FragmentInfo::* fn)(uint32_t)const) const58 py::object for_all_fid(T (FragmentInfo::*fn)(uint32_t) const) const {
59 py::list l;
60 uint32_t nfrag = fragment_num();
61
62 for (uint32_t i = 0; i < nfrag; ++i)
63 l.append((fi_.get()->*fn)(i));
64 return py::tuple(l);
65 }
66
load() const67 void load() const {
68 try {
69 fi_->load();
70 } catch (TileDBError &e) {
71 TPY_ERROR_LOC(e.what());
72 }
73 }
74
load(tiledb_encryption_type_t encryption_type,const string & encryption_key) const75 void load(tiledb_encryption_type_t encryption_type,
76 const string &encryption_key) const {
77 try {
78 fi_->load(encryption_type, encryption_key);
79 } catch (TileDBError &e) {
80 TPY_ERROR_LOC(e.what());
81 }
82 }
83
fragment_uri(py::object fid) const84 py::object fragment_uri(py::object fid) const {
85 return fid.is(py::none())
86 ? for_all_fid(&FragmentInfo::fragment_uri)
87 : py::str(fi_->fragment_uri(py::cast<uint32_t>(fid)));
88 }
89
get_non_empty_domain(py::object schema) const90 py::tuple get_non_empty_domain(py::object schema) const {
91 py::list all_frags;
92 uint32_t nfrag = fragment_num();
93
94 for (uint32_t fid = 0; fid < nfrag; ++fid)
95 all_frags.append(get_non_empty_domain(schema, fid));
96
97 return all_frags;
98 }
99
get_non_empty_domain(py::object schema,uint32_t fid) const100 py::tuple get_non_empty_domain(py::object schema, uint32_t fid) const {
101 py::list all_dims;
102 int ndim = (schema.attr("domain").attr("ndim")).cast<int>();
103
104 for (int did = 0; did < ndim; ++did)
105 all_dims.append(get_non_empty_domain(schema, fid, did));
106
107 return all_dims;
108 }
109
110 template <typename T>
get_non_empty_domain(py::object schema,uint32_t fid,T did) const111 py::tuple get_non_empty_domain(py::object schema, uint32_t fid, T did) const {
112 py::bool_ isvar = get_dim_isvar(schema.attr("domain"), did);
113
114 if (isvar) {
115 pair<string, string> lims = fi_->non_empty_domain_var(fid, did);
116 return py::make_tuple(lims.first, lims.second);
117 }
118
119 py::dtype type = get_dim_type(schema.attr("domain"), did);
120 py::dtype array_type =
121 type.kind() == 'M' ? pybind11::dtype::of<uint64_t>() : type;
122
123 py::array limits = py::array(array_type, 2);
124 py::buffer_info buffer = limits.request();
125 fi_->get_non_empty_domain(fid, did, buffer.ptr);
126
127 if (type.kind() == 'M') {
128 auto np = py::module::import("numpy");
129 auto datetime64 = np.attr("datetime64");
130 auto datetime_data = np.attr("datetime_data");
131
132 uint64_t *dates = static_cast<uint64_t *>(buffer.ptr);
133 limits = py::make_tuple(datetime64(dates[0], datetime_data(type)),
134 datetime64(dates[1], datetime_data(type)));
135 }
136
137 return limits;
138 }
139
get_dim_isvar(py::object dom,uint32_t did) const140 py::bool_ get_dim_isvar(py::object dom, uint32_t did) const {
141 // passing templated type "did" to Python function dom.attr("dim")
142 // does not work
143 return (dom.attr("dim")(did).attr("isvar")).cast<py::bool_>();
144 }
145
get_dim_isvar(py::object dom,string did) const146 py::bool_ get_dim_isvar(py::object dom, string did) const {
147 // passing templated type "did" to Python function dom.attr("dim")
148 // does not work
149 return (dom.attr("dim")(did).attr("isvar")).cast<py::bool_>();
150 }
151
get_dim_type(py::object dom,uint32_t did) const152 py::dtype get_dim_type(py::object dom, uint32_t did) const {
153 // passing templated type "did" to Python function dom.attr("dim")
154 // does not work
155 return (dom.attr("dim")(did).attr("dtype")).cast<py::dtype>();
156 }
157
get_dim_type(py::object dom,string did) const158 py::dtype get_dim_type(py::object dom, string did) const {
159 // passing templated type "did" to Python function dom.attr("dim")
160 // does not work
161 return (dom.attr("dim")(did).attr("dtype")).cast<py::dtype>();
162 }
163
timestamp_range(py::object fid) const164 py::object timestamp_range(py::object fid) const {
165 if (fid.is(py::none()))
166 return for_all_fid(&FragmentInfo::timestamp_range);
167
168 auto p = fi_->timestamp_range(py::cast<uint32_t>(fid));
169 return py::make_tuple(p.first, p.second);
170 }
171
fragment_num() const172 uint32_t fragment_num() const { return fi_->fragment_num(); }
173
dense(py::object fid) const174 py::object dense(py::object fid) const {
175 return fid.is(py::none()) ? for_all_fid(&FragmentInfo::dense)
176 : py::bool_(fi_->dense(py::cast<uint32_t>(fid)));
177 }
178
sparse(py::object fid) const179 py::object sparse(py::object fid) const {
180 return fid.is(py::none()) ? for_all_fid(&FragmentInfo::sparse)
181 : py::bool_(fi_->sparse(py::cast<uint32_t>(fid)));
182 }
183
cell_num(py::object fid) const184 py::object cell_num(py::object fid) const {
185 return fid.is(py::none())
186 ? for_all_fid(&FragmentInfo::cell_num)
187 : py::int_(fi_->cell_num(py::cast<uint32_t>(fid)));
188 }
189
version(py::object fid) const190 py::object version(py::object fid) const {
191 return fid.is(py::none()) ? for_all_fid(&FragmentInfo::version)
192 : py::int_(fi_->version(py::cast<uint32_t>(fid)));
193 }
194
has_consolidated_metadata(py::object fid) const195 py::object has_consolidated_metadata(py::object fid) const {
196 return fid.is(py::none())
197 ? for_all_fid(&FragmentInfo::has_consolidated_metadata)
198 : py::bool_(
199 fi_->has_consolidated_metadata(py::cast<uint32_t>(fid)));
200 }
201
unconsolidated_metadata_num() const202 uint32_t unconsolidated_metadata_num() const {
203 return fi_->unconsolidated_metadata_num();
204 }
205
to_vacuum_num() const206 uint32_t to_vacuum_num() const { return fi_->to_vacuum_num(); }
207
to_vacuum_uri(py::object fid) const208 py::object to_vacuum_uri(py::object fid) const {
209 return fid.is(py::none())
210 ? for_all_fid(&FragmentInfo::to_vacuum_uri)
211 : py::str(fi_->to_vacuum_uri(py::cast<uint32_t>(fid)));
212 }
213
dump() const214 void dump() const { return fi_->dump(stdout); }
215 };
216
PYBIND11_MODULE(_fragment,m)217 PYBIND11_MODULE(_fragment, m) {
218 py::class_<PyFragmentInfo>(m, "info")
219 .def(py::init<const string &, py::object>(), py::arg("uri"),
220 py::arg("ctx") = py::none())
221
222 .def("load",
223 static_cast<void (PyFragmentInfo::*)() const>(&PyFragmentInfo::load))
224 .def("load", static_cast<void (PyFragmentInfo::*)(
225 tiledb_encryption_type_t, const string &) const>(
226 &PyFragmentInfo::load))
227
228 .def("get_non_empty_domain",
229 static_cast<py::tuple (PyFragmentInfo::*)(py::object) const>(
230 &PyFragmentInfo::get_non_empty_domain))
231 .def("get_non_empty_domain",
232 static_cast<py::tuple (PyFragmentInfo::*)(py::object, uint32_t)
233 const>(&PyFragmentInfo::get_non_empty_domain))
234 .def("get_non_empty_domain", static_cast<py::tuple (PyFragmentInfo::*)(
235 py::object, uint32_t, uint32_t) const>(
236 &PyFragmentInfo::get_non_empty_domain))
237 .def("get_non_empty_domain",
238 static_cast<py::tuple (PyFragmentInfo::*)(py::object, uint32_t,
239 const string &) const>(
240 &PyFragmentInfo::get_non_empty_domain))
241
242 .def("fragment_uri", &PyFragmentInfo::fragment_uri,
243 py::arg("fid") = py::none())
244 .def("timestamp_range", &PyFragmentInfo::timestamp_range,
245 py::arg("fid") = py::none())
246 .def("fragment_num", &PyFragmentInfo::fragment_num)
247 .def("dense", &PyFragmentInfo::dense, py::arg("fid") = py::none())
248 .def("sparse", &PyFragmentInfo::sparse, py::arg("fid") = py::none())
249 .def("cell_num", &PyFragmentInfo::cell_num, py::arg("fid") = py::none())
250 .def("version", &PyFragmentInfo::version, py::arg("fid") = py::none())
251 .def("has_consolidated_metadata",
252 &PyFragmentInfo::has_consolidated_metadata,
253 py::arg("fid") = py::none())
254 .def("unconsolidated_metadata_num",
255 &PyFragmentInfo::unconsolidated_metadata_num)
256 .def("to_vacuum_num", &PyFragmentInfo::to_vacuum_num)
257 .def("to_vacuum_uri", &PyFragmentInfo::to_vacuum_uri,
258 py::arg("fid") = py::none())
259 .def("dump", &PyFragmentInfo::dump);
260 }
261
262 }; // namespace tiledbpy
263
264 #endif