Add MjSpec.from_zip() constructor.

PiperOrigin-RevId: 736871864
Change-Id: Ib6cc189d5912a57e5c505c744a4a1d6ad61d1c84
This commit is contained in:
Alessio Quaglino
2025-03-14 08:30:11 -07:00
committed by Copybara-Service
parent 1a67aaf1b7
commit f480a9e985
2 changed files with 33 additions and 3 deletions
+29 -2
View File
@@ -91,7 +91,7 @@ MjStruct: TypeAlias = Union[
def to_zip(spec: _specs.MjSpec, file: Union[str, IO[bytes]]) -> None:
"""Converts a spec to a zip file.
"""Converts an MjSpec to a zip file.
Args:
spec: The mjSpec to save to a file.
@@ -109,6 +109,33 @@ def to_zip(spec: _specs.MjSpec, file: Union[str, IO[bytes]]) -> None:
zip_file.writestr(zip_info, contents)
def from_zip(file: Union[str, IO[bytes]]) -> _specs.MjSpec:
"""Reads a zip file and returns an MjSpec.
Args:
file: The path to the file to read from or the file object to read from.
Returns:
An MjSpec object.
"""
assets = {}
xml_string = None
if isinstance(file, str):
file = open(file, 'rb')
if not zipfile.is_zipfile(file):
raise ValueError(f'File {file} is not a zip file.')
with zipfile.ZipFile(file, 'r') as zip_file:
for zip_info in zip_file.infolist():
if not zip_info.filename.endswith(os.path.sep):
with zip_file.open(zip_info.filename) as f:
if zip_info.filename.endswith('.xml'):
xml_string = f.read()
else:
assets[zip_info.filename] = f.read()
if not xml_string:
raise ValueError('No XML file found in zip file.')
return _specs.MjSpec.from_string(xml_string, assets=assets)
class _MjBindModel:
def __init__(self, elements: Sequence[Any]):
self.elements = elements
@@ -166,7 +193,7 @@ def _bind_data(
else:
return data.bind_scalar(specs)
_specs.MjSpec.from_zip = from_zip
_specs.MjSpec.to_zip = to_zip
_structs.MjData.bind = _bind_data
_structs.MjModel.bind = _bind_model
+4 -1
View File
@@ -758,11 +758,14 @@ class SpecsTest(absltest.TestCase):
xml = """
<mujoco model="test">
<compiler angle="radian"/>
<asset>
<mesh name="cube" file="cube.obj"/>
</asset>
<worldbody>
<geom mesh="cube"/>
<geom type="mesh" mesh="cube"/>
</worldbody>
</mujoco>
"""