diff --git a/python/mujoco/specs.cc b/python/mujoco/specs.cc
index 9b5793ff..2869483e 100644
--- a/python/mujoco/specs.cc
+++ b/python/mujoco/specs.cc
@@ -595,16 +595,14 @@ PYBIND11_MODULE(_specs, m) {
[](raw::MjsBody& self, raw::MjsFrame& frame) -> void {
mjs_setFrame(self.element, &frame);
});
- mjsBody.def("set_default",
- [](raw::MjsBody& self, raw::MjsDefault& default_) -> void {
- mjs_setDefault(self.element, &default_);
- });
- mjsBody.def(
- "default",
+ mjsBody.def_property(
+ "classname",
[](raw::MjsBody& self) -> raw::MjsDefault* {
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(
"find_all",
[](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) {
mjs_setFrame(self.element, &frame);
});
- mjsGeom.def("set_default", [](raw::MjsGeom& self, raw::MjsDefault& def) {
- mjs_setDefault(self.element, &def);
- });
mjsGeom.def_property_readonly(
"parent",
[](raw::MjsGeom& self) -> raw::MjsBody* {
return mjs_getParent(self.element);
},
py::return_value_policy::reference_internal);
- mjsGeom.def(
- "default",
+ mjsGeom.def_property(
+ "classname",
[](raw::MjsGeom& self) -> raw::MjsDefault* {
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.def("delete", [](raw::MjsJoint& self) { mjs_delete(self.element); });
mjsJoint.def("set_frame", [](raw::MjsJoint& self, raw::MjsFrame& 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(
"parent",
[](raw::MjsJoint& self) -> raw::MjsBody* {
return mjs_getParent(self.element);
},
py::return_value_policy::reference_internal);
- mjsJoint.def(
- "default",
+ mjsJoint.def_property(
+ "classname",
[](raw::MjsJoint& self) -> raw::MjsDefault* {
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.def("delete", [](raw::MjsSite& self) { mjs_delete(self.element); });
mjsSite.def("set_frame", [](raw::MjsSite& self, raw::MjsFrame& 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(
"parent",
[](raw::MjsSite& self) -> raw::MjsBody* {
return mjs_getParent(self.element);
},
py::return_value_policy::reference_internal);
- mjsSite.def(
- "default",
+ mjsSite.def_property(
+ "classname",
[](raw::MjsSite& self) -> raw::MjsDefault* {
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(
"attach_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) {
mjs_setFrame(self.element, &frame);
});
- mjsCamera.def("set_default", [](raw::MjsCamera& self, raw::MjsDefault& def) {
- mjs_setDefault(self.element, &def);
- });
mjsCamera.def_property_readonly(
"parent",
[](raw::MjsCamera& self) -> raw::MjsBody* {
return mjs_getParent(self.element);
},
py::return_value_policy::reference_internal);
- mjsCamera.def(
- "default",
+ mjsCamera.def_property(
+ "classname",
[](raw::MjsCamera& self) -> raw::MjsDefault* {
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.def("delete", [](raw::MjsLight& self) { mjs_delete(self.element); });
mjsLight.def("set_frame", [](raw::MjsLight& self, raw::MjsFrame& 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(
"parent",
[](raw::MjsLight& self) -> raw::MjsBody* {
return mjs_getParent(self.element);
},
py::return_value_policy::reference_internal);
- mjsLight.def(
- "default",
+ mjsLight.def_property(
+ "classname",
[](raw::MjsLight& self) -> raw::MjsDefault* {
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.def("delete",
[](raw::MjsMaterial& self) { mjs_delete(self.element); });
- mjsMaterial.def("set_default",
- [](raw::MjsMaterial& self, raw::MjsDefault& def) {
- mjs_setDefault(self.element, &def);
- });
- mjsMaterial.def(
- "default",
+ mjsMaterial.def_property(
+ "classname",
[](raw::MjsMaterial& self) -> raw::MjsDefault* {
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.def("delete", [](raw::MjsMesh& self) { mjs_delete(self.element); });
- mjsMesh.def("set_default", [](raw::MjsMesh& self, raw::MjsDefault& def) {
- mjs_setDefault(self.element, &def);
- });
- mjsMesh.def(
- "default",
+ mjsMesh.def_property(
+ "classname",
[](raw::MjsMesh& self) -> raw::MjsDefault* {
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.def("delete", [](raw::MjsPair& self) { mjs_delete(self.element); });
- mjsPair.def("set_default", [](raw::MjsPair& self, raw::MjsDefault& def) {
- mjs_setDefault(self.element, &def);
- });
- mjsPair.def(
- "default",
+ mjsPair.def_property(
+ "classname",
[](raw::MjsPair& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
- py::return_value_policy::reference_internal);
+ [](raw::MjsPair& self, raw::MjsDefault& default_) -> void {
+ mjs_setDefault(self.element, &default_);
+ });
// ============================= MJSEQUAL ====================================
mjsEquality.def("delete",
[](raw::MjsEquality& self) { mjs_delete(self.element); });
- mjsEquality.def("set_default",
- [](raw::MjsEquality& self, raw::MjsDefault& def) {
- mjs_setDefault(self.element, &def);
- });
- mjsEquality.def(
- "default",
+ mjsEquality.def_property(
+ "classname",
[](raw::MjsEquality& self) -> raw::MjsDefault* {
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.def("delete",
[](raw::MjsActuator& self) { mjs_delete(self.element); });
- mjsActuator.def("set_default",
- [](raw::MjsActuator& self, raw::MjsDefault& def) {
- mjs_setDefault(self.element, &def);
- });
- mjsActuator.def(
- "default",
+ mjsActuator.def_property(
+ "classname",
[](raw::MjsActuator& self) -> raw::MjsDefault* {
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.def("delete",
[](raw::MjsTendon& self) { mjs_delete(self.element); });
- mjsTendon.def("set_default", [](raw::MjsTendon& self, raw::MjsDefault& def) {
- mjs_setDefault(self.element, &def);
- });
mjsTendon.def(
"default",
[](raw::MjsTendon& self) -> raw::MjsDefault* {
diff --git a/python/mujoco/specs_test.py b/python/mujoco/specs_test.py
index 41e12202..710e483c 100644
--- a/python/mujoco/specs_test.py
+++ b/python/mujoco/specs_test.py
@@ -528,22 +528,7 @@ class SpecsTest(absltest.TestCase):
spec.to_xml()
def test_modelname_default_class(self):
- 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
-
- spec.worldbody.add_geom(def1)
- spec.worldbody.add_geom(main)
-
- spec.compile()
- self.assertEqual(
- spec.to_xml(),
- textwrap.dedent("""\
+ XML = textwrap.dedent("""\
@@ -559,8 +544,8 @@ class SpecsTest(absltest.TestCase):
- """),
- )
+ """)
+
spec = mujoco.MjSpec()
spec.modelname = 'test'
@@ -574,26 +559,38 @@ class SpecsTest(absltest.TestCase):
spec.worldbody.add_geom(main)
spec.compile()
- self.assertEqual(
- spec.to_xml(),
- textwrap.dedent("""\
-
-
+ 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(def1)
+ geom2 = spec.worldbody.add_geom()
+ self.assertEqual(geom1.classname.name, 'def1')
+ self.assertEqual(geom2.classname.name, 'main')
+
+ 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):
spec = mujoco.MjSpec()