Skip to content

Commit baa9012

Browse files
authored
Update pybind11 to v3.0.0 (#7249)
* Allow `"` in return types when parsing with FunctionDoc * Removed NamespaceFix from docstring header (got moved into sphinx autodoc) * Updated pybind11 filesystem to use correct typing * Fixed usage of deprecated pybind11 functions. * Refactor enum bindings to use py::native_enum * Removed export_values() for conflicting enum values
1 parent 083210b commit baa9012

File tree

29 files changed

+274
-307
lines changed

29 files changed

+274
-307
lines changed

3rdparty/pybind11/pybind11.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ include(FetchContent)
33
FetchContent_Declare(
44
ext_pybind11
55
PREFIX pybind11
6-
URL https://github.com/pybind/pybind11/archive/refs/tags/v2.13.1.tar.gz
7-
URL_HASH SHA256=51631e88960a8856f9c497027f55c9f2f9115cafb08c0005439838a05ba17bfc
6+
URL https://github.com/pybind/pybind11/archive/refs/tags/v3.0.0.tar.gz
7+
URL_HASH SHA256=453b1a3e2b266c3ae9da872411cadb6d693ac18063bd73226d96cfb7015a200c
88
DOWNLOAD_DIR "${OPEN3D_THIRD_PARTY_DOWNLOAD_DIR}/pybind11"
99
)
1010

cpp/pybind/camera/camera.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ void pybind_camera_declarations(py::module &m) {
2121
"PinholeCameraIntrinsic class stores intrinsic camera matrix, and "
2222
"image height and width.");
2323
// open3d.camera.PinholeCameraIntrinsicParameters
24-
py::enum_<PinholeCameraIntrinsicParameters> pinhole_intr_params(
25-
m_camera, "PinholeCameraIntrinsicParameters", py::arithmetic(),
26-
"PinholeCameraIntrinsicParameters");
24+
py::native_enum<PinholeCameraIntrinsicParameters> pinhole_intr_params(
25+
m_camera, "PinholeCameraIntrinsicParameters", "enum.Enum",
26+
"Enum class that contains default camera intrinsic parameters for "
27+
"different sensors.");
2728
pinhole_intr_params
2829
.value("PrimeSenseDefault",
2930
PinholeCameraIntrinsicParameters::PrimeSenseDefault,
@@ -36,13 +37,8 @@ void pybind_camera_declarations(py::module &m) {
3637
PinholeCameraIntrinsicParameters::Kinect2ColorCameraDefault,
3738
"Default camera intrinsic parameter for Kinect2 color "
3839
"camera.")
39-
.export_values();
40-
pinhole_intr_params.attr("__doc__") = docstring::static_property(
41-
py::cpp_function([](py::handle arg) -> std::string {
42-
return "Enum class that contains default camera intrinsic "
43-
"parameters for different sensors.";
44-
}),
45-
py::none(), py::none(), "");
40+
.export_values()
41+
.finalize();
4642
py::class_<PinholeCameraParameters> pinhole_param(
4743
m_camera, "PinholeCameraParameters",
4844
"Contains both intrinsic and extrinsic pinhole camera parameters.");

cpp/pybind/core/device.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ void pybind_core_device_declarations(py::module &m) {
1818
py::class_<Device> device(
1919
m, "Device",
2020
"Device context specifying device type and device id.");
21-
py::enum_<Device::DeviceType>(device, "DeviceType")
21+
py::native_enum<Device::DeviceType>(device, "DeviceType", "enum.Enum")
2222
.value("CPU", Device::DeviceType::CPU)
2323
.value("CUDA", Device::DeviceType::CUDA)
2424
.value("SYCL", Device::DeviceType::SYCL)
25-
.export_values();
25+
.export_values()
26+
.finalize();
2627
}
2728
void pybind_core_device_definitions(py::module &m) {
2829
auto device = static_cast<py::class_<Device>>(m.attr("Device"));

cpp/pybind/core/dtype.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ namespace core {
1818
void pybind_core_dtype_declarations(py::module &m) {
1919
py::class_<Dtype, std::shared_ptr<Dtype>> dtype(m, "Dtype",
2020
"Open3D data types.");
21-
py::enum_<Dtype::DtypeCode>(dtype, "DtypeCode")
21+
py::native_enum<Dtype::DtypeCode>(dtype, "DtypeCode", "enum.Enum")
2222
.value("Undefined", Dtype::DtypeCode::Undefined)
2323
.value("Bool", Dtype::DtypeCode::Bool)
2424
.value("Int", Dtype::DtypeCode::Int)
2525
.value("UInt", Dtype::DtypeCode::UInt)
2626
.value("Float", Dtype::DtypeCode::Float)
27-
.value("Object", Dtype::DtypeCode::Object);
27+
.value("Object", Dtype::DtypeCode::Object)
28+
.finalize();
2829
}
2930
void pybind_core_dtype_definitions(py::module &m) {
3031
// open3d.core.Dtype class

cpp/pybind/core/tensor_accessor.cpp

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -78,39 +78,36 @@ static TensorKey ToTensorKey(const Tensor& key_tensor) {
7878
}
7979
}
8080

81-
/// Convert supported types to TensorKey. Infer types via type name and dynamic
82-
/// casting. Supported types:
81+
/// Convert supported types to TensorKey.
82+
/// Supported types:
8383
/// 1) int
8484
/// 2) slice
8585
/// 3) list
8686
/// 4) tuple
8787
/// 5) numpy.ndarray
8888
/// 6) Tensor
8989
static TensorKey PyHandleToTensorKey(const py::handle& item) {
90-
// Infer types from type name and dynamic casting.
91-
// See: https://github.com/pybind/pybind11/issues/84.
92-
std::string class_name(py::str(item.get_type()));
93-
if (class_name == "<class 'int'>") {
94-
return ToTensorKey(static_cast<int64_t>(item.cast<py::int_>()));
95-
} else if (class_name == "<class 'slice'>") {
96-
return ToTensorKey(item.cast<py::slice>());
97-
} else if (class_name == "<class 'list'>") {
98-
return ToTensorKey(item.cast<py::list>());
99-
} else if (class_name == "<class 'tuple'>") {
100-
return ToTensorKey(item.cast<py::tuple>());
101-
} else if (class_name == "<class 'numpy.ndarray'>") {
102-
return ToTensorKey(item.cast<py::array>());
103-
} else if (class_name.find("open3d") != std::string::npos &&
104-
class_name.find("Tensor") != std::string::npos) {
90+
if (py::isinstance<py::int_>(item)) {
91+
return ToTensorKey(
92+
static_cast<int64_t>(py::reinterpret_borrow<py::int_>(item)));
93+
} else if (py::isinstance<py::slice>(item)) {
94+
return ToTensorKey(py::reinterpret_borrow<py::slice>(item));
95+
} else if (py::isinstance<py::list>(item)) {
96+
return ToTensorKey(py::reinterpret_borrow<py::list>(item));
97+
} else if (py::isinstance<py::tuple>(item)) {
98+
return ToTensorKey(py::reinterpret_borrow<py::tuple>(item));
99+
} else if (py::isinstance<py::array>(item)) {
100+
return ToTensorKey(py::reinterpret_borrow<py::array>(item));
101+
} else if (py::isinstance<Tensor>(item)) {
105102
try {
106-
Tensor* tensor = item.cast<Tensor*>();
107-
return ToTensorKey(*tensor);
103+
return ToTensorKey(*item.cast<Tensor*>());
108104
} catch (...) {
109105
utility::LogError("Cannot cast index to Tensor.");
110106
}
111107
} else {
112-
utility::LogError("PyHandleToTensorKey has invalid key type {}.",
113-
class_name);
108+
utility::LogError(
109+
"PyHandleToTensorKey has invalid key type {}.",
110+
static_cast<std::string>(py::str(py::type::of(item))));
114111
}
115112
}
116113

cpp/pybind/core/tensor_converter.cpp

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -197,26 +197,30 @@ Tensor PyHandleToTensor(const py::handle& handle,
197197
// 5) tuple
198198
// 6) numpy.ndarray (value will be copied)
199199
// 7) Tensor (value will be copied)
200-
std::string class_name(py::str(handle.get_type()));
201-
if (class_name == "<class 'bool'>") {
202-
return BoolToTensor(static_cast<bool>(handle.cast<py::bool_>()), dtype,
203-
device);
204-
} else if (class_name == "<class 'int'>") {
205-
return IntToTensor(static_cast<int64_t>(handle.cast<py::int_>()), dtype,
206-
device);
207-
} else if (class_name == "<class 'float'>") {
208-
return DoubleToTensor(static_cast<double>(handle.cast<py::float_>()),
209-
dtype, device);
210-
} else if (class_name == "<class 'list'>") {
211-
return PyListToTensor(handle.cast<py::list>(), dtype, device);
212-
} else if (class_name == "<class 'tuple'>") {
213-
return PyTupleToTensor(handle.cast<py::tuple>(), dtype, device);
214-
} else if (class_name == "<class 'numpy.ndarray'>") {
215-
return CastOptionalDtypeDevice(PyArrayToTensor(handle.cast<py::array>(),
216-
/*inplace=*/!force_copy),
217-
dtype, device);
218-
} else if (class_name.find("open3d") != std::string::npos &&
219-
class_name.find("Tensor") != std::string::npos) {
200+
if (py::isinstance<py::bool_>(handle)) {
201+
return BoolToTensor(
202+
static_cast<bool>(py::reinterpret_borrow<py::bool_>(handle)),
203+
dtype, device);
204+
} else if (py::isinstance<py::int_>(handle)) {
205+
return IntToTensor(
206+
static_cast<int64_t>(py::reinterpret_borrow<py::int_>(handle)),
207+
dtype, device);
208+
} else if (py::isinstance<py::float_>(handle)) {
209+
return DoubleToTensor(
210+
static_cast<double>(py::reinterpret_borrow<py::float_>(handle)),
211+
dtype, device);
212+
} else if (py::isinstance<py::list>(handle)) {
213+
return PyListToTensor(py::reinterpret_borrow<py::list>(handle), dtype,
214+
device);
215+
} else if (py::isinstance<py::tuple>(handle)) {
216+
return PyTupleToTensor(py::reinterpret_borrow<py::tuple>(handle), dtype,
217+
device);
218+
} else if (py::isinstance<py::array>(handle)) {
219+
return CastOptionalDtypeDevice(
220+
PyArrayToTensor(py::reinterpret_borrow<py::array>(handle),
221+
/*inplace=*/!force_copy),
222+
dtype, device);
223+
} else if (py::isinstance<Tensor>(handle)) {
220224
try {
221225
Tensor* tensor = handle.cast<Tensor*>();
222226
if (force_copy) {
@@ -228,8 +232,9 @@ Tensor PyHandleToTensor(const py::handle& handle,
228232
utility::LogError("Cannot cast index to Tensor.");
229233
}
230234
} else {
231-
utility::LogError("PyHandleToTensor has invalid input type {}.",
232-
class_name);
235+
utility::LogError(
236+
"PyHandleToTensor has invalid input type {}.",
237+
static_cast<std::string>(py::str(py::type::of(handle))));
233238
}
234239
}
235240

cpp/pybind/core/tensor_type_caster.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ bool type_caster<open3d::core::Tensor>::load(handle src, bool convert) {
1919
}
2020

2121
if (convert) {
22-
std::string class_name(py::str(src.get_type()));
23-
if (class_name == "<class 'bool'>" || class_name == "<class 'int'>" ||
24-
class_name == "<class 'float'>" || class_name == "<class 'list'>" ||
25-
class_name == "<class 'tuple'>" ||
26-
class_name == "<class 'numpy.ndarray'>") {
22+
if (py::isinstance<py::bool_>(src) || py::isinstance<py::int_>(src) ||
23+
py::isinstance<py::float_>(src) || py::isinstance<py::list>(src) ||
24+
py::isinstance<py::tuple>(src) || py::isinstance<py::array>(src)) {
2725
holder_ = std::make_unique<open3d::core::Tensor>(
2826
open3d::core::PyHandleToTensor(src));
2927
value = holder_.get();

cpp/pybind/docstring.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,9 @@ size_t FunctionDoc::ParseSummary() {
138138
overload_docs_.push_back(OverloadDocs{});
139139
size_t result_type_pos = arrow_pos + 4;
140140
size_t summary_start_pos =
141-
result_type_pos +
142-
utility::WordLength(pybind_doc_, result_type_pos, "._:,[]() ,");
141+
result_type_pos + utility::WordLength(pybind_doc_,
142+
result_type_pos,
143+
"._:,[]() ,\"");
143144
summary_end_pos =
144145
pybind_doc_.find(". " + name_ + "(", summary_start_pos);
145146
if (summary_end_pos == std::string::npos)
@@ -177,7 +178,7 @@ void FunctionDoc::ParseReturn() {
177178
std::string return_type = pybind_doc_.substr(
178179
result_type_pos,
179180
utility::WordLength(pybind_doc_, result_type_pos,
180-
"._:,[]() ,"));
181+
"._:,[]() ,\""));
181182
overload_docs_.back().return_doc_.type_ = StringCleanAll(return_type);
182183
}
183184
}

cpp/pybind/docstring.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,6 @@ class FunctionDoc {
6666
/// Generate Google style python docstring.
6767
std::string ToGoogleDocString() const;
6868

69-
/// Apply fixes to namespace, e.g. "::" to "." for python
70-
static std::string NamespaceFix(const std::string& s);
71-
7269
protected:
7370
/// Parse the function name from docstring.
7471
///

cpp/pybind/geometry/geometry.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,9 @@ namespace geometry {
1717
void pybind_geometry_classes_declarations(py::module &m) {
1818
py::class_<Geometry, PyGeometry<Geometry>, std::shared_ptr<Geometry>>
1919
geometry(m, "Geometry", "The base geometry class.");
20-
py::enum_<Geometry::GeometryType> geometry_type(geometry, "Type",
21-
py::arithmetic());
22-
// Trick to write docs without listing the members in the enum class again.
23-
geometry_type.attr("__doc__") = docstring::static_property(
24-
py::cpp_function([](py::handle arg) -> std::string {
25-
return "Enum class for Geometry types.";
26-
}),
27-
py::none(), py::none(), "");
28-
29-
geometry_type.value("Unspecified", Geometry::GeometryType::Unspecified)
20+
py::native_enum<Geometry::GeometryType>(geometry, "Type", "enum.Enum",
21+
"Enum class for Geometry types.")
22+
.value("Unspecified", Geometry::GeometryType::Unspecified)
3023
.value("PointCloud", Geometry::GeometryType::PointCloud)
3124
.value("VoxelGrid", Geometry::GeometryType::VoxelGrid)
3225
.value("LineSet", Geometry::GeometryType::LineSet)
@@ -36,7 +29,8 @@ void pybind_geometry_classes_declarations(py::module &m) {
3629
.value("Image", Geometry::GeometryType::Image)
3730
.value("RGBDImage", Geometry::GeometryType::RGBDImage)
3831
.value("TetraMesh", Geometry::GeometryType::TetraMesh)
39-
.export_values();
32+
.export_values()
33+
.finalize();
4034
py::class_<Geometry3D, PyGeometry3D<Geometry3D>,
4135
std::shared_ptr<Geometry3D>, Geometry>
4236
geometry3d(m, "Geometry3D",

0 commit comments

Comments
 (0)