Skip to content

Commit 32eee30

Browse files
committed
Fix issue with generator bindings.
1 parent 32d24d8 commit 32eee30

File tree

3 files changed

+46
-25
lines changed

3 files changed

+46
-25
lines changed

src/mobase/wrappers/pyfiletree.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ namespace mo2::detail {
4949
return std::make_shared<PyFileTree>(parent, name, m_Callback);
5050
}
5151

52-
bool doPopulate(std::shared_ptr<const IFileTree> parent,
52+
bool doPopulate([[maybe_unused]] std::shared_ptr<const IFileTree> parent,
5353
std::vector<std::shared_ptr<FileTreeEntry>>&) const override
5454
{
5555
return true;
@@ -83,10 +83,6 @@ namespace mo2::python {
8383

8484
void add_ifiletree_bindings(pybind11::module_& m)
8585
{
86-
87-
// register generator for walk and glob
88-
register_generator_type<std::shared_ptr<const FileTreeEntry>>(m);
89-
9086
// FileTreeEntry class:
9187
auto fileTreeEntryClass =
9288
py::class_<FileTreeEntry, std::shared_ptr<FileTreeEntry>>(m,
@@ -191,10 +187,17 @@ namespace mo2::python {
191187
QString>(&IFileTree::walk, py::const_),
192188
py::arg("callback"), py::arg("sep") = "\\");
193189

194-
iFileTreeClass.def("walk", py::overload_cast<>(&IFileTree::walk, py::const_));
190+
iFileTreeClass.def("walk", [](IFileTree const* tree) {
191+
return make_generator(tree->walk());
192+
});
195193

196-
iFileTreeClass.def("glob", &IFileTree::glob, py::arg("pattern"),
197-
py::arg("type") = IFileTree::GlobPatternType::GLOB);
194+
iFileTreeClass.def(
195+
"glob", // &IFileTree::glob,
196+
[](IFileTree const* tree, QString pattern,
197+
IFileTree::GlobPatternType patternType) {
198+
return make_generator(tree->glob(pattern, patternType));
199+
},
200+
py::arg("pattern"), py::arg("type") = IFileTree::GlobPatternType::GLOB);
198201

199202
// Kind-of-static operations:
200203
iFileTreeClass.def("createOrphanTree", &IFileTree::createOrphanTree,

src/pybind11-utils/include/pybind11_utils/generator.h

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,46 @@
77

88
namespace mo2::python {
99

10+
// the code here is mostly taken from pybind11 itself, and relies on some pybind11
11+
// internals so might be subject to change when upgrading pybind11 versions
12+
13+
namespace detail {
14+
template <typename T>
15+
struct generator_state {
16+
std::generator<T> g;
17+
decltype(g.begin()) it;
18+
19+
generator_state(std::generator<T> gen) : g(std::move(gen)), it(g.begin()) {}
20+
};
21+
} // namespace detail
22+
1023
// create a Python generator from a C++ generator
1124
//
1225
template <typename T>
13-
auto register_generator_type(pybind11::handle scope,
14-
const char* name = "_mo2_generator")
26+
auto make_generator(std::generator<T> g)
1527
{
28+
using state = detail::generator_state<T>;
29+
1630
namespace py = pybind11;
31+
if (!py::detail::get_type_info(typeid(state), false)) {
32+
py::class_<state>(py::handle(), "iterator", pybind11::module_local())
33+
.def("__iter__",
34+
[](state& s) -> state& {
35+
return s;
36+
})
37+
.def("__next__", [](state& s) {
38+
if (s.it != s.g.end()) {
39+
const auto v = *s.it;
40+
s.it++;
41+
return v;
42+
}
43+
else {
44+
throw py::stop_iteration();
45+
}
46+
});
47+
}
1748

18-
return py::class_<std::generator<T>>(scope, name, py::module_local())
19-
.def("__iter__",
20-
[](std::generator<T>& gen) -> std::generator<T>& {
21-
return gen;
22-
})
23-
.def("__next__", [](std::generator<T>& gen) {
24-
auto it = gen.begin();
25-
if (it != gen.end()) {
26-
return *it;
27-
}
28-
else {
29-
throw py::stop_iteration();
30-
}
31-
});
49+
return py::cast(state{std::move(g)});
3250
}
3351

3452
} // namespace mo2::python

tests/python/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ foreach (test_file ${test_files})
5353
pybind11_add_module(${target} EXCLUDE_FROM_ALL THIN_LTO ${test_file})
5454
set_target_properties(${target}
5555
PROPERTIES
56-
CXX_STANDARD 20
56+
CXX_STANDARD 23
5757
OUTPUT_NAME ${pymodule}
5858
FOLDER tests/python
5959
LIBRARY_OUTPUT_DIRECTORY "${PYLIB_DIR}/mobase_tests")

0 commit comments

Comments
 (0)