1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
#include <functional>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h> /* needed for std::vector! */
#include <pybind11/functional.h> /* for std::function */
namespace py = pybind11;
int scale(int a, float argument) {
return int(a*argument);
}
void voidFunction(int) {}
std::tuple<int, int, int> takingAListReturningATuple(const std::vector<float>&) {
return {};
}
template<std::size_t, class> struct Crazy {};
void crazySignature(const Crazy<3, int>&) {}
std::string overloaded(int) { return {}; }
bool overloaded(float) { return {}; }
// Doesn't work with just a plain function pointer, MEH
void takesAFunction(std::function<int(float, std::vector<float>&)>) {}
void takesAFunctionReturningVoid(std::function<void()>) {}
struct MyClass {
static MyClass staticFunction(int, float) { return {}; }
std::pair<float, int> instanceFunction(int, const std::string&) { return {0.5f, 42}; }
int another() { return 42; }
float foo() const { return _foo; }
void setFoo(float foo) { _foo = foo; }
private: float _foo = 0.0f;
};
struct MyClass23 {
void setFoo(float) {}
void setFooCrazy(const Crazy<3, int>&) {}
};
struct MyClass26 {
static int positionalOnly(int, float) { return 1; }
static int keywordOnly(float, const std::string&) { return 2; }
static int positionalKeywordOnly(int, float, const std::string&) { return 3; }
};
void duck(py::args, py::kwargs) {}
template<class T, class U> void tenOverloads(T, U) {}
PYBIND11_MODULE(pybind_signatures, m) {
m.doc() = "pybind11 function signature extraction";
m
.def("scale", &scale, "Scale an integer")
.def("scale_kwargs", &scale, "Scale an integer, kwargs", py::arg("a"), py::arg("argument"))
.def("void_function", &voidFunction, "Returns nothing")
.def("taking_a_list_returning_a_tuple", &takingAListReturningATuple, "Takes a list, returns a tuple")
.def("crazy_signature", &crazySignature, "Function that failed to get parsed")
.def("overloaded", static_cast<std::string(*)(int)>(&overloaded), "Overloaded for ints")
.def("overloaded", static_cast<bool(*)(float)>(&overloaded), "Overloaded for floats")
.def("duck", &duck, "A function taking args/kwargs directly")
.def("takes_a_function", &takesAFunction, "A function taking a Callable")
.def("takes_a_function_returning_none", &takesAFunctionReturningVoid, "A function taking a Callable that returns None")
.def("escape_docstring", &voidFunction, "A docstring that <em>should</em> be escaped")
.def("failed_parse_docstring", &crazySignature, "A failed parse should <strong>also</strong> escape the docstring")
.def("tenOverloads", &tenOverloads<float, float>, "Ten overloads of a function")
.def("tenOverloads", &tenOverloads<int, float>, "Ten overloads of a function")
.def("tenOverloads", &tenOverloads<bool, float>, "Ten overloads of a function")
.def("tenOverloads", &tenOverloads<float, int>, "Ten overloads of a function")
.def("tenOverloads", &tenOverloads<int, int>, "Ten overloads of a function")
.def("tenOverloads", &tenOverloads<bool, int>, "Ten overloads of a function")
.def("tenOverloads", &tenOverloads<float, bool>, "Ten overloads of a function")
.def("tenOverloads", &tenOverloads<int, bool>, "Ten overloads of a function")
.def("tenOverloads", &tenOverloads<bool, bool>, "Ten overloads of a function")
.def("tenOverloads", &tenOverloads<std::string, std::string>, "Ten overloads of a function")
.def("full_docstring", &voidFunction, R"(A summary
And a larger docstring as well.)")
.def("full_docstring_overloaded", &tenOverloads<int, int>, R"(An overload summary
This function takes a value of 2. full_docstring_overloaded(a: float, b: float)
takes just 3 instead.)")
.def("full_docstring_overloaded", &tenOverloads<float, float>, R"(Another overload summary
This overload, however, takes just a 32-bit (or 64-bit) floating point value of
3. full_docstring_overloaded(a: int, b: int)
takes just 2. There's nothing for 4. full_docstring_overloaded(a: poo, b: foo)
could be another, but it's not added yet.)");
py::class_<MyClass>(m, "MyClass", "My fun class!")
.def_static("static_function", &MyClass::staticFunction, "Static method with positional-only args")
.def(py::init(), "Constructor")
.def("instance_function", &MyClass::instanceFunction, "Instance method with positional-only args")
.def("instance_function_kwargs", &MyClass::instanceFunction, "Instance method with position or keyword args", py::arg("hey"), py::arg("what") = "<eh?>")
.def("another", &MyClass::another, "Instance method with no args, 'self' is thus position-only")
.def_property("foo", &MyClass::foo, &MyClass::setFoo, "A read/write property")
.def_property_readonly("bar", &MyClass::foo, "A read-only property");
py::class_<MyClass23> pybind23{m, "MyClass23", "Testing pybind 2.3 features"};
/* Checker so the Python side can detect if testing pybind 2.3 features is
feasible */
pybind23.attr("is_pybind23") =
#if PYBIND11_VERSION_MAJOR*100 + PYBIND11_VERSION_MINOR >= 203
true
#else
false
#endif
;
#if PYBIND11_VERSION_MAJOR*100 + PYBIND11_VERSION_MINOR >= 203
pybind23
.def_property("writeonly", nullptr, &MyClass23::setFoo, "A write-only property")
.def_property("writeonly_crazy", nullptr, &MyClass23::setFooCrazy, "A write-only property with a type that can't be parsed");
#endif
py::class_<MyClass26> pybind26{m, "MyClass26", "Testing pybind 2.6 features"};
/* Checker so the Python side can detect if testing pybind 2.6 features is
feasible */
pybind26.attr("is_pybind26") =
#if PYBIND11_VERSION_MAJOR*100 + PYBIND11_VERSION_MINOR >= 206
true
#else
false
#endif
;
#if PYBIND11_VERSION_MAJOR*100 + PYBIND11_VERSION_MINOR >= 206
pybind26
.def_static("positional_only", &MyClass26::positionalOnly, "Positional-only arguments", py::arg("a"), py::pos_only{}, py::arg("b"))
.def_static("keyword_only", &MyClass26::keywordOnly, "Keyword-only arguments", py::arg("b"), py::kw_only{}, py::arg("keyword") = "no")
.def_static("positional_keyword_only", &MyClass26::positionalKeywordOnly, "Positional and keyword-only arguments", py::arg("a"), py::pos_only{}, py::arg("b"), py::kw_only{}, py::arg("keyword") = "no");
#endif
}
|