mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-18 06:30:54 +00:00
Merge d57ed515a8
into 83b92ceb35
This commit is contained in:
commit
6c732c1c10
@ -1172,7 +1172,7 @@ protected:
|
||||
};
|
||||
|
||||
inline std::string quote_cpp_type_name(const std::string &cpp_type_name) {
|
||||
return cpp_type_name; // No-op for now. See PR #4888
|
||||
return "`" + cpp_type_name + "`"; // See PR #4888
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) {
|
||||
|
@ -113,6 +113,7 @@ set(PYBIND11_TEST_FILES
|
||||
test_builtin_casters
|
||||
test_call_policies
|
||||
test_callbacks
|
||||
test_cases_for_stubgen
|
||||
test_chrono
|
||||
test_class
|
||||
test_const_name
|
||||
|
222
tests/test_cases_for_stubgen.cpp
Normal file
222
tests/test_cases_for_stubgen.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
#include "pybind11/stl.h"
|
||||
#include "pybind11/stl_bind.h"
|
||||
#include "pybind11_tests.h"
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace test_cases_for_stubgen {
|
||||
|
||||
// The `basics` code was copied from here (to have all test cases for stubgen in one place):
|
||||
// https://github.com/python/mypy/blob/c6cb3c6282003dd3dadcf028735f9ba6190a0c84/test-data/pybind11_mypy_demo/src/main.cpp
|
||||
// Copyright (c) 2016 The Pybind Development Team, All rights reserved.
|
||||
|
||||
namespace basics {
|
||||
|
||||
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); }
|
||||
|
||||
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 basics
|
||||
|
||||
void bind_basics(py::module &basics) {
|
||||
|
||||
using namespace basics;
|
||||
|
||||
// Functions
|
||||
basics.def(
|
||||
"answer", &answer, "answer docstring, with end quote\""); // tests explicit docstrings
|
||||
basics.def("sum", &sum, "multiline docstring test, edge case quotes \"\"\"'''");
|
||||
basics.def("midpoint", &midpoint, py::arg("left"), py::arg("right"));
|
||||
basics.def("weighted_midpoint",
|
||||
weighted_midpoint,
|
||||
py::arg("left"),
|
||||
py::arg("right"),
|
||||
py::arg("alpha") = 0.5);
|
||||
|
||||
// Classes
|
||||
py::class_<Point> pyPoint(basics, "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"))
|
||||
#ifdef PYBIND11_CPP14
|
||||
.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"))
|
||||
#else
|
||||
.def("distance_to",
|
||||
static_cast<double (Point::*)(double, double) const>(&Point::distance_to),
|
||||
py::arg("x"),
|
||||
py::arg("y"))
|
||||
.def("distance_to",
|
||||
static_cast<double (Point::*)(const Point &) const>(&Point::distance_to),
|
||||
py::arg("other"))
|
||||
#endif
|
||||
.def_readwrite("x", &Point::x)
|
||||
.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::handle /*cls*/) { return Point::x_axis; })
|
||||
.def_property_readonly_static("y_axis", [](py::handle /*cls*/) { return Point::y_axis; })
|
||||
.def_readwrite_static("length_unit", &Point::length_unit)
|
||||
.def_property_static(
|
||||
"angle_unit",
|
||||
[](py::handle /*cls*/) { return Point::angle_unit; },
|
||||
[](py::handle /*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
|
||||
basics.attr("PI") = std::acos(-1);
|
||||
basics.attr("__version__") = "0.0.1";
|
||||
}
|
||||
|
||||
struct UserType {
|
||||
bool operator<(const UserType &) const { return false; }
|
||||
};
|
||||
|
||||
struct minimal_caster {
|
||||
static constexpr auto name = py::detail::const_name<UserType>();
|
||||
|
||||
static py::handle
|
||||
cast(UserType const & /*src*/, py::return_value_policy /*policy*/, py::handle /*parent*/) {
|
||||
return py::none().release();
|
||||
}
|
||||
|
||||
// Maximizing simplicity. This will go terribly wrong for other arg types.
|
||||
template <typename>
|
||||
using cast_op_type = const UserType &;
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
operator UserType const &() {
|
||||
static UserType obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool load(py::handle /*src*/, bool /*convert*/) { return false; }
|
||||
};
|
||||
|
||||
} // namespace test_cases_for_stubgen
|
||||
|
||||
namespace pybind11 {
|
||||
namespace detail {
|
||||
|
||||
template <>
|
||||
struct type_caster<test_cases_for_stubgen::UserType> : test_cases_for_stubgen::minimal_caster {};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace pybind11
|
||||
|
||||
PYBIND11_MAKE_OPAQUE(std::map<int, test_cases_for_stubgen::UserType>);
|
||||
PYBIND11_MAKE_OPAQUE(std::map<test_cases_for_stubgen::UserType, int>);
|
||||
PYBIND11_MAKE_OPAQUE(std::map<float, test_cases_for_stubgen::UserType>);
|
||||
PYBIND11_MAKE_OPAQUE(std::map<test_cases_for_stubgen::UserType, float>);
|
||||
|
||||
TEST_SUBMODULE(cases_for_stubgen, m) {
|
||||
auto basics = m.def_submodule("basics");
|
||||
test_cases_for_stubgen::bind_basics(basics);
|
||||
|
||||
using UserType = test_cases_for_stubgen::UserType;
|
||||
|
||||
m.def("pass_user_type", [](const UserType &) {});
|
||||
m.def("return_user_type", []() { return UserType(); });
|
||||
|
||||
py::bind_map<std::map<int, UserType>>(m, "MapIntUserType");
|
||||
py::bind_map<std::map<UserType, int>>(m, "MapUserTypeInt");
|
||||
|
||||
#define LOCAL_HELPER(MapTypePythonName, ...) \
|
||||
py::class_<__VA_ARGS__>(m, MapTypePythonName) \
|
||||
.def( \
|
||||
"keys", \
|
||||
[](const __VA_ARGS__ &v) { return py::make_key_iterator(v); }, \
|
||||
py::keep_alive<0, 1>()) \
|
||||
.def( \
|
||||
"values", \
|
||||
[](const __VA_ARGS__ &v) { return py::make_value_iterator(v); }, \
|
||||
py::keep_alive<0, 1>()) \
|
||||
.def( \
|
||||
"__iter__", \
|
||||
[](const __VA_ARGS__ &v) { return py::make_iterator(v.begin(), v.end()); }, \
|
||||
py::keep_alive<0, 1>())
|
||||
|
||||
LOCAL_HELPER("MapFloatUserType", std::map<float, UserType>);
|
||||
LOCAL_HELPER("MapUserTypeFloat", std::map<UserType, float>);
|
||||
#undef LOCAL_HELPER
|
||||
|
||||
m.def("pass_std_array_int_2", [](const std::array<int, 2> &) {});
|
||||
m.def("return_std_array_int_3", []() { return std::array<int, 3>{{1, 2, 3}}; });
|
||||
|
||||
// Rather arbitrary, meant to be a torture test for recursive processing.
|
||||
using nested_case_01a = std::vector<std::array<int, 2>>;
|
||||
using nested_case_02a = std::vector<UserType>;
|
||||
using nested_case_03a = std::map<std::array<int, 2>, UserType>;
|
||||
using nested_case_04a = std::map<nested_case_01a, nested_case_02a>;
|
||||
using nested_case_05a = std::vector<nested_case_04a>;
|
||||
using nested_case_06a = std::map<nested_case_04a, nested_case_05a>;
|
||||
#define LOCAL_HELPER(name) m.def(#name, [](const name &) {})
|
||||
LOCAL_HELPER(nested_case_01a);
|
||||
LOCAL_HELPER(nested_case_02a);
|
||||
LOCAL_HELPER(nested_case_03a);
|
||||
LOCAL_HELPER(nested_case_04a);
|
||||
LOCAL_HELPER(nested_case_05a);
|
||||
LOCAL_HELPER(nested_case_06a);
|
||||
#undef LOCAL_HELPER
|
||||
}
|
45
tests/test_cases_for_stubgen.py
Normal file
45
tests/test_cases_for_stubgen.py
Normal file
@ -0,0 +1,45 @@
|
||||
import pytest
|
||||
|
||||
from pybind11_tests import cases_for_stubgen as m
|
||||
|
||||
TEST_CASES = {
|
||||
"m.basics.answer.__doc__": 'answer() -> int\n\nanswer docstring, with end quote"\n',
|
||||
"m.basics.sum.__doc__": "sum(arg0: int, arg1: int) -> int\n\nmultiline docstring test, edge case quotes \"\"\"'''\n",
|
||||
"m.basics.midpoint.__doc__": "midpoint(left: float, right: float) -> float\n",
|
||||
"m.basics.weighted_midpoint.__doc__": "weighted_midpoint(left: float, right: float, alpha: float = 0.5) -> float\n",
|
||||
"m.basics.Point.__init__.__doc__": "__init__(*args, **kwargs)\nOverloaded function.\n\n1. __init__(self: pybind11_tests.cases_for_stubgen.basics.Point) -> None\n\n2. __init__(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> None\n",
|
||||
"m.basics.Point.distance_to.__doc__": "distance_to(*args, **kwargs)\nOverloaded function.\n\n1. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, x: float, y: float) -> float\n\n2. distance_to(self: pybind11_tests.cases_for_stubgen.basics.Point, other: pybind11_tests.cases_for_stubgen.basics.Point) -> float\n",
|
||||
"m.basics.Point.length_unit.__doc__": "Members:\n\n mm\n\n pixel\n\n inch",
|
||||
"m.basics.Point.angle_unit.__doc__": "Members:\n\n radian\n\n degree",
|
||||
"m.pass_user_type.__doc__": "pass_user_type(arg0: `test_cases_for_stubgen::UserType`) -> None\n",
|
||||
"m.return_user_type.__doc__": "return_user_type() -> `test_cases_for_stubgen::UserType`\n",
|
||||
"m.MapIntUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.KeysView\n",
|
||||
"m.MapIntUserType.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ValuesView\n",
|
||||
"m.MapIntUserType.items.__doc__": "items(self: pybind11_tests.cases_for_stubgen.MapIntUserType) -> pybind11_tests.cases_for_stubgen.ItemsView\n",
|
||||
"m.MapUserTypeInt.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.KeysView\n",
|
||||
"m.MapUserTypeInt.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ValuesView\n",
|
||||
"m.MapUserTypeInt.items.__doc__": "items(self: pybind11_tests.cases_for_stubgen.MapUserTypeInt) -> pybind11_tests.cases_for_stubgen.ItemsView\n",
|
||||
"m.MapFloatUserType.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[float]\n",
|
||||
"m.MapFloatUserType.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[`test_cases_for_stubgen::UserType`]\n",
|
||||
"m.MapFloatUserType.__iter__.__doc__": "__iter__(self: pybind11_tests.cases_for_stubgen.MapFloatUserType) -> Iterator[tuple[float, `test_cases_for_stubgen::UserType`]]\n",
|
||||
"m.MapUserTypeFloat.keys.__doc__": "keys(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[`test_cases_for_stubgen::UserType`]\n",
|
||||
"m.MapUserTypeFloat.values.__doc__": "values(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[float]\n",
|
||||
"m.MapUserTypeFloat.__iter__.__doc__": "__iter__(self: pybind11_tests.cases_for_stubgen.MapUserTypeFloat) -> Iterator[tuple[`test_cases_for_stubgen::UserType`, float]]\n",
|
||||
"m.pass_std_array_int_2.__doc__": "pass_std_array_int_2(arg0: Annotated[list[int], FixedSize(2)]) -> None\n",
|
||||
"m.return_std_array_int_3.__doc__": "return_std_array_int_3() -> Annotated[list[int], FixedSize(3)]\n",
|
||||
"m.nested_case_01a.__doc__": "nested_case_01a(arg0: list[Annotated[list[int], FixedSize(2)]]) -> None\n",
|
||||
"m.nested_case_02a.__doc__": "nested_case_02a(arg0: list[`test_cases_for_stubgen::UserType`]) -> None\n",
|
||||
"m.nested_case_03a.__doc__": "nested_case_03a(arg0: dict[Annotated[list[int], FixedSize(2)], `test_cases_for_stubgen::UserType`]) -> None\n",
|
||||
"m.nested_case_04a.__doc__": "nested_case_04a(arg0: dict[list[Annotated[list[int], FixedSize(2)]], list[`test_cases_for_stubgen::UserType`]]) -> None\n",
|
||||
"m.nested_case_05a.__doc__": "nested_case_05a(arg0: list[dict[list[Annotated[list[int], FixedSize(2)]], list[`test_cases_for_stubgen::UserType`]]]) -> None\n",
|
||||
"m.nested_case_06a.__doc__": "nested_case_06a(arg0: dict[dict[list[Annotated[list[int], FixedSize(2)]], list[`test_cases_for_stubgen::UserType`]], list[dict[list[Annotated[list[int], FixedSize(2)]], list[`test_cases_for_stubgen::UserType`]]]]) -> None\n",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("test_case", TEST_CASES.keys())
|
||||
def test_docstring(test_case):
|
||||
assert dir(m) # Only direct use of m, to stop tooling from removing the import.
|
||||
# On some platforms the stl_binders module name prevails for KeysView, ValuesView, ItemsView.
|
||||
docstring = eval(test_case).replace(".stl_binders.", ".cases_for_stubgen.")
|
||||
expected = TEST_CASES[test_case]
|
||||
assert docstring == expected
|
@ -372,8 +372,8 @@ def test_complex_array():
|
||||
|
||||
def test_signature(doc):
|
||||
assert (
|
||||
doc(m.create_rec_nested)
|
||||
== "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
|
||||
doc(m.create_rec_nested) == "create_rec_nested(arg0: int) "
|
||||
"-> numpy.ndarray[`NestedStruct`]"
|
||||
)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user