diff --git a/python/mujoco/specs.cc b/python/mujoco/specs.cc index 313de159..3adc549b 100644 --- a/python/mujoco/specs.cc +++ b/python/mujoco/specs.cc @@ -1032,6 +1032,22 @@ PYBIND11_MODULE(_specs, m) { }); mjsPlugin.def("delete", [](raw::MjsPlugin& self) { mjs_delete(self.element); }); + mjsPlugin.def_property( + "config", + [](raw::MjsPlugin& self) -> void { + throw pybind11::value_error("Reading plugin config is not supported."); + }, + [](raw::MjsPlugin& self, py::dict& config) { + std::map> config_attribs; + for (const auto& [key, value] : config) { + std::string key_str = key.cast(); + if (config_attribs.find(key_str) != config_attribs.end()) { + throw pybind11::value_error("Duplicate config key: " + key_str); + } + config_attribs[key_str] = value.cast(); + } + mjs_setPluginAttributes(&self, &config_attribs); + }); // ============================= MJVISUAL ==================================== mjVisual.def_property( "global_", diff --git a/python/mujoco/specs_test.py b/python/mujoco/specs_test.py index 1b46bd4b..210d833f 100644 --- a/python/mujoco/specs_test.py +++ b/python/mujoco/specs_test.py @@ -841,8 +841,9 @@ class SpecsTest(absltest.TestCase): name='instance_name', plugin_name='mujoco.elasticity.cable', active=True, - info='info', + info='info' ) + plugin.config = {'twist': '10', 'bend': '1'} body = spec.worldbody.add_body() body.plugin = plugin @@ -858,6 +859,7 @@ class SpecsTest(absltest.TestCase): model = spec.compile() self.assertIsNotNone(model) self.assertEqual(model.nplugin, 1) + self.assertEqual(model.npluginattr, 7) self.assertEqual(model.body_plugin[1], 0) def test_recompile_error(self):