Skip to content

Commit 601516a

Browse files
authored
Fixes for pybind11-stubgen errors (#6896)
* Added open3d.core.Dtype.DtypeCode enum bindings. * Changed TransformationEstimationPointToPoint.__repr__. * Added __repr__ for Margins to provide nicer default values. * Added TextureHandle binding. * Improved __repr__ for SLACDebugOption and SLACOptimizerParams. * Improved arguments with enum default values using py::arg_v. * Fixed false tokens in GetArgumentTokens when docstring contains ",". * Added type annotations to func signature output by ToGoogleDocString. * Changed kdtree __repr__ methods to return proper constructor call. * Fixed more __repr__ methods to return proper constructor calls. * Replaced substr with resize to fix codacy issue. * Define `capsule` as `Any` type to fix pybind11-stubgen error. * Added `m` and `n` as TypeVars to fix stubgen when using Eigen::MatrixXd.
1 parent f2461a3 commit 601516a

File tree

19 files changed

+166
-96
lines changed

19 files changed

+166
-96
lines changed

cpp/pybind/camera/camera.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,12 @@ void pybind_camera_definitions(py::module &m) {
9393
"0, cx], [0, fy, "
9494
"cy], [0, 0, 1]]``")
9595
.def("__repr__", [](const PinholeCameraIntrinsic &c) {
96-
return std::string("PinholeCameraIntrinsic with width = ") +
97-
std::to_string(c.width_) +
98-
std::string(" and height = ") +
99-
std::to_string(c.height_) +
100-
std::string(
101-
".\nAccess intrinsics with intrinsic_matrix.");
96+
return fmt::format(
97+
"PinholeCameraIntrinsic("
98+
"width={}, "
99+
"height={}, "
100+
")",
101+
c.width_, c.height_);
102102
});
103103
docstring::ClassMethodDocInject(m_camera, "PinholeCameraIntrinsic",
104104
"__init__");

cpp/pybind/core/dtype.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ 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")
22+
.value("Undefined", Dtype::DtypeCode::Undefined)
23+
.value("Bool", Dtype::DtypeCode::Bool)
24+
.value("Int", Dtype::DtypeCode::Int)
25+
.value("UInt", Dtype::DtypeCode::UInt)
26+
.value("Float", Dtype::DtypeCode::Float)
27+
.value("Object", Dtype::DtypeCode::Object);
2128
}
2229
void pybind_core_dtype_definitions(py::module &m) {
2330
// open3d.core.Dtype class

cpp/pybind/core/tensor.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ void pybind_core_tensor_declarations(py::module& m) {
254254
py::class_<Tensor> tensor(
255255
m, "Tensor",
256256
"A Tensor is a view of a data Blob with shape, stride, data_ptr.");
257+
m.attr("capsule") = py::module_::import("typing").attr("Any");
257258
}
258259
void pybind_core_tensor_definitions(py::module& m) {
259260
auto tensor = static_cast<py::class_<Tensor>>(m.attr("Tensor"));

cpp/pybind/docstring.cpp

+19-8
Original file line numberDiff line numberDiff line change
@@ -201,14 +201,24 @@ std::string FunctionDoc::ToGoogleDocString() const {
201201
for (size_t i = 0; i < overload.argument_docs_.size(); ++i) {
202202
const ArgumentDoc& argument_doc = overload.argument_docs_[i];
203203
rc << argument_doc.name_;
204+
if (argument_doc.type_ != "") {
205+
rc << ": " << argument_doc.type_;
206+
}
204207
if (argument_doc.default_ != "") {
205-
rc << "=" << argument_doc.default_;
208+
rc << " = " << argument_doc.default_;
206209
}
207210
if (i != overload.argument_docs_.size() - 1) {
208211
rc << ", ";
209212
}
210213
}
211-
rc << ")" << std::endl;
214+
rc << ")";
215+
216+
// Return type
217+
if (overload.return_doc_.type_ != "") {
218+
rc << " -> " << overload.return_doc_.type_;
219+
}
220+
221+
rc << std::endl;
212222

213223
// Summary line, strictly speaking this shall be at the very front.
214224
// However from a compiled Python module we need the function signature
@@ -347,6 +357,12 @@ std::vector<std::string> FunctionDoc::GetArgumentTokens(
347357
str.replace(parenthesis_pos + 1, 0, ", ");
348358
}
349359

360+
// Ignore everything after last argument (right before ") ->")
361+
// Otherwise false argument matches might be found in docstrings
362+
std::size_t arrow_pos = str.rfind(") -> ");
363+
if (arrow_pos == std::string::npos) return {};
364+
str.resize(arrow_pos);
365+
350366
// Get start positions
351367
std::regex pattern("(, [A-Za-z_][A-Za-z\\d_]*:)");
352368
std::smatch res;
@@ -366,12 +382,7 @@ std::vector<std::string> FunctionDoc::GetArgumentTokens(
366382
for (size_t i = 0; i + 1 < argument_start_positions.size(); ++i) {
367383
argument_end_positions.push_back(argument_start_positions[i + 1] - 2);
368384
}
369-
std::size_t arrow_pos = str.rfind(") -> ");
370-
if (arrow_pos == std::string::npos) {
371-
return {};
372-
} else {
373-
argument_end_positions.push_back(arrow_pos);
374-
}
385+
argument_end_positions.push_back(arrow_pos);
375386

376387
std::vector<std::string> argument_tokens;
377388
for (size_t i = 0; i < argument_start_positions.size(); ++i) {

cpp/pybind/geometry/geometry.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ void pybind_geometry_classes_declarations(py::module &m) {
4545
std::shared_ptr<Geometry2D>, Geometry>
4646
geometry2d(m, "Geometry2D",
4747
"The base geometry class for 2D geometries.");
48+
49+
m.attr("m") = py::module_::import("typing").attr("TypeVar")("m");
50+
m.attr("n") = py::module_::import("typing").attr("TypeVar")("n");
4851
}
4952
void pybind_geometry_classes_definitions(py::module &m) {
5053
// open3d.geometry functions

cpp/pybind/geometry/kdtreeflann.cpp

+13-13
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ void pybind_kdtreeflann_definitions(py::module &m) {
5858
kdtreesearchparam_knn.def(py::init<int>(), "knn"_a = 30)
5959
.def("__repr__",
6060
[](const KDTreeSearchParamKNN &param) {
61-
return std::string(
62-
"KDTreeSearchParamKNN with knn "
63-
"= ") +
64-
std::to_string(param.knn_);
61+
return fmt::format(
62+
"KDTreeSearchParamKNN("
63+
"knn={})",
64+
param.knn_);
6565
})
6666
.def_readwrite("knn", &KDTreeSearchParamKNN::knn_,
6767
"Number of the neighbors that will be searched.");
@@ -73,10 +73,10 @@ void pybind_kdtreeflann_definitions(py::module &m) {
7373
kdtreesearchparam_radius.def(py::init<double>(), "radius"_a)
7474
.def("__repr__",
7575
[](const KDTreeSearchParamRadius &param) {
76-
return std::string(
77-
"KDTreeSearchParamRadius with "
78-
"radius = ") +
79-
std::to_string(param.radius_);
76+
return fmt::format(
77+
"KDTreeSearchParamRadius("
78+
"radius={})",
79+
param.radius_);
8080
})
8181
.def_readwrite("radius", &KDTreeSearchParamRadius::radius_,
8282
"Search radius.");
@@ -89,11 +89,11 @@ void pybind_kdtreeflann_definitions(py::module &m) {
8989
.def(py::init<double, int>(), "radius"_a, "max_nn"_a)
9090
.def("__repr__",
9191
[](const KDTreeSearchParamHybrid &param) {
92-
return std::string(
93-
"KDTreeSearchParamHybrid with "
94-
"radius = ") +
95-
std::to_string(param.radius_) +
96-
" and max_nn = " + std::to_string(param.max_nn_);
92+
return fmt::format(
93+
"KDTreeSearchParamHybrid("
94+
"radius={}, "
95+
"max_nn={})",
96+
param.radius_, param.max_nn_);
9797
})
9898
.def_readwrite("radius", &KDTreeSearchParamHybrid::radius_,
9999
"Search radius.")

cpp/pybind/geometry/trianglemesh.cpp

+15-6
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,17 @@ void pybind_trianglemesh_definitions(py::module &m) {
110110
":math:`v_o = v_i x strength (v_i * |N| - \\sum_{n \\in N} "
111111
"v_n)`",
112112
"number_of_iterations"_a = 1, "strength"_a = 1,
113-
"filter_scope"_a = MeshBase::FilterScope::All)
113+
py::arg_v("filter_scope", MeshBase::FilterScope::All,
114+
"FilterScope.All"))
114115
.def("filter_smooth_simple", &TriangleMesh::FilterSmoothSimple,
115116
"Function to smooth triangle mesh with simple neighbour "
116117
"average. :math:`v_o = \\frac{v_i + \\sum_{n \\in N} "
117118
"v_n)}{|N| + 1}`, with :math:`v_i` being the input value, "
118119
":math:`v_o` the output value, and :math:`N` is the set of "
119120
"adjacent neighbours.",
120121
"number_of_iterations"_a = 1,
121-
"filter_scope"_a = MeshBase::FilterScope::All)
122+
py::arg_v("filter_scope", MeshBase::FilterScope::All,
123+
"FilterScope.All"))
122124
.def("filter_smooth_laplacian",
123125
&TriangleMesh::FilterSmoothLaplacian,
124126
"Function to smooth triangle mesh using Laplacian. :math:`v_o "
@@ -129,7 +131,8 @@ void pybind_trianglemesh_definitions(py::module &m) {
129131
"inverse distance (closer neighbours have higher weight), and "
130132
"lambda_filter is the smoothing parameter.",
131133
"number_of_iterations"_a = 1, "lambda_filter"_a = 0.5,
132-
"filter_scope"_a = MeshBase::FilterScope::All)
134+
py::arg_v("filter_scope", MeshBase::FilterScope::All,
135+
"FilterScope.All"))
133136
.def("filter_smooth_taubin", &TriangleMesh::FilterSmoothTaubin,
134137
"Function to smooth triangle mesh using method of Taubin, "
135138
"\"Curve and Surface Smoothing Without Shrinkage\", 1995. "
@@ -139,7 +142,9 @@ void pybind_trianglemesh_definitions(py::module &m) {
139142
"parameter mu as smoothing parameter. This method avoids "
140143
"shrinkage of the triangle mesh.",
141144
"number_of_iterations"_a = 1, "lambda_filter"_a = 0.5,
142-
"mu"_a = -0.53, "filter_scope"_a = MeshBase::FilterScope::All)
145+
"mu"_a = -0.53,
146+
py::arg_v("filter_scope", MeshBase::FilterScope::All,
147+
"FilterScope.All"))
143148
.def("has_vertices", &TriangleMesh::HasVertices,
144149
"Returns ``True`` if the mesh contains vertices.")
145150
.def("has_triangles", &TriangleMesh::HasTriangles,
@@ -250,7 +255,9 @@ void pybind_trianglemesh_definitions(py::module &m) {
250255
&TriangleMesh::SimplifyVertexClustering,
251256
"Function to simplify mesh using vertex clustering.",
252257
"voxel_size"_a,
253-
"contraction"_a = MeshBase::SimplificationContraction::Average)
258+
py::arg_v("contraction",
259+
MeshBase::SimplificationContraction::Average,
260+
"SimplificationContraction.Average"))
254261
.def("simplify_quadric_decimation",
255262
&TriangleMesh::SimplifyQuadricDecimation,
256263
"Function to simplify mesh using Quadric Error Metric "
@@ -298,7 +305,9 @@ void pybind_trianglemesh_definitions(py::module &m) {
298305
"'As-Rigid-As-Possible Surface Modeling', 2007",
299306
"constraint_vertex_indices"_a, "constraint_vertex_positions"_a,
300307
"max_iter"_a,
301-
"energy"_a = MeshBase::DeformAsRigidAsPossibleEnergy::Spokes,
308+
py::arg_v("energy",
309+
MeshBase::DeformAsRigidAsPossibleEnergy::Spokes,
310+
"DeformAsRigidAsPossibleEnergy.Spokes"),
302311
"smoothed_alpha"_a = 0.01)
303312
.def_static(
304313
"create_from_point_cloud_alpha_shape",

cpp/pybind/pipelines/odometry/odometry.cpp

+9-11
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,15 @@ void pybind_odometry_definitions(py::module &m) {
128128
c.iteration_number_per_pyramid_level_[i]) +
129129
", ";
130130
str_iteration_number_per_pyramid_level_ += "] ";
131-
return std::string("OdometryOption class.") +
132-
/*std::string("\nodo_init = ") +
133-
std::to_string(c.odo_init_) +*/
134-
std::string("\niteration_number_per_pyramid_level = ") +
135-
str_iteration_number_per_pyramid_level_ +
136-
std::string("\ndepth_diff_max = ") +
137-
std::to_string(c.depth_diff_max_) +
138-
std::string("\ndepth_min = ") +
139-
std::to_string(c.depth_min_) +
140-
std::string("\ndepth_max = ") +
141-
std::to_string(c.depth_max_);
131+
return fmt::format(
132+
"OdometryOption(\n"
133+
"iteration_number_per_pyramid_level={},\n"
134+
"depth_diff_max={},\n"
135+
"depth_min={},\n"
136+
"depth_max={},\n"
137+
")",
138+
str_iteration_number_per_pyramid_level_,
139+
c.depth_diff_max_, c.depth_min_, c.depth_max_);
142140
});
143141

144142
// open3d.odometry.RGBDOdometryJacobian

cpp/pybind/pipelines/registration/feature.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ void pybind_feature_declarations(py::module &m_registration) {
1919
py::class_<Feature, std::shared_ptr<Feature>> feature(
2020
m_registration, "Feature",
2121
"Class to store featrues for registration.");
22+
m_registration.attr("m") =
23+
py::module_::import("typing").attr("TypeVar")("m");
24+
m_registration.attr("n") =
25+
py::module_::import("typing").attr("TypeVar")("n");
2226
}
2327
void pybind_feature_definitions(py::module &m_registration) {
2428
// open3d.registration.Feature

cpp/pybind/pipelines/registration/registration.cpp

+35-32
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,10 @@ void pybind_registration_definitions(py::module &m) {
188188
"Maximum iteration before iteration stops.")
189189
.def("__repr__", [](const ICPConvergenceCriteria &c) {
190190
return fmt::format(
191-
"ICPConvergenceCriteria class "
192-
"with relative_fitness={:e}, relative_rmse={:e}, "
193-
"and max_iteration={:d}",
191+
"ICPConvergenceCriteria("
192+
"relative_fitness={:e}, "
193+
"relative_rmse={:e}, "
194+
"max_iteration={:d})",
194195
c.relative_fitness_, c.relative_rmse_,
195196
c.max_iteration_);
196197
});
@@ -214,9 +215,9 @@ void pybind_registration_definitions(py::module &m) {
214215
"termination. Use 1.0 to avoid early termination.")
215216
.def("__repr__", [](const RANSACConvergenceCriteria &c) {
216217
return fmt::format(
217-
"RANSACConvergenceCriteria "
218-
"class with max_iteration={:d}, "
219-
"and confidence={:e}",
218+
"RANSACConvergenceCriteria("
219+
"max_iteration={:d}, "
220+
"confidence={:e})",
220221
c.max_iteration_, c.confidence_);
221222
});
222223

@@ -264,11 +265,10 @@ void pybind_registration_definitions(py::module &m) {
264265
"with_scaling"_a = false)
265266
.def("__repr__",
266267
[](const TransformationEstimationPointToPoint &te) {
267-
return std::string(
268-
"TransformationEstimationPointToPoint ") +
269-
(te.with_scaling_
270-
? std::string("with scaling.")
271-
: std::string("without scaling."));
268+
return fmt::format(
269+
"TransformationEstimationPointToPoint("
270+
"with_scaling={})",
271+
te.with_scaling_ ? "True" : "False");
272272
})
273273
.def_readwrite(
274274
"with_scaling",
@@ -336,10 +336,12 @@ Sets :math:`c = 1` if ``with_scaling`` is ``False``.
336336
"kernel"_a)
337337
.def("__repr__",
338338
[](const TransformationEstimationForColoredICP &te) {
339-
return std::string(
340-
"TransformationEstimationForColoredICP ") +
341-
("with lambda_geometric=" +
342-
std::to_string(te.lambda_geometric_));
339+
// This is missing kernel, but getting kernel name on C++
340+
// is hard
341+
return fmt::format(
342+
"TransformationEstimationForColoredICP("
343+
"lambda_geometric={})",
344+
te.lambda_geometric_);
343345
})
344346
.def_readwrite(
345347
"lambda_geometric",
@@ -380,10 +382,10 @@ Sets :math:`c = 1` if ``with_scaling`` is ``False``.
380382
"kernel"_a)
381383
.def("__repr__",
382384
[](const TransformationEstimationForGeneralizedICP &te) {
383-
return std::string(
384-
"TransformationEstimationForGeneralizedICP"
385-
" ") +
386-
("with epsilon=" + std::to_string(te.epsilon_));
385+
return fmt::format(
386+
"TransformationEstimationForGeneralizedICP("
387+
"epsilon={})",
388+
te.epsilon_);
387389
})
388390
.def_readwrite("epsilon",
389391
&TransformationEstimationForGeneralizedICP::epsilon_,
@@ -555,19 +557,20 @@ must hold true for all edges.)");
555557
"tests on initial set of correspondences.")
556558
.def("__repr__", [](const FastGlobalRegistrationOption &c) {
557559
return fmt::format(
558-
""
559-
"FastGlobalRegistrationOption class "
560-
"with \ndivision_factor={}"
561-
"\nuse_absolute_scale={}"
562-
"\ndecrease_mu={}"
563-
"\nmaximum_correspondence_distance={}"
564-
"\niteration_number={}"
565-
"\ntuple_scale={}"
566-
"\nmaximum_tuple_count={}",
567-
"\ntuple_test={}", c.division_factor_,
568-
c.use_absolute_scale_, c.decrease_mu_,
569-
c.maximum_correspondence_distance_, c.iteration_number_,
570-
c.tuple_scale_, c.maximum_tuple_count_, c.tuple_test_);
560+
"FastGlobalRegistrationOption("
561+
"\ndivision_factor={},"
562+
"\nuse_absolute_scale={},"
563+
"\ndecrease_mu={},"
564+
"\nmaximum_correspondence_distance={},"
565+
"\niteration_number={},"
566+
"\ntuple_scale={},"
567+
"\nmaximum_tuple_count={},"
568+
"\ntuple_test={},"
569+
"\n)",
570+
c.division_factor_, c.use_absolute_scale_,
571+
c.decrease_mu_, c.maximum_correspondence_distance_,
572+
c.iteration_number_, c.tuple_scale_,
573+
c.maximum_tuple_count_, c.tuple_test_);
571574
});
572575

573576
// open3d.registration.RegistrationResult

cpp/pybind/t/geometry/image.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ void pybind_image_definitions(py::module &m) {
181181
"Upsample if sampling rate > 1. Aspect ratio is always "
182182
"kept.",
183183
"sampling_rate"_a = 0.5,
184-
"interp_type"_a = Image::InterpType::Nearest)
184+
py::arg_v("interp_type", Image::InterpType::Nearest,
185+
"open3d.t.geometry.InterpType.Nearest"))
185186
.def("pyrdown", &Image::PyrDown,
186187
"Return a new downsampled image with pyramid downsampling "
187188
"formed by a chained Gaussian filter (kernel_size = 5, sigma"

cpp/pybind/t/geometry/lineset.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,10 @@ transformation as :math:`P = R(P) + t`)");
306306
line_set.def_static(
307307
"create_camera_visualization", &LineSet::CreateCameraVisualization,
308308
"view_width_px"_a, "view_height_px"_a, "intrinsic"_a, "extrinsic"_a,
309-
"scale"_a = 1.f, "color"_a = core::Tensor({}, core::Float32),
309+
"scale"_a = 1.f,
310+
py::arg_v(
311+
"color", core::Tensor({}, core::Float32),
312+
"open3d.core.Tensor([], dtype=open3d.core.Dtype.Float32)"),
310313
R"(Factory function to create a LineSet from intrinsic and extrinsic
311314
matrices. Camera reference frame is shown with XYZ axes in RGB.
312315

0 commit comments

Comments
 (0)