ChimeraTK-ApplicationCore 04.09.00
Loading...
Searching...
No Matches
PyArrayAccessor.cc
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4#include "PyArrayAccessor.h"
5
6#include <ChimeraTK/PyConvert.h>
7
8#include <pybind11/stl.h>
9
10namespace py = pybind11;
11
12namespace ChimeraTK {
13
14 /********************************************************************************************************************/
15
16 template<template<typename> class AccessorType>
17 ArrayAccessorVariant PyArrayAccessor::createAccessor(ChimeraTK::DataType type, Module* owner, const std::string& name,
18 std::string unit, size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
19 std::optional<ArrayAccessorVariant> rv;
20 ChimeraTK::callForTypeNoVoid(type, [&](auto t) {
21 using UserType = decltype(t);
22 AccessorType<UserType> acc(owner, name, unit, nElements, description, tags);
23 rv.emplace(std::in_place_type<AccessorType<UserType>>, std::move(acc));
24 });
25 return std::move(rv.value());
26 }
27
28 /********************************************************************************************************************/
29
31 read();
32 return get();
33 }
34
35 /********************************************************************************************************************/
36
37 void PyArrayAccessor::setAndWrite(const pybind11::object& input) {
38 set(input);
39 write();
40 }
41 /********************************************************************************************************************/
42
44 size_t rv;
45 std::visit([&](auto& acc) { rv = acc.getNElements(); }, _accessor);
46 return rv;
47 }
48
49 /********************************************************************************************************************/
50
51 void PyArrayAccessor::set(const py::object& input) {
52 std::visit(
53 [&](auto& acc) {
54 using ACC = std::remove_reference<decltype(acc)>::type;
55 using expectedUserType = ACC::value_type;
56 std::vector<expectedUserType> converted = convertPyObject<expectedUserType>(input, false, true);
57 acc = converted;
58 },
59 _accessor);
60 }
61
62 /********************************************************************************************************************/
63
64 py::object PyArrayAccessor::get() const {
65 py::object rv;
66 std::visit(
67 [&](auto& acc) {
68 using ACC = typename std::remove_reference<decltype(acc)>::type;
69 using userType = typename ACC::value_type;
70 auto ndacc = boost::dynamic_pointer_cast<NDRegisterAccessor<userType>>(acc.getHighLevelImplElement());
71 if constexpr(std::is_same<userType, std::string>::value) {
72 // String arrays are not really supported by numpy, so we return a list instead
73 rv = py::cast(ndacc->accessChannel(0));
74 }
75 else {
76 auto ary = py::array(py::dtype::of<userType>(), {acc.getNElements()}, {sizeof(userType)},
77 ndacc->accessChannel(0).data(), py::cast(this));
78 assert(!ary.owndata()); // numpy must not own our buffers
79 rv = ary;
80 }
81 },
82 _accessor);
83 return rv;
84 }
85 /********************************************************************************************************************/
86
87 py::object PyArrayAccessor::getitem(size_t index) const {
88 py::object rv;
89 // Return the element as a numpy scalar of the matching user type (e.g. np.float32)
90 // so that single-element access is consistent with get().
91 std::visit(
92 [&](auto& acc) {
93 using ACC = std::remove_reference<decltype(acc)>::type;
94 using userType = typename ACC::value_type;
95 auto ndacc = boost::dynamic_pointer_cast<NDRegisterAccessor<userType>>(acc.getHighLevelImplElement());
96 if constexpr(std::is_same<userType, std::string>::value) {
97 // String arrays are not really supported by numpy, so we return a python string
98 rv = py::cast(ndacc->accessChannel(0)[index]);
99 }
100 else {
101 // Create a 1-element numpy array of the correct dtype pointing to this element and index it,
102 // so numpy returns the matching numpy scalar type (np.float32, np.int32, ...).
103 auto ary = py::array(
104 py::dtype::of<userType>(), {1}, {sizeof(userType)}, &ndacc->accessChannel(0)[index], py::cast(this));
105 assert(!ary.owndata()); // numpy must not own our buffers
106 rv = ary.attr("__getitem__")(py::int_(0));
107 }
108 },
109 _accessor);
110 return rv;
111 }
112
113 /********************************************************************************************************************/
114
115 void PyArrayAccessor::setitem(size_t index, const pybind11::object& input) {
116 std::visit(
117 [&](auto& acc) {
118 using ACC = std::remove_reference<decltype(acc)>::type;
119 using expectedUserType = ACC::value_type;
120
121 // TODO check whether we can disable Pass 2 of python argument conversion also for setitem,setslice
122 expectedUserType value = convertPyScalar<expectedUserType>(input);
123 acc[index] = value;
124 },
125 _accessor);
126 }
127
128 /********************************************************************************************************************/
129
130 void PyArrayAccessor::setslice(const py::slice& slice, const pybind11::object& input) {
131 std::visit(
132 [&](auto& acc) {
133 size_t start, stop, step, length;
134 if(!slice.compute(acc.getNElements(), &start, &stop, &step, &length)) {
135 throw pybind11::error_already_set();
136 }
137 using ACC = std::remove_reference<decltype(acc)>::type;
138 using expectedUserType = ACC::value_type;
139 expectedUserType value = convertPyScalar<expectedUserType>(input);
140 for(size_t i = start; i < stop; i += step) {
141 acc[i] = value;
142 }
143 },
144 _accessor);
145 }
146
147 /********************************************************************************************************************/
148
149 std::string PyArrayAccessor::repr(py::object& acc) {
150 if(not acc.cast<PyArrayAccessor&>().getTE().isInitialised()) {
151 return "<ArrayAccessor(not initialized)>";
152 }
153
154 std::string rep{"<ArrayAccessor(type="};
155 rep.append(py::cast<py::object>(py::cast(&acc).attr("getValueType")()).attr("__repr__")().cast<std::string>());
156 rep.append(", name=");
157 rep.append(py::cast(&acc).attr("getName")().cast<std::string>());
158 rep.append(", data=");
159 rep.append(py::cast<py::object>(py::cast(&acc).attr("__str__")()).cast<std::string>());
160 rep.append(", versionNumber=");
161 rep.append(py::cast<py::object>(py::cast(&acc).attr("getVersionNumber")()).attr("__repr__")().cast<std::string>());
162 rep.append(", dataValidity=");
163 rep.append(py::cast<py::object>(py::cast(&acc).attr("dataValidity")()).attr("__repr__")().cast<std::string>());
164 rep.append(")>");
165 return rep;
166 }
167 /********************************************************************************************************************/
168
170 py::buffer_info info;
171 std::visit(
172 [&](auto& acc) {
173 using ACC = typename std::remove_reference<decltype(acc)>::type;
174 using userType = typename ACC::value_type;
175 auto ndacc = boost::dynamic_pointer_cast<NDRegisterAccessor<userType>>(acc.getHighLevelImplElement());
176 if constexpr(std::is_same<userType, ChimeraTK::Boolean>::value) {
177 info.format = py::format_descriptor<bool>::format();
178 }
179 else if constexpr(std::is_same<userType, std::string>::value) {
180 // cannot implement
181 return;
182 }
183 else {
184 info.format = py::format_descriptor<userType>::format();
185 }
186 info.ptr = ndacc->accessChannel(0).data();
187 info.itemsize = sizeof(userType);
188 info.ndim = 1;
189 info.shape = {acc.getNElements()};
190 info.strides = {sizeof(userType)};
191 },
192 _accessor);
193 return info;
194 }
195
196 /********************************************************************************************************************/
197
199
200 /********************************************************************************************************************/
201
203 py::class_<PyArrayAccessor, PyTransferElementBase, std::unique_ptr<PyArrayAccessor, py::nodelete>> arrayacc(
204 m, "ArrayAccessor", py::buffer_protocol(), py::module_local());
205 arrayacc.def(py::init<>())
207 .def("read", &PyArrayAccessor::read,
208 "Read the data from the device.\n\nIf AccessMode::wait_for_new_data was set, this function will block "
209 "until new data has arrived. Otherwise it still might block for a short time until the data transfer was "
210 "complete.")
211 .def("readNonBlocking", &PyArrayAccessor::readNonBlocking,
212 "Read the next value, if available in the input buffer.\n\nIf AccessMode::wait_for_new_data was set, this "
213 "function returns immediately and the return value indicated if a new value was available (true) or not "
214 "(false).\n\nIf AccessMode::wait_for_new_data was not set, this function is identical to read(), which "
215 "will still return quickly. Depending on the actual transfer implementation, the backend might need to "
216 "transfer data to obtain the current value before returning. Also this function is not guaranteed to be "
217 "lock free. The return value will be always true in this mode.")
218 .def("readLatest", &PyArrayAccessor::readLatest,
219 "Read the latest value, discarding any other update since the last read if present.\n\nOtherwise this "
220 "function is identical to readNonBlocking(), i.e. it will never wait for new values and it will return "
221 "whether a new value was available if AccessMode::wait_for_new_data is set.")
222 .def("write", &PyArrayAccessor::write,
223 "Write the data to device.\n\nThe return value is true, old data was lost on the write transfer (e.g. due "
224 "to an buffer overflow). In case of an unbuffered write transfer, the return value will always be false.")
225 .def("writeDestructively", &PyArrayAccessor::writeDestructively,
226 "Just like write(), but allows the implementation to destroy the content of the user buffer in the "
227 "process.\n\nThis is an optional optimisation, hence there is a default implementation which just calls "
228 "the normal doWriteTransfer(). In any case, the application must expect the user buffer of the "
229 "TransferElement to contain undefined data after calling this function.")
230 .def("getName", &PyArrayAccessor::getName, "Returns the name that identifies the process variable.")
231 .def("getUnit", &PyArrayAccessor::getUnit,
232 "Returns the engineering unit.\n\nIf none was specified, it will default to ' n./ a.'")
233 .def("getDescription", &PyArrayAccessor::getDescription, "Returns the description of this variable/register.")
234 .def("getValueType", &PyArrayAccessor::getValueType,
235 "Returns the std::type_info for the value type of this transfer element.\n\nThis can be used to determine "
236 "the type at runtime.")
237 .def("getVersionNumber", &PyArrayAccessor::getVersionNumber,
238 "Returns the version number that is associated with the last transfer (i.e. last read or write)")
239 .def("isReadOnly", &PyArrayAccessor::isReadOnly,
240 "Check if transfer element is read only, i.e. it is readable but not writeable.")
241 .def("isReadable", &PyArrayAccessor::isReadable, "Check if transfer element is readable.")
242 .def("isWriteable", &PyArrayAccessor::isWriteable, "Check if transfer element is writeable.")
243 .def("getId", &PyArrayAccessor::getId,
244 "Obtain unique ID for the actual implementation of this TransferElement.\n\nThis means that e.g. two "
245 "instances of ScalarRegisterAccessor created by the same call to Device::getScalarRegisterAccessor() (e.g. "
246 "by copying the accessor to another using NDRegisterAccessorBridge::replace()) will have the same ID, "
247 "while two instances obtained by to difference calls to Device::getScalarRegisterAccessor() will have a "
248 "different ID even when accessing the very same register.")
249 .def("dataValidity", &PyArrayAccessor::dataValidity,
250 "Return current validity of the data.\n\nWill always return DataValidity.ok if the backend does not "
251 "support it")
252 .def("getNElements", &PyArrayAccessor::getNElements, "Return number of elements/samples in the register.")
253 .def("get", &PyArrayAccessor::get, "Return an array of UserType (without a previous read).")
254 .def("set", &PyArrayAccessor::set, "Set the values of the array of UserType.", py::arg("newValue"))
255 .def("setAndWrite", &PyArrayAccessor::setAndWrite,
256 "Convenience function to set and write new value.\n\nThe given version number. If versionNumber == {}, a "
257 "new version number is generated.",
258 py::arg("newValue"))
259 .def(
260 "readAndGet", &PyArrayAccessor::readAndGet, "Convenience function to read and return an array of UserType.")
261 .def("__repr__", &PyArrayAccessor::repr)
262 .def("__getitem__", &PyArrayAccessor::getitem)
263 .def("__setitem__", &PyArrayAccessor::setitem, "", py::arg("index"), py::arg("newValue"))
264 .def("__setitem__", &PyArrayAccessor::setslice, "", py::arg("slice"), py::arg("newValue"))
265 .def("__getattr__", &PyArrayAccessor::getattr);
267 arrayacc.def(fn.c_str(),
268 [fn](PyArrayAccessor& acc, PyArrayAccessor& other) { return acc.get().attr(fn.c_str())(other.get()); });
269 arrayacc.def(
270 fn.c_str(), [fn](PyArrayAccessor& acc, py::object& other) { return acc.get().attr(fn.c_str())(other); });
271 }
273 arrayacc.def(fn.c_str(), [fn](PyArrayAccessor& acc) { return acc.get().attr(fn.c_str())(); });
274 }
275
279 m.def(
280 "ArrayPushInput",
281 [](ChimeraTK::DataType type, VariableGroup& owner, const std::string& name, const std::string& unit,
282 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
283 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
284 AccessorTypeTag<ArrayPushInput>{}, type, &owner, name, unit, nElements, description, tags);
285 },
286 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
287 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
288 "");
289 m.def(
290 "ArrayPushInput",
291 [](ChimeraTK::DataType::TheType type, VariableGroup& owner, const std::string& name, const std::string& unit,
292 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
293 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
294 AccessorTypeTag<ArrayPushInput>{}, DataType(type), &owner, name, unit, nElements, description, tags);
295 },
296 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
297 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
298 "");
299
303 m.def(
304 "ArrayPushInputWB",
305 [](ChimeraTK::DataType type, VariableGroup& owner, const std::string& name, const std::string& unit,
306 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
307 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
308 AccessorTypeTag<ArrayPushInputWB>{}, type, &owner, name, unit, nElements, description, tags);
309 },
310 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
311 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
312 "");
313 m.def(
314 "ArrayPushInputWB",
315 [](ChimeraTK::DataType::TheType type, VariableGroup& owner, const std::string& name, const std::string& unit,
316 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
317 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
318 AccessorTypeTag<ArrayPushInputWB>{}, DataType(type), &owner, name, unit, nElements, description, tags);
319 },
320 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
321 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
322 "");
323
327 m.def(
328 "ArrayPollInput",
329 [](ChimeraTK::DataType type, VariableGroup& owner, const std::string& name, const std::string& unit,
330 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
331 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
332 AccessorTypeTag<ArrayPollInput>{}, type, &owner, name, unit, nElements, description, tags);
333 },
334 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
335 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
336 "");
337 m.def(
338 "ArrayPollInput",
339 [](ChimeraTK::DataType::TheType type, VariableGroup& owner, const std::string& name, const std::string& unit,
340 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
341 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
342 AccessorTypeTag<ArrayPollInput>{}, DataType(type), &owner, name, unit, nElements, description, tags);
343 },
344 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
345 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
346 "");
347
351 m.def(
352 "ArrayOutput",
353 [](ChimeraTK::DataType type, VariableGroup& owner, const std::string& name, const std::string& unit,
354 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
355 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
356 AccessorTypeTag<ArrayOutput>{}, type, &owner, name, unit, nElements, description, tags);
357 },
358 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
359 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
360 "");
361 m.def(
362 "ArrayOutput",
363 [](ChimeraTK::DataType::TheType type, VariableGroup& owner, const std::string& name, const std::string& unit,
364 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
365 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
366 AccessorTypeTag<ArrayOutput>{}, DataType(type), &owner, name, unit, nElements, description, tags);
367 },
368 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
369 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
370 "");
371
375 m.def(
376 "ArrayOutputPushRB",
377 [](ChimeraTK::DataType type, VariableGroup& owner, const std::string& name, const std::string& unit,
378 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
379 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
380 AccessorTypeTag<ArrayOutputPushRB>{}, type, &owner, name, unit, nElements, description, tags);
381 },
382 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
383 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
384 "");
385 m.def(
386 "ArrayOutputPushRB",
387 [](ChimeraTK::DataType::TheType type, VariableGroup& owner, const std::string& name, const std::string& unit,
388 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
389 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
390 AccessorTypeTag<ArrayOutputPushRB>{}, DataType(type), &owner, name, unit, nElements, description, tags);
391 },
392 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
393 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
394 "");
395
399 m.def(
400 "ArrayOutputReverseRecovery",
401 [](ChimeraTK::DataType type, VariableGroup& owner, const std::string& name, const std::string& unit,
402 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
403 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
404 AccessorTypeTag<ArrayOutputReverseRecovery>{}, type, &owner, name, unit, nElements, description, tags);
405 },
406 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
407 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
408 "");
409 m.def(
410 "ArrayOutputReverseRecovery",
411 [](ChimeraTK::DataType::TheType type, VariableGroup& owner, const std::string& name, const std::string& unit,
412 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
413 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
414 AccessorTypeTag<ArrayOutputReverseRecovery>{}, DataType(type), &owner, name, unit, nElements, description,
415 tags);
416 },
417 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
418 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
419 "");
420
424 m.def(
425 "ArrayPushInputNoInitialValue",
426 [](ChimeraTK::DataType type, VariableGroup& owner, const std::string& name, const std::string& unit,
427 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
428 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
429 AccessorTypeTag<ArrayPushInputNoInitialValue>{}, type, &owner, name, unit, nElements, description, tags);
430 },
431 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
432 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
433 "");
434 m.def(
435 "ArrayPushInputNoInitialValue",
436 [](ChimeraTK::DataType::TheType type, VariableGroup& owner, const std::string& name, const std::string& unit,
437 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
438 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
439 AccessorTypeTag<ArrayPushInputNoInitialValue>{}, DataType(type), &owner, name, unit, nElements,
440 description, tags);
441 },
442 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
443 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
444 "");
445
449 m.def(
450 "ArrayPollInputNoInitialValue",
451 [](ChimeraTK::DataType type, VariableGroup& owner, const std::string& name, const std::string& unit,
452 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
453 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
454 AccessorTypeTag<ArrayPollInputNoInitialValue>{}, type, &owner, name, unit, nElements, description, tags);
455 },
456 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
457 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
458 "");
459 m.def(
460 "ArrayPollInputNoInitialValue",
461 [](ChimeraTK::DataType::TheType type, VariableGroup& owner, const std::string& name, const std::string& unit,
462 size_t nElements, const std::string& description, const std::unordered_set<std::string>& tags) {
463 return dynamic_cast<PyOwningObject&>(owner).make_child<PyArrayAccessor>(
464 AccessorTypeTag<ArrayPollInputNoInitialValue>{}, DataType(type), &owner, name, unit, nElements,
465 description, tags);
466 },
467 py::arg("type"), py::arg("owner"), py::arg("name"), py::arg("unit"), py::arg("nElements"),
468 py::arg("description"), py::arg("tags") = std::unordered_set<std::string>{}, py::return_value_policy::reference,
469 "");
470 }
471
472 /********************************************************************************************************************/
473
474} // namespace ChimeraTK
Helper class acting as a ArrayAccessor with a variant UserType.
py::object getitem(size_t index) const
void setAndWrite(const pybind11::object &input)
static void bind(py::module &mod)
void set(const pybind11::object &input)
void setitem(size_t index, const pybind11::object &input)
static std::string repr(py::object &acc)
void setslice(const py::slice &slice, const pybind11::object &input)
py::buffer_info getBufferInfo()
ArrayAccessorVariant _accessor
py::object getattr(const std::string &name) const
Base class used for all objects in the Python world which can own other objects and can be owned them...
static const std::set< std::string > specialUnaryFunctionsToEmulateNumeric
static const std::set< std::string > specialFunctionsToEmulateNumeric
const TransferElementAbstractor & getTE() const final
InvalidityTracer application module.
typename detail::NestedVariant< UserTypeTemplateVariantNoVoid< ArrayAccessor >, UserTypeTemplateVariantNoVoid< ArrayPollInput >, UserTypeTemplateVariantNoVoid< ArrayPushInput >, UserTypeTemplateVariantNoVoid< ArrayOutput >, UserTypeTemplateVariantNoVoid< ArrayPushInputWB >, UserTypeTemplateVariantNoVoid< ArrayOutputPushRB >, UserTypeTemplateVariantNoVoid< ArrayOutputReverseRecovery >, UserTypeTemplateVariantNoVoid< ArrayPushInputNoInitialValue >, UserTypeTemplateVariantNoVoid< ArrayPollInputNoInitialValue > >::type ArrayAccessorVariant
All concrete array accessor types used by the Python bindings.
module_ module