blob: 4d275ab1fd7090f30c74b6476cff1538d8400faa [file] [log] [blame]
/**
* This file contains the pybind11 reference implementation for the stugen tests,
* and was originally inspired by:
*
* https://github.com/sizmailov/pybind11-mypy-demo
*
* Copyright (c) 2016 The Pybind Development Team, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You are under no obligation whatsoever to provide any bug fixes, patches, or
* upgrades to the features, functionality or performance of the source code
* ("Enhancements") to anyone; however, if you choose to make your Enhancements
* available either publicly, or directly to the author of this software, without
* imposing a separate written license agreement for such Enhancements, then you
* hereby grant the following license: a non-exclusive, royalty-free perpetual
* license to install, use, modify, prepare derivative works, incorporate into
* other computer software, distribute, and sublicense such enhancements or
* derivative works thereof, in binary and source code form.
*/
#include <cmath>
#include <filesystem>
#include <optional>
#include <utility>
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl/filesystem.h>
namespace py = pybind11;
// ----------------------------------------------------------------------------
// Dedicated test cases
// ----------------------------------------------------------------------------
std::vector<float> funcReturningVector()
{
return std::vector<float>{1.0, 2.0, 3.0};
}
std::pair<int, float> funcReturningPair()
{
return std::pair{42, 1.0};
}
std::optional<int> funcReturningOptional()
{
return std::nullopt;
}
std::filesystem::path funcReturningPath()
{
return std::filesystem::path{"foobar"};
}
namespace dummy_sub_namespace {
struct HasNoBinding{};
}
// We can enforce the case of an incomplete signature by referring to a type in
// some namespace that doesn't have a pybind11 binding.
dummy_sub_namespace::HasNoBinding funcIncompleteSignature()
{
return dummy_sub_namespace::HasNoBinding{};
}
struct TestStruct
{
int field_readwrite;
int field_readwrite_docstring;
int field_readonly;
};
struct StaticMethods
{
static int some_static_method(int a, int b) { return 42; }
static int overloaded_static_method(int value) { return 42; }
static double overloaded_static_method(double value) { return 1.0; }
};
// Bindings
void bind_test_cases(py::module& m) {
m.def("func_returning_vector", &funcReturningVector);
m.def("func_returning_pair", &funcReturningPair);
m.def("func_returning_optional", &funcReturningOptional);
m.def("func_returning_path", &funcReturningPath);
m.def("func_incomplete_signature", &funcIncompleteSignature);
py::class_<TestStruct>(m, "TestStruct")
.def_readwrite("field_readwrite", &TestStruct::field_readwrite)
.def_readwrite("field_readwrite_docstring", &TestStruct::field_readwrite_docstring, "some docstring")
.def_property_readonly(
"field_readonly",
[](const TestStruct& x) {
return x.field_readonly;
},
"some docstring");
// Static methods
py::class_<StaticMethods> pyStaticMethods(m, "StaticMethods");
pyStaticMethods
.def_static(
"some_static_method",
&StaticMethods::some_static_method, R"#(None)#", py::arg("a"), py::arg("b"))
.def_static(
"overloaded_static_method",
py::overload_cast<int>(&StaticMethods::overloaded_static_method), py::arg("value"))
.def_static(
"overloaded_static_method",
py::overload_cast<double>(&StaticMethods::overloaded_static_method), py::arg("value"));
}
// ----------------------------------------------------------------------------
// Original demo
// ----------------------------------------------------------------------------
namespace demo {
int answer() {
return 42;
}
int sum(int a, int b) {
return a + b;
}
double midpoint(double left, double right){
return left + (right - left)/2;
}
double weighted_midpoint(double left, double right, double alpha=0.5) {
return left + (right - left) * alpha;
}
struct Point {
enum class LengthUnit {
mm=0,
pixel,
inch
};
enum class AngleUnit {
radian=0,
degree
};
Point() : Point(0, 0) {}
Point(double x, double y) : x(x), y(y) {}
static const Point origin;
static const Point x_axis;
static const Point y_axis;
static LengthUnit length_unit;
static AngleUnit angle_unit;
double length() const {
return std::sqrt(x * x + y * y);
}
double distance_to(double other_x, double other_y) const {
double dx = x - other_x;
double dy = y - other_y;
return std::sqrt(dx*dx + dy*dy);
}
double distance_to(const Point& other) const {
return distance_to(other.x, other.y);
}
std::vector<double> as_vector()
{
return std::vector<double>{x, y};
}
double x, y;
};
const Point Point::origin = Point(0, 0);
const Point Point::x_axis = Point(1, 0);
const Point Point::y_axis = Point(0, 1);
Point::LengthUnit Point::length_unit = Point::LengthUnit::mm;
Point::AngleUnit Point::angle_unit = Point::AngleUnit::radian;
} // namespace: demo
// Bindings
void bind_demo(py::module& m) {
using namespace demo;
// Functions
m.def("answer", &answer, "answer docstring, with end quote\""); // tests explicit docstrings
m.def("sum", &sum, "multiline docstring test, edge case quotes \"\"\"'''");
m.def("midpoint", &midpoint, py::arg("left"), py::arg("right"));
m.def("weighted_midpoint", weighted_midpoint, py::arg("left"), py::arg("right"), py::arg("alpha")=0.5);
// Classes
py::class_<Point> pyPoint(m, "Point");
py::enum_<Point::LengthUnit> pyLengthUnit(pyPoint, "LengthUnit");
py::enum_<Point::AngleUnit> pyAngleUnit(pyPoint, "AngleUnit");
pyPoint
.def(py::init<>())
.def(py::init<double, double>(), py::arg("x"), py::arg("y"))
.def("distance_to", py::overload_cast<double, double>(&Point::distance_to, py::const_), py::arg("x"), py::arg("y"))
.def("distance_to", py::overload_cast<const Point&>(&Point::distance_to, py::const_), py::arg("other"))
.def("as_list", &Point::as_vector)
.def_readwrite("x", &Point::x, "some docstring")
.def_property("y",
[](Point& self){ return self.y; },
[](Point& self, double value){ self.y = value; }
)
.def_property_readonly("length", &Point::length)
.def_property_readonly_static("x_axis", [](py::object cls){return Point::x_axis;})
.def_property_readonly_static("y_axis", [](py::object cls){return Point::y_axis;}, "another docstring")
.def_readwrite_static("length_unit", &Point::length_unit)
.def_property_static("angle_unit",
[](py::object& /*cls*/){ return Point::angle_unit; },
[](py::object& /*cls*/, Point::AngleUnit value){ Point::angle_unit = value; }
);
pyPoint.attr("origin") = Point::origin;
pyLengthUnit
.value("mm", Point::LengthUnit::mm)
.value("pixel", Point::LengthUnit::pixel)
.value("inch", Point::LengthUnit::inch);
pyAngleUnit
.value("radian", Point::AngleUnit::radian)
.value("degree", Point::AngleUnit::degree);
// Module-level attributes
m.attr("PI") = std::acos(-1);
m.attr("__version__") = "0.0.1";
}
// ----------------------------------------------------------------------------
// Module entry point
// ----------------------------------------------------------------------------
PYBIND11_MODULE(pybind11_fixtures, m) {
bind_test_cases(m);
auto demo = m.def_submodule("demo");
bind_demo(demo);
}