Implement __repr__ and __eq__ on MjrRect in Python bindings.

PiperOrigin-RevId: 457457401
Change-Id: I0d395ff301fbcf775b4766ac81c830a625b3be63
This commit is contained in:
Nimrod Gileadi
2022-06-27 05:55:03 -07:00
committed by Copybara-Service
parent 263c92e301
commit a077db1b91
4 changed files with 92 additions and 81 deletions
-81
View File
@@ -74,87 +74,6 @@ constexpr auto XArrayShapeImpl(const std::string_view dim1_str) {
}
}
// An equals operator that works for comparing numpy arrays too.
// Unlike other objects, the equality operator for numpy arrays returns a
// numpy array.
bool FieldsEqual(py::handle lhs, py::handle rhs, py::handle array_equal) {
// np.array_equal handles non-arrays.
return PyObject_IsTrue(array_equal(lhs, rhs).ptr());
}
// Returns an iterable object for iterating over attributes of T.
template <typename T>
py::object Dir() {
py::object type = py::type::of<T>();
auto dir = py::reinterpret_steal<py::object>(PyObject_Dir(type.ptr()));
if (PyErr_Occurred()) {
throw py::error_already_set();
}
return dir;
}
// Returns true if all public fields in lhs and rhs are equal.
template <typename T>
bool StructsEqual(py::object lhs, py::object rhs) {
// Equivalent to the following python code:
// if type(lhs) != type(rhs):
// return False
// for field in dir(lhs):
// if field.startswith("_"):
// continue
// # equal() handles equality of numpy arrays
// if not equal(getattr(lhs, field, None), getattr(rhs, field, None)):
// return False
//
// return True
auto np = py::module::import("numpy");
auto array_equal = np.attr("array_equal");
const py::handle lhs_t = py::type::handle_of(lhs);
const py::handle rhs_t = py::type::handle_of(rhs);
if (!lhs_t.is(rhs_t)) {
return false;
}
for (py::handle f : Dir<T>()) {
auto name = f.cast<std::string_view>();
if (name.empty() || name[0] == '_') {
continue;
}
py::object l = py::getattr(lhs, f, py::none());
py::object r = py::getattr(rhs, f, py::none());
if (!FieldsEqual(l, r, array_equal)) {
return false;
}
}
return true;
}
// Returns a string representation of a struct like object.
template <typename T>
std::string StructRepr(py::object self) {
std::ostringstream result;
result << "<"
<< self.attr("__class__").attr("__name__").cast<std::string_view>();
for (py::handle f : Dir<T>()) {
auto name = f.cast<std::string_view>();
if (name.empty() || name[0] == '_') {
continue;
}
result << "\n " << name << ": "
<< self.attr(f).attr("__repr__")().cast<std::string_view>();
}
result << "\n>";
return result.str();
}
template <typename C, typename... O>
void DefineStructFunctions(py::class_<C, O...> c) {
c.def("__eq__", StructsEqual<C>);
c.def("__repr__", StructRepr<C>);
}
} // namespace
// ==================== MJOPTION ===============================================