Add mujoco.MjSpec.MjStruct type.

PiperOrigin-RevId: 723552214
Change-Id: I8ecb43b4025b532ba8b48e15c9c6a2b350293d20
This commit is contained in:
Alessio Quaglino
2025-02-05 10:00:40 -08:00
committed by Copybara-Service
parent fe16c27555
commit dec7b661c1
3 changed files with 49 additions and 9 deletions
+11 -5
View File
@@ -14,7 +14,7 @@
# ============================================================================== # ==============================================================================
"""Engine support functions.""" """Engine support functions."""
from collections.abc import Sequence from collections.abc import Sequence
from typing import Optional, Tuple, Union, Any from typing import Optional, Tuple, Union
import jax import jax
from jax import numpy as jp from jax import numpy as jp
@@ -289,7 +289,7 @@ def name2id(
class BindModel(object): class BindModel(object):
"""Class holding the requested MJX Model and spec id for binding a spec to Model.""" """Class holding the requested MJX Model and spec id for binding a spec to Model."""
def __init__(self, model: Model, specs: Sequence[Any]): def __init__(self, model: Model, specs: Sequence[mujoco.MjStruct]):
self.model = model self.model = model
try: try:
iter(specs) iter(specs)
@@ -371,7 +371,9 @@ class BindModel(object):
return getattr(self.model, self.prefix + name)[self.id, ...] return getattr(self.model, self.prefix + name)[self.id, ...]
def _bind_model(self: Model, obj: Sequence[Any]) -> BindModel: def _bind_model(
self: Model, obj: Sequence[mujoco.MjStruct]
) -> BindModel:
"""Bind a Mujoco spec to an MJX Model.""" """Bind a Mujoco spec to an MJX Model."""
return BindModel(self, obj) return BindModel(self, obj)
@@ -379,7 +381,9 @@ def _bind_model(self: Model, obj: Sequence[Any]) -> BindModel:
class BindData(object): class BindData(object):
"""Class holding the requested MJX Data and spec id for binding a spec to Data.""" """Class holding the requested MJX Data and spec id for binding a spec to Data."""
def __init__(self, data: Data, model: Model, specs: Sequence[Any]): def __init__(
self, data: Data, model: Model, specs: Sequence[mujoco.MjStruct]
):
self.data = data self.data = data
self.model = model self.model = model
try: try:
@@ -499,7 +503,9 @@ class BindData(object):
return self.data.replace(**{self.__getname(name): array}) return self.data.replace(**{self.__getname(name): array})
def _bind_data(self: Data, model: Model, obj: Sequence[Any]) -> BindData: def _bind_data(
self: Data, model: Model, obj: Sequence[mujoco.MjStruct]
) -> BindData:
"""Bind a Mujoco spec to an MJX Data.""" """Bind a Mujoco spec to an MJX Data."""
return BindData(self, model, obj) return BindData(self, model, obj)
+31 -4
View File
@@ -19,7 +19,8 @@ import ctypes.util
import os import os
import platform import platform
import subprocess import subprocess
from typing import Union, IO from typing import IO, Union
from typing_extensions import TypeAlias
import warnings import warnings
import zipfile import zipfile
@@ -48,6 +49,7 @@ elif _SYSTEM == 'Darwin':
'machine. This is not supported by MuJoCo. Please install and run a ' 'machine. This is not supported by MuJoCo. Please install and run a '
'native, arm64 build of Python.') 'native, arm64 build of Python.')
from mujoco import _specs
from mujoco._callbacks import * from mujoco._callbacks import *
from mujoco._constants import * from mujoco._constants import *
from mujoco._enums import * from mujoco._enums import *
@@ -55,13 +57,38 @@ from mujoco._errors import *
from mujoco._functions import * from mujoco._functions import *
from mujoco._render import * from mujoco._render import *
from mujoco._specs import * from mujoco._specs import *
from mujoco._specs import MjSpec
from mujoco._structs import * from mujoco._structs import *
from mujoco.gl_context import * from mujoco.gl_context import *
from mujoco.renderer import Renderer from mujoco.renderer import Renderer
MjStruct: TypeAlias = Union[
_specs.MjsBody,
_specs.MjsFrame,
_specs.MjsGeom,
_specs.MjsJoint,
_specs.MjsLight,
_specs.MjsMaterial,
_specs.MjsSite,
_specs.MjsMesh,
_specs.MjsSkin,
_specs.MjsTexture,
_specs.MjsText,
_specs.MjsTuple,
_specs.MjsCamera,
_specs.MjsFlex,
_specs.MjsHField,
_specs.MjsKey,
_specs.MjsNumeric,
_specs.MjsPair,
_specs.MjsExclude,
_specs.MjsEquality,
_specs.MjsTendon,
_specs.MjsSensor,
_specs.MjsActuator,
_specs.MjsPlugin,
]
def to_zip(spec: MjSpec, file: Union[str, IO[bytes]]) -> None: def to_zip(spec: _specs.MjSpec, file: Union[str, IO[bytes]]) -> None:
"""Converts a spec to a zip file. """Converts a spec to a zip file.
Args: Args:
@@ -79,7 +106,7 @@ def to_zip(spec: MjSpec, file: Union[str, IO[bytes]]) -> None:
zip_info = zipfile.ZipInfo(os.path.join(spec.modelname, filename)) zip_info = zipfile.ZipInfo(os.path.join(spec.modelname, filename))
zip_file.writestr(zip_info, contents) zip_file.writestr(zip_info, contents)
MjSpec.to_zip = to_zip _specs.MjSpec.to_zip = to_zip
HEADERS_DIR = os.path.join(os.path.dirname(__file__), 'include/mujoco') HEADERS_DIR = os.path.join(os.path.dirname(__file__), 'include/mujoco')
PLUGINS_DIR = os.path.join(os.path.dirname(__file__), 'plugin') PLUGINS_DIR = os.path.join(os.path.dirname(__file__), 'plugin')
+7
View File
@@ -17,6 +17,7 @@
import inspect import inspect
import os import os
import textwrap import textwrap
import typing
import zipfile import zipfile
from absl.testing import absltest from absl.testing import absltest
@@ -32,6 +33,12 @@ def get_linenumber():
class SpecsTest(absltest.TestCase): class SpecsTest(absltest.TestCase):
def test_typing(self):
spec = mujoco.MjSpec()
self.assertIsInstance(spec, mujoco.MjSpec)
self.assertIsInstance(spec.worldbody, mujoco.MjsBody)
self.assertIsInstance(spec.worldbody, typing.get_args(mujoco.MjStruct))
def test_basic(self): def test_basic(self):
# Create a spec. # Create a spec.
spec = mujoco.MjSpec() spec = mujoco.MjSpec()