Skip to content

Commit ad0824f

Browse files
erez-tomcopybara-github
authored andcommitted
PyMJCF: Don't replace '/' -> '\' in attributes that may contain filesystem path information.
PiperOrigin-RevId: 631419245 Change-Id: I317bae0b5b6d6041baaf1ca663cd5628012831a0
1 parent f3e1114 commit ad0824f

3 files changed

Lines changed: 43 additions & 6 deletions

File tree

dm_control/mjcf/export_with_assets_test.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
_ASSETS_DIR = os.path.join(os.path.dirname(__file__), 'test_assets')
2929
_TEST_MODEL_WITH_ASSETS = os.path.join(_ASSETS_DIR, 'model_with_assets.xml')
3030
_TEST_MODEL_WITH_ASSETDIR = os.path.join(_ASSETS_DIR, 'model_with_assetdir.xml')
31+
_TEST_MODEL_WITH_SEPARATORS = os.path.join(_ASSETS_DIR,
32+
'model_with_separators.xml')
3133
_TEST_MODEL_WITHOUT_ASSETS = os.path.join(_ASSETS_DIR, 'lego_brick.xml')
3234

3335

@@ -89,6 +91,15 @@ def test_default_model_filename(self):
8991
expected_name = mjcf_model.model + '.xml'
9092
self.assertTrue(os.path.isfile(os.path.join(out_dir, expected_name)))
9193

94+
def test_model_with_separators(self):
95+
out_dir = self.create_tempdir().full_path
96+
mjcf_model = mjcf.from_path(
97+
_TEST_MODEL_WITH_SEPARATORS, escape_separators=True
98+
)
99+
mjcf.export_with_assets(mjcf_model, out_dir, out_file_name=None)
100+
expected_name = mjcf_model.model + '.xml'
101+
self.assertTrue(os.path.isfile(os.path.join(out_dir, expected_name)))
102+
92103
def test_exceptions(self):
93104
out_dir = self.create_tempdir().full_path
94105
mjcf_model = mjcf.from_path(_TEST_MODEL_WITH_ASSETS)

dm_control/mjcf/parser.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,19 @@ def _parse_children(xml_element, mjcf_element, escape_separators=False):
199199
if escape_separators:
200200
attributes = {}
201201
for name, value in xml_child.attrib.items():
202-
new_value = value.replace(
203-
constants.PREFIX_SEPARATOR_ESCAPE,
204-
constants.PREFIX_SEPARATOR_ESCAPE * 2)
205-
new_value = new_value.replace(
206-
constants.PREFIX_SEPARATOR, constants.PREFIX_SEPARATOR_ESCAPE)
207-
attributes[name] = new_value
202+
# skip flipping the slash for fields that may contain paths, like
203+
# custom text and asset file.
204+
if name in ['data', 'file', 'meshdir', 'assetdir', 'texturedir',
205+
'content_type', 'fileleft', 'fileright', 'fileback',
206+
'filefront', 'plugin', 'key', 'value']:
207+
attributes[name] = value
208+
else:
209+
new_value = value.replace(
210+
constants.PREFIX_SEPARATOR_ESCAPE,
211+
constants.PREFIX_SEPARATOR_ESCAPE * 2)
212+
new_value = new_value.replace(
213+
constants.PREFIX_SEPARATOR, constants.PREFIX_SEPARATOR_ESCAPE)
214+
attributes[name] = new_value
208215
else:
209216
attributes = dict(xml_child.attrib)
210217
if child_spec.repeated or child_spec.on_demand:
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<mujoco model="Textured cube and mesh">
2+
<compiler meshdir="meshes" texturedir="textures"/>
3+
<asset>
4+
<mesh name="cube" file="cube.stl"/>
5+
<mesh name="another_cube" file="more_meshes/cube.stl"/>
6+
<mesh name="unused_asset_should_not_cause_problems" file="cube.stl"/>
7+
<mesh name="cube_msh" file="cube.msh"/>
8+
<texture name="texture" file="deepmind.png"/>
9+
<material name="mat_texture" texture="texture"/>
10+
<hfield name="hill" file="../textures/deepmind.png" size="0.5 0.5 0.5 0.1"/>
11+
</asset>
12+
<worldbody>
13+
<light diffuse=".5 .5 .5" pos="0 0 3" dir="0 0 -1"/>
14+
<geom name="left/cube" type="mesh" mesh="cube" material="mat_texture"/>
15+
<geom name="right/cube" type="mesh" mesh="another_cube" material="mat_texture" pos="2.5 0. 0."/>
16+
<geom type="mesh" mesh="cube_msh" material="mat_texture" pos="4. 0. 0."/>
17+
<geom type="hfield" hfield="hill" pos="1.2 0. 0" rgba="0. 0.9 0. 1" size="40 40 0.1"/>
18+
</worldbody>
19+
</mujoco>

0 commit comments

Comments
 (0)