Change set_default and default to classname in the bindings.

Having defaults in the names of the attribute or function names is confusing for the users since the defaults are not re-applied but are only used for writing to XML. The alternative would be to change mjs_setDefault to re-apply them, but this would overwrite any other attribute set by the user so far.

PiperOrigin-RevId: 726431090
Change-Id: I41f4a23e1722e278b0ecc0a00b07db9b384fe994
This commit is contained in:
Alessio Quaglino
2025-02-13 04:51:05 -08:00
committed by Copybara-Service
parent 89253d957d
commit 1b4258d274
2 changed files with 88 additions and 109 deletions
+55 -73
View File
@@ -595,16 +595,14 @@ PYBIND11_MODULE(_specs, m) {
[](raw::MjsBody& self, raw::MjsFrame& frame) -> void { [](raw::MjsBody& self, raw::MjsFrame& frame) -> void {
mjs_setFrame(self.element, &frame); mjs_setFrame(self.element, &frame);
}); });
mjsBody.def("set_default", mjsBody.def_property(
[](raw::MjsBody& self, raw::MjsDefault& default_) -> void { "classname",
mjs_setDefault(self.element, &default_);
});
mjsBody.def(
"default",
[](raw::MjsBody& self) -> raw::MjsDefault* { [](raw::MjsBody& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsBody& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
mjsBody.def( mjsBody.def(
"find_all", "find_all",
[](raw::MjsBody& self, mjtObj objtype) -> py::list { [](raw::MjsBody& self, mjtObj objtype) -> py::list {
@@ -837,63 +835,60 @@ PYBIND11_MODULE(_specs, m) {
mjsGeom.def("set_frame", [](raw::MjsGeom& self, raw::MjsFrame& frame) { mjsGeom.def("set_frame", [](raw::MjsGeom& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame); mjs_setFrame(self.element, &frame);
}); });
mjsGeom.def("set_default", [](raw::MjsGeom& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsGeom.def_property_readonly( mjsGeom.def_property_readonly(
"parent", "parent",
[](raw::MjsGeom& self) -> raw::MjsBody* { [](raw::MjsGeom& self) -> raw::MjsBody* {
return mjs_getParent(self.element); return mjs_getParent(self.element);
}, },
py::return_value_policy::reference_internal); py::return_value_policy::reference_internal);
mjsGeom.def( mjsGeom.def_property(
"default", "classname",
[](raw::MjsGeom& self) -> raw::MjsDefault* { [](raw::MjsGeom& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsGeom& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
// ============================= MJSJOINT ==================================== // ============================= MJSJOINT ====================================
mjsJoint.def("delete", [](raw::MjsJoint& self) { mjs_delete(self.element); }); mjsJoint.def("delete", [](raw::MjsJoint& self) { mjs_delete(self.element); });
mjsJoint.def("set_frame", [](raw::MjsJoint& self, raw::MjsFrame& frame) { mjsJoint.def("set_frame", [](raw::MjsJoint& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame); mjs_setFrame(self.element, &frame);
}); });
mjsJoint.def("set_default", [](raw::MjsJoint& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsJoint.def_property_readonly( mjsJoint.def_property_readonly(
"parent", "parent",
[](raw::MjsJoint& self) -> raw::MjsBody* { [](raw::MjsJoint& self) -> raw::MjsBody* {
return mjs_getParent(self.element); return mjs_getParent(self.element);
}, },
py::return_value_policy::reference_internal); py::return_value_policy::reference_internal);
mjsJoint.def( mjsJoint.def_property(
"default", "classname",
[](raw::MjsJoint& self) -> raw::MjsDefault* { [](raw::MjsJoint& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsJoint& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
// ============================= MJSSITE ===================================== // ============================= MJSSITE =====================================
mjsSite.def("delete", [](raw::MjsSite& self) { mjs_delete(self.element); }); mjsSite.def("delete", [](raw::MjsSite& self) { mjs_delete(self.element); });
mjsSite.def("set_frame", [](raw::MjsSite& self, raw::MjsFrame& frame) { mjsSite.def("set_frame", [](raw::MjsSite& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame); mjs_setFrame(self.element, &frame);
}); });
mjsSite.def("set_default", [](raw::MjsSite& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsSite.def_property_readonly( mjsSite.def_property_readonly(
"parent", "parent",
[](raw::MjsSite& self) -> raw::MjsBody* { [](raw::MjsSite& self) -> raw::MjsBody* {
return mjs_getParent(self.element); return mjs_getParent(self.element);
}, },
py::return_value_policy::reference_internal); py::return_value_policy::reference_internal);
mjsSite.def( mjsSite.def_property(
"default", "classname",
[](raw::MjsSite& self) -> raw::MjsDefault* { [](raw::MjsSite& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsSite& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
mjsSite.def( mjsSite.def(
"attach_body", "attach_body",
[](raw::MjsSite& self, raw::MjsBody& body, [](raw::MjsSite& self, raw::MjsBody& body,
@@ -918,115 +913,102 @@ PYBIND11_MODULE(_specs, m) {
mjsCamera.def("set_frame", [](raw::MjsCamera& self, raw::MjsFrame& frame) { mjsCamera.def("set_frame", [](raw::MjsCamera& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame); mjs_setFrame(self.element, &frame);
}); });
mjsCamera.def("set_default", [](raw::MjsCamera& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsCamera.def_property_readonly( mjsCamera.def_property_readonly(
"parent", "parent",
[](raw::MjsCamera& self) -> raw::MjsBody* { [](raw::MjsCamera& self) -> raw::MjsBody* {
return mjs_getParent(self.element); return mjs_getParent(self.element);
}, },
py::return_value_policy::reference_internal); py::return_value_policy::reference_internal);
mjsCamera.def( mjsCamera.def_property(
"default", "classname",
[](raw::MjsCamera& self) -> raw::MjsDefault* { [](raw::MjsCamera& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsCamera& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
// ============================= MJSLIGHT ==================================== // ============================= MJSLIGHT ====================================
mjsLight.def("delete", [](raw::MjsLight& self) { mjs_delete(self.element); }); mjsLight.def("delete", [](raw::MjsLight& self) { mjs_delete(self.element); });
mjsLight.def("set_frame", [](raw::MjsLight& self, raw::MjsFrame& frame) { mjsLight.def("set_frame", [](raw::MjsLight& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame); mjs_setFrame(self.element, &frame);
}); });
mjsLight.def("set_default", [](raw::MjsLight& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsLight.def_property_readonly( mjsLight.def_property_readonly(
"parent", "parent",
[](raw::MjsLight& self) -> raw::MjsBody* { [](raw::MjsLight& self) -> raw::MjsBody* {
return mjs_getParent(self.element); return mjs_getParent(self.element);
}, },
py::return_value_policy::reference_internal); py::return_value_policy::reference_internal);
mjsLight.def( mjsLight.def_property(
"default", "classname",
[](raw::MjsLight& self) -> raw::MjsDefault* { [](raw::MjsLight& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsLight& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
// ============================= MJSMATERIAL ================================= // ============================= MJSMATERIAL =================================
mjsMaterial.def("delete", mjsMaterial.def("delete",
[](raw::MjsMaterial& self) { mjs_delete(self.element); }); [](raw::MjsMaterial& self) { mjs_delete(self.element); });
mjsMaterial.def("set_default", mjsMaterial.def_property(
[](raw::MjsMaterial& self, raw::MjsDefault& def) { "classname",
mjs_setDefault(self.element, &def);
});
mjsMaterial.def(
"default",
[](raw::MjsMaterial& self) -> raw::MjsDefault* { [](raw::MjsMaterial& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsMaterial& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
// ============================= MJSMESH ===================================== // ============================= MJSMESH =====================================
mjsMesh.def("delete", [](raw::MjsMesh& self) { mjs_delete(self.element); }); mjsMesh.def("delete", [](raw::MjsMesh& self) { mjs_delete(self.element); });
mjsMesh.def("set_default", [](raw::MjsMesh& self, raw::MjsDefault& def) { mjsMesh.def_property(
mjs_setDefault(self.element, &def); "classname",
});
mjsMesh.def(
"default",
[](raw::MjsMesh& self) -> raw::MjsDefault* { [](raw::MjsMesh& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsMesh& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
// ============================= MJSPAIR ===================================== // ============================= MJSPAIR =====================================
mjsPair.def("delete", [](raw::MjsPair& self) { mjs_delete(self.element); }); mjsPair.def("delete", [](raw::MjsPair& self) { mjs_delete(self.element); });
mjsPair.def("set_default", [](raw::MjsPair& self, raw::MjsDefault& def) { mjsPair.def_property(
mjs_setDefault(self.element, &def); "classname",
});
mjsPair.def(
"default",
[](raw::MjsPair& self) -> raw::MjsDefault* { [](raw::MjsPair& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsPair& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
// ============================= MJSEQUAL ==================================== // ============================= MJSEQUAL ====================================
mjsEquality.def("delete", mjsEquality.def("delete",
[](raw::MjsEquality& self) { mjs_delete(self.element); }); [](raw::MjsEquality& self) { mjs_delete(self.element); });
mjsEquality.def("set_default", mjsEquality.def_property(
[](raw::MjsEquality& self, raw::MjsDefault& def) { "classname",
mjs_setDefault(self.element, &def);
});
mjsEquality.def(
"default",
[](raw::MjsEquality& self) -> raw::MjsDefault* { [](raw::MjsEquality& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsEquality& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
// ============================= MJSACTUATOR ================================= // ============================= MJSACTUATOR =================================
mjsActuator.def("delete", mjsActuator.def("delete",
[](raw::MjsActuator& self) { mjs_delete(self.element); }); [](raw::MjsActuator& self) { mjs_delete(self.element); });
mjsActuator.def("set_default", mjsActuator.def_property(
[](raw::MjsActuator& self, raw::MjsDefault& def) { "classname",
mjs_setDefault(self.element, &def);
});
mjsActuator.def(
"default",
[](raw::MjsActuator& self) -> raw::MjsDefault* { [](raw::MjsActuator& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element); return mjs_getDefault(self.element);
}, },
py::return_value_policy::reference_internal); [](raw::MjsActuator& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
// ============================= MJSTENDON =================================== // ============================= MJSTENDON ===================================
mjsTendon.def("delete", mjsTendon.def("delete",
[](raw::MjsTendon& self) { mjs_delete(self.element); }); [](raw::MjsTendon& self) { mjs_delete(self.element); });
mjsTendon.def("set_default", [](raw::MjsTendon& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsTendon.def( mjsTendon.def(
"default", "default",
[](raw::MjsTendon& self) -> raw::MjsDefault* { [](raw::MjsTendon& self) -> raw::MjsDefault* {
+33 -36
View File
@@ -528,22 +528,7 @@ class SpecsTest(absltest.TestCase):
spec.to_xml() spec.to_xml()
def test_modelname_default_class(self): def test_modelname_default_class(self):
spec = mujoco.MjSpec() XML = textwrap.dedent("""\
spec.modelname = 'test'
main = spec.default()
main.geom.size[0] = 2
def1 = spec.add_default('def1', main)
def1.geom.size[0] = 3
spec.worldbody.add_geom(def1)
spec.worldbody.add_geom(main)
spec.compile()
self.assertEqual(
spec.to_xml(),
textwrap.dedent("""\
<mujoco model="test"> <mujoco model="test">
<compiler angle="radian"/> <compiler angle="radian"/>
@@ -559,8 +544,8 @@ class SpecsTest(absltest.TestCase):
<geom/> <geom/>
</worldbody> </worldbody>
</mujoco> </mujoco>
"""), """)
)
spec = mujoco.MjSpec() spec = mujoco.MjSpec()
spec.modelname = 'test' spec.modelname = 'test'
@@ -574,26 +559,38 @@ class SpecsTest(absltest.TestCase):
spec.worldbody.add_geom(main) spec.worldbody.add_geom(main)
spec.compile() spec.compile()
self.assertEqual( self.assertEqual(spec.to_xml(), XML)
spec.to_xml(), spec = mujoco.MjSpec()
textwrap.dedent("""\ spec.modelname = 'test'
<mujoco model="test">
<compiler angle="radian"/>
<default> main = spec.default()
<geom size="2 0 0"/> main.geom.size[0] = 2
<default class="def1"> def1 = spec.add_default('def1', main)
<geom size="3 0 0"/> def1.geom.size[0] = 3
</default>
</default>
<worldbody> geom1 = spec.worldbody.add_geom(def1)
<geom class="def1"/> geom2 = spec.worldbody.add_geom()
<geom/> self.assertEqual(geom1.classname.name, 'def1')
</worldbody> self.assertEqual(geom2.classname.name, 'main')
</mujoco>
"""), spec.compile()
) self.assertEqual(spec.to_xml(), XML)
spec = mujoco.MjSpec()
spec.modelname = 'test'
main = spec.default()
main.geom.size[0] = 2
def1 = spec.add_default('def1', main)
def1.geom.size[0] = 3
geom1 = spec.worldbody.add_geom(size=[3, 0, 0])
geom2 = spec.worldbody.add_geom(size=[2, 0, 0])
geom1.classname = def1
geom2.classname = main # actually redundant, since main is always applied
spec.compile()
self.assertEqual(spec.to_xml(), XML)
def test_element_list(self): def test_element_list(self):
spec = mujoco.MjSpec() spec = mujoco.MjSpec()