Skip to content

Commit

Permalink
Fix the mysterious issue with ownership
Browse files Browse the repository at this point in the history
  • Loading branch information
Matevz Morato committed Mar 13, 2024
1 parent 4ac79a9 commit f6c09e7
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 163 deletions.
8 changes: 4 additions & 4 deletions cmake/Hunter/config.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Pybind11 2.9.2
# Pybind11 2.11.0-smart_holder
hunter_config(
pybind11
VERSION "2.9.2"
URL "https://github.com/pybind/pybind11/archive/refs/tags/v2.9.2.tar.gz"
SHA1 "5e05583a210282c3251281b6ee5677915f0cbf95"
VERSION "2.11.0-smart_holder"
URL "https://github.com/pybind/pybind11/archive/10283c2ef44a9100bc88d066a4972c4f51ded2b0.tar.gz"
SHA1 "0da09bdd6987a33feb800e4b7f129df5c9aa5aed"
)
4 changes: 2 additions & 2 deletions python_host_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def run(self):
print("hello world")

p = dai.Pipeline()
printer = Printer()
a = p.add(printer)
p.create(Printer)
a = p.add(Printer())
p.start()
p.wait()
265 changes: 133 additions & 132 deletions src/DeviceBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,135 +23,135 @@ PYBIND11_MAKE_OPAQUE(std::unordered_map<std::int8_t, dai::BoardConfig::UART>);
// Patch for bind_map naming
// Remove if it gets mainlined in pybind11
namespace pybind11 {

template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
class_<Map, holder_type> bind_map_patched(handle scope, const std::string &name, Args &&...args) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
using KeysView = detail::keys_view<Map>;
using ValuesView = detail::values_view<Map>;
using ItemsView = detail::items_view<Map>;
using Class_ = class_<Map, holder_type>;

// If either type is a non-module-local bound type then make the map binding non-local as well;
// otherwise (e.g. both types are either module-local or converting) the map will be
// module-local.
auto *tinfo = detail::get_type_info(typeid(MappedType));
bool local = !tinfo || tinfo->module_local;
if (local) {
tinfo = detail::get_type_info(typeid(KeyType));
local = !tinfo || tinfo->module_local;
}

Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
class_<KeysView> keys_view(
scope, ("KeysView_" + name).c_str(), pybind11::module_local(local));
class_<ValuesView> values_view(
scope, ("ValuesView_" + name).c_str(), pybind11::module_local(local));
class_<ItemsView> items_view(
scope, ("ItemsView_" + name).c_str(), pybind11::module_local(local));

cl.def(init<>());

// Register stream insertion operator (if possible)
detail::map_if_insertion_operator<Map, Class_>(cl, name);

cl.def(
"__bool__",
[](const Map &m) -> bool { return !m.empty(); },
"Check whether the map is nonempty");

cl.def(
"__iter__",
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */
);

cl.def(
"keys",
[](Map &m) { return KeysView{m}; },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);

cl.def(
"values",
[](Map &m) { return ValuesView{m}; },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);

cl.def(
"items",
[](Map &m) { return ItemsView{m}; },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);

cl.def(
"__getitem__",
[](Map &m, const KeyType &k) -> MappedType & {
auto it = m.find(k);
if (it == m.end()) {
throw key_error();
}
return it->second;
},
return_value_policy::reference_internal // ref + keepalive
);

cl.def("__contains__", [](Map &m, const KeyType &k) -> bool {
auto it = m.find(k);
if (it == m.end()) {
return false;
}
return true;
});
// Fallback for when the object is not of the key type
cl.def("__contains__", [](Map &, const object &) -> bool { return false; });

// Assignment provided only if the type is copyable
detail::map_assignment<Map, Class_>(cl);

cl.def("__delitem__", [](Map &m, const KeyType &k) {
auto it = m.find(k);
if (it == m.end()) {
throw key_error();
}
m.erase(it);
});

cl.def("__len__", &Map::size);

keys_view.def("__len__", [](KeysView &view) { return view.map.size(); });
keys_view.def(
"__iter__",
[](KeysView &view) { return make_key_iterator(view.map.begin(), view.map.end()); },
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);
keys_view.def("__contains__", [](KeysView &view, const KeyType &k) -> bool {
auto it = view.map.find(k);
if (it == view.map.end()) {
return false;
}
return true;
});
// Fallback for when the object is not of the key type
keys_view.def("__contains__", [](KeysView &, const object &) -> bool { return false; });

values_view.def("__len__", [](ValuesView &view) { return view.map.size(); });
values_view.def(
"__iter__",
[](ValuesView &view) { return make_value_iterator(view.map.begin(), view.map.end()); },
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);

items_view.def("__len__", [](ItemsView &view) { return view.map.size(); });
items_view.def(
"__iter__",
[](ItemsView &view) { return make_iterator(view.map.begin(), view.map.end()); },
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);

return cl;
}
// TODO(Morato) - check if fixed, doesn't compile on v2.11.1
// template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
// class_<Map, holder_type> bind_map_patched(handle scope, const std::string &name, Args &&...args) {
// using KeyType = typename Map::key_type;
// using MappedType = typename Map::mapped_type;
// using KeysView = detail::keys_view<Map>;
// using ValuesView = detail::values_view<Map>;
// using ItemsView = detail::items_view<Map>;
// using Class_ = class_<Map, holder_type>;

// // If either type is a non-module-local bound type then make the map binding non-local as well;
// // otherwise (e.g. both types are either module-local or converting) the map will be
// // module-local.
// auto *tinfo = detail::get_type_info(typeid(MappedType));
// bool local = !tinfo || tinfo->module_local;
// if (local) {
// tinfo = detail::get_type_info(typeid(KeyType));
// local = !tinfo || tinfo->module_local;
// }

// Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
// class_<KeysView> keys_view(
// scope, ("KeysView_" + name).c_str(), pybind11::module_local(local));
// class_<ValuesView> values_view(
// scope, ("ValuesView_" + name).c_str(), pybind11::module_local(local));
// class_<ItemsView> items_view(
// scope, ("ItemsView_" + name).c_str(), pybind11::module_local(local));

// cl.def(init<>());

// // Register stream insertion operator (if possible)
// detail::map_if_insertion_operator<Map, Class_>(cl, name);

// cl.def(
// "__bool__",
// [](const Map &m) -> bool { return !m.empty(); },
// "Check whether the map is nonempty");

// cl.def(
// "__iter__",
// [](Map &m) { return make_key_iterator(m.begin(), m.end()); },
// keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */
// );

// cl.def(
// "keys",
// [](Map &m) { return KeysView{m}; },
// keep_alive<0, 1>() /* Essential: keep map alive while view exists */
// );

// cl.def(
// "values",
// [](Map &m) { return ValuesView{m}; },
// keep_alive<0, 1>() /* Essential: keep map alive while view exists */
// );

// cl.def(
// "items",
// [](Map &m) { return ItemsView{m}; },
// keep_alive<0, 1>() /* Essential: keep map alive while view exists */
// );

// cl.def(
// "__getitem__",
// [](Map &m, const KeyType &k) -> MappedType & {
// auto it = m.find(k);
// if (it == m.end()) {
// throw key_error();
// }
// return it->second;
// },
// return_value_policy::reference_internal // ref + keepalive
// );

// cl.def("__contains__", [](Map &m, const KeyType &k) -> bool {
// auto it = m.find(k);
// if (it == m.end()) {
// return false;
// }
// return true;
// });
// // Fallback for when the object is not of the key type
// cl.def("__contains__", [](Map &, const object &) -> bool { return false; });

// // Assignment provided only if the type is copyable
// detail::map_assignment<Map, Class_>(cl);

// cl.def("__delitem__", [](Map &m, const KeyType &k) {
// auto it = m.find(k);
// if (it == m.end()) {
// throw key_error();
// }
// m.erase(it);
// });

// cl.def("__len__", &Map::size);

// keys_view.def("__len__", [](KeysView &view) { return view.map.size(); });
// keys_view.def(
// "__iter__",
// [](KeysView &view) { return make_key_iterator(view.map.begin(), view.map.end()); },
// keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
// );
// keys_view.def("__contains__", [](KeysView &view, const KeyType &k) -> bool {
// auto it = view.map.find(k);
// if (it == view.map.end()) {
// return false;
// }
// return true;
// });
// // Fallback for when the object is not of the key type
// keys_view.def("__contains__", [](KeysView &, const object &) -> bool { return false; });

// values_view.def("__len__", [](ValuesView &view) { return view.map.size(); });
// values_view.def(
// "__iter__",
// [](ValuesView &view) { return make_value_iterator(view.map.begin(), view.map.end()); },
// keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
// );

// items_view.def("__len__", [](ItemsView &view) { return view.map.size(); });
// items_view.def(
// "__iter__",
// [](ItemsView &view) { return make_iterator(view.map.begin(), view.map.end()); },
// keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
// );

// return cl;
// }

} // namespace pybind11

Expand Down Expand Up @@ -348,9 +348,10 @@ void DeviceBindings::bind(pybind11::module& m, void* pCallstack){
py::class_<PyClock> clock(m, "Clock");


py::bind_map_patched<std::unordered_map<std::int8_t, dai::BoardConfig::GPIO>>(boardConfig, "GPIOMap");
py::bind_map_patched<std::unordered_map<std::int8_t, dai::BoardConfig::UART>>(boardConfig, "UARTMap");

// py::bind_map_patched<std::unordered_map<std::int8_t, dai::BoardConfig::GPIO>>(boardConfig, "GPIOMap");
// py::bind_map_patched<std::unordered_map<std::int8_t, dai::BoardConfig::UART>>(boardConfig, "UARTMap");
py::bind_map<std::unordered_map<std::int8_t, dai::BoardConfig::GPIO>>(boardConfig, "GPIOMap");
py::bind_map<std::unordered_map<std::int8_t, dai::BoardConfig::UART>>(boardConfig, "UARTMap");

// pybind11 limitation of having actual classes as exceptions
// Possible but requires a larger workaround
Expand Down
31 changes: 6 additions & 25 deletions src/pipeline/PipelineBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,43 +121,24 @@ void PipelineBindings::bind(pybind11::module& m, void* pCallstack){
.def("add",
[](Pipeline &p, std::shared_ptr<Node> hostNode) {
p.add(hostNode);
// TODO(Morato) TMP TMP only a test
if (std::dynamic_pointer_cast<HostNode>(hostNode) != nullptr) {
std::dynamic_pointer_cast<HostNode>(hostNode)->run();
}
})
// 'Template' create function
.def("create",
[](dai::Pipeline &p, py::object class_) {
// TODO(zimen) re-introduce create function for custom host nodes
// if
// (py::cast<std::string>(class_.attr("__base__").attr("__name__"))
// == "HostNode") { Call the constructor of the class auto
// host_node =
// py::cast<std::shared_ptr<Node>>(class_.attr("__new__")(class_));
// std::cout << py::str(class_.attr("a")) << std::endl;
// class_().attr("run")();
// auto host_node = py::cast<std::shared_ptr<Node>>(class_());
// std::shared_ptr<HostNode> host_node =
// py::cast<std::shared_ptr<HostNode>>(class_());
// std::shared_ptr<HostNode> host_node =
// class_().cast<std::shared_ptr<HostNode>>();
// host_node->run();
// return class_();

// p.add(host_node);
// return (std::shared_ptr<Node>) host_node;
// return (std::shared_ptr<Node>) nullptr;
// }
if(py::cast<std::string>(class_.attr("__base__").attr("__name__")) == "HostNode") {
std::shared_ptr<Node> host_node = py::cast<std::shared_ptr<Node>>(class_());
p.add(host_node);
return host_node;
}
auto node = createNode(p, class_);
if (node == nullptr) {
throw std::invalid_argument(
std::string(py::str(class_)) +
" is not a subclass of depthai.node");
}
// Cast the node to a py::object
py::object obj = py::cast(node);
return obj;
return node;
})
// TODO(themarpe) DEPRECATE, use pipeline.create([class name])
// templated create<NODE> function
Expand Down

0 comments on commit f6c09e7

Please sign in to comment.