Skip to content

Support MuJoCo 3.12.0, widen pin to >=3.6,<3.13, and repair the skipped/stale test suites - #404

Open
M-Colley wants to merge 4 commits into
MyoHub:mainfrom
M-Colley:mujoco-3.12
Open

Support MuJoCo 3.12.0, widen pin to >=3.6,<3.13, and repair the skipped/stale test suites#404
M-Colley wants to merge 4 commits into
MyoHub:mainfrom
M-Colley:mujoco-3.12

Conversation

@M-Colley

Copy link
Copy Markdown

Summary

Adds support for MuJoCo 3.12.0 and widens the pin to mujoco>=3.6,<3.13.

The MuJoCo side turned out to be small — no API MyoSuite uses was removed or changed incompatibly in 3.12. Most of this PR is fixing pre-existing NumPy 2 breakage and three test suites that were silently not testing what they claimed to.

MuJoCo 3.12

pyproject.toml pin bumped in both the core dependencies and the mjx extra, and uv.lock regenerated (mujoco 3.6.0 → 3.12.0, mujoco-mjx 3.6.0 → 3.12.0, warp-lang 1.11.1 → 1.16.0).

Nothing in the 3.12 breaking-change list applies: there is no flex, dcmotor, custom binary texture, mjx.render, or efm_L_* usage anywhere in the tree, and every mjtDyn/mjtGain reference is symbolic, so the enum renumbering is a no-op. Trajectories are effectively unchanged — max |Δqpos| ≈ 5e-7 over 50 steps with identical contact counts — so no policy retraining is implied.

The pin is widened rather than moved to 3.12-only: the full suite passes on 3.6.0 through 3.12.0, so there is no reason to force downstream users to upgrade.

NumPy 2 fixes (pre-existing, independent of MuJoCo version)

Named accessors like geomadr, vertadr, qposadr and dofadr return shape-(1,) arrays, and NumPy ≥2.3 no longer converts those to scalars implicitly. Nine sites:

  • bimanual_v0geomadr/vertadr/vertnum/qposadr/dofadr indexed before use
  • soccer_v0, chasetag_v0float(obs_dict["time"]) via .item()
  • soccer_v0 — dropped size=(1,) from the joint-noise draws so a scalar is assigned into qpos[i] (RNG stream consumption is unchanged, so seeded reproducibility is preserved)

These reproduce identically on MuJoCo 3.6.0, so they are not 3.12 regressions. They only surface on Python 3.11+, where NumPy resolves to 2.4+; CI pinned 3.10, which resolves NumPy 2.2.6 and still permits the conversion as a deprecation — which is why they were invisible.

Also declares scipy, imported by bimanual_v0 and tabletennis_v0 but previously reaching CI only as an incidental scikit-video dependency.

Test suites

test_mjx.pyimport mjx can never succeed (mjx ships as mujoco.mjx), so MJX_AVAILABLE was always False and all four tests silently skipped. Importing it correctly exposed API rot: mjx.device_put was removed (→ mjx.put_model), mjx.step takes (model, data) with control carried on Data, and the "xpos should not be all zeros" assertion is false for myofinger_v0, whose four bodies all sit at the origin.

test_editor.py (62 failures → 12 passed / 70 subtests) — the phalanx tests looked up thumbprox, 2proxph, … as body names, but those are geom/mesh names; the bodies are proximal_thumb, proxph2, … edit_fn_arm_reaching rebuilds each phalanx under its original body name, so every lookup returned None. test_digit_bodies_are_removed could never hold either, since the bodies are removed and re-added under the same name — replaced with test_digit_bodies_are_simplified, asserting what the edit actually does.

test_heightfields.py — constructed ChaseTagField/TrackField with a stale sim= wrapper, but HeightField takes mj_model/mj_data; ChaseTagField was also given one of its three required ranges.

CI

Adds a Python matrix (3.10, 3.12, 3.14) across the three runners with fail-fast: false. Keeping 3.10 matters — it is the floor declared by requires-python and the only tested interpreter resolving NumPy 2.2.6, the case that hid the breakage above. requires-python raised to <3.15 with a 3.14 classifier; MuJoCo 3.12 ships cp314 wheels.

mink

mink[examples] referenced an extra dropped in mink 1.0.0, which made uv lock warn. The requirement is now split by interpreter, because mink 1.3.0 — the first release without a <3.14 cap — also raises its floor to mujoco>=3.10.0, and requiring it unconditionally would drag every .[examples] install up to mujoco 3.10 and quietly invalidate the >=3.6 floor. Below 3.14 mink is left unconstrained; on 3.14 mujoco 3.6 has no wheels anyway (cp310–cp313 only).

Verification

test_myo (392 registered envs), test_editor and test_heightfields, all green:

MuJoCo (py3.13) 3.6.0 3.7.0 3.8.1 3.9.0 3.10.0 3.11.0 3.12.0
OK OK OK OK OK OK OK
Python (mujoco 3.12.0) 3.10 3.11 3.12 3.13 3.14
numpy 2.2.6 2.4.6 2.5.2 2.5.2 2.5.2
OK OK OK OK OK

MJX: 57 passed (the 4 previously-skipped test_mjx tests plus tests/mjx/).

Also verified that py3.10 + .[examples] + mujoco==3.6.0 still resolves and passes, so the widened floor is real rather than nominal.

Known behavioural change

3.12 gives built-in primitives canonical UV parameterisations (cc7fb98c). In this repo the visible effect is confined to the myoarm_bionic_bimanual pillars — cylinders carrying builtin="checker" mark="random" textures, which change from smooth vertical striping to mottled noise (~19% of pixels in a representative view). Textured planes and meshes are unaffected (myoelbow floor: 0.01% of pixels, max delta 1). Physics is unchanged; this only matters for screenshots and any vision-based bimanual observations.

🤖 Generated with Claude Code

M-Colley and others added 4 commits August 22, 2026 11:53
Bump the MuJoCo pin from >=3.6,<3.7 to >=3.12,<3.13 in the core
dependencies and the mjx extra, and regenerate uv.lock (mujoco
3.6.0 -> 3.12.0, mujoco-mjx 3.6.0 -> 3.12.0, warp-lang 1.11.1 -> 1.16.0).

No MuJoCo API used by MyoSuite was removed or changed incompatibly in
3.12: there is no flex, dcmotor, custom binary texture, mjx.render or
efm_L_* usage, and all mjtDyn/mjtGain references are symbolic so the
enum renumbering is a no-op. Trajectories are effectively unchanged
(max |dqpos| ~5e-7 over 50 steps, identical contact counts).

Fix pre-existing NumPy 2 incompatibilities that blocked the env suite
regardless of MuJoCo version. Named accessors such as geomadr, vertadr,
qposadr and dofadr return shape-(1,) arrays, and NumPy >= 2.3 no longer
converts those to scalars implicitly:

  - bimanual_v0: index geomadr/vertadr/vertnum/qposadr/dofadr before use
  - soccer_v0, chasetag_v0: float() on obs_dict["time"] via .item()
  - soccer_v0: drop size=(1,) from the joint noise draws so the value
    assigned into qpos[i] is a scalar (RNG stream consumption unchanged)

These only surfaced on Python 3.11+, where NumPy resolves to 2.4+; CI
runs Python 3.10, which resolves NumPy 2.2.6 and still allows the
conversion as a deprecation.

Declare scipy, which bimanual_v0 and tabletennis_v0 import but which
was only reaching CI incidentally as a scikit-video dependency.

Update the install docs, whose stated requirements (mujoco >= 2.3.6,
python >= 3.9) no longer matched requires-python.

Verified: all 392 registered envs construct, reset and step, and
myosuite.tests.test_myo passes on MuJoCo 3.7/3.8.1/3.9/3.10/3.11/3.12
and on Python 3.10/3.11/3.12/3.13.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…on matrix

Pin
---
Widen the MuJoCo requirement from >=3.12,<3.13 to >=3.6,<3.13 in the core
dependencies and the mjx extra. Verified: myosuite.tests.test_myo, test_editor
and test_heightfields all pass on MuJoCo 3.6.0, 3.7.0, 3.8.1, 3.9.0, 3.10.0,
3.11.0 and 3.12.0, so there is no reason to force downstream users onto 3.12.

Raise requires-python to <3.15 and add the 3.14 classifier; MuJoCo 3.12 ships
cp314 wheels and the suite passes on 3.14.

test_mjx
--------
"import mjx" can never succeed -- mjx ships as mujoco.mjx -- so MJX_AVAILABLE
was always False and all four tests silently skipped. Importing it correctly
exposed API rot that had accumulated unnoticed:

  - mjx.device_put was removed; use mjx.put_model
  - mjx.step takes (model, data); the control is carried on Data, so pass it
    via data.replace(ctrl=action) rather than as a third argument
  - the "xpos should not be all zeros" assertion is false for myofinger_v0,
    whose four bodies all sit at the origin. Assert the shape instead and let
    the existing comparison against mj_forward carry correctness.

test_editor
-----------
The phalanx tests looked up 'thumbprox', '2proxph', ... as body names, but
those are geom/mesh names; the bodies are 'proximal_thumb', 'proxph2', ...
edit_fn_arm_reaching rebuilds each phalanx under its original body name, so
every one of those lookups returned None. Use the real body names throughout
and drop the original->edited rename map, which described a renaming the edit
function does not perform.

test_digit_bodies_are_removed asserted the bodies were gone, but they are
removed and re-added under the same name, so it could never hold. Replace it
with test_digit_bodies_are_simplified, which asserts what the edit actually
does: the replacements carry a mesh geom and none of the original's joints.

Relax test_invalid_model_path to the stable "Error opening file" prefix;
MuJoCo no longer appends the platform strerror text.

test_heightfields
-----------------
The tests built ChaseTagField/TrackField with a sim= wrapper carrying .model
and .data, but HeightField takes mj_model/mj_data, and ChaseTagField was given
only one of its three required ranges. Construct both the way chasetag_v0 and
run_track_v0 do.

CI
--
Add a Python matrix (3.12 and 3.14) across the three runners with
fail-fast: false, so a failure on one interpreter no longer hides the others.
Previously every job pinned 3.10, which resolves NumPy 2.2.6 -- the last
release where converting a size-1 array to a scalar is a deprecation rather
than a TypeError. That is why the NumPy 2 breakage fixed in the previous
commit never surfaced in CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CI now runs 3.10, 3.12 and 3.14 on each of the three runners (9 jobs).
3.10 is the floor declared by requires-python, and it is also the only
tested interpreter that resolves NumPy 2.2.6, where converting a size-1
array to a scalar is still a deprecation rather than a TypeError -- so
without it the matrix would not cover the case that hid the NumPy 2
breakage in the first place.

mink dropped its "examples" extra in 1.0.0 (it existed up to 0.0.13), so
"mink[examples]" made uv emit:

    warning: The package `mink==1.1.0` does not have an extra named `examples`

Depend on the plain package instead. Resolution is unaffected: mink has
no extra-gated dependencies any more, and a fresh resolve still selects
1.3.0 on Python 3.14 (1.1.0 caps at <3.14), so .[examples] installs there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mink 1.3.0 is the first release without a <3.14 python cap, so the extra
needs it to be installable on 3.14. But 1.3.0 also raises its own floor to
mujoco>=3.10.0, and requiring it unconditionally would drag every install
of .[examples] up to mujoco 3.10 -- quietly invalidating the >=3.6 floor
this branch just widened to.

Split the requirement by interpreter instead:

  - python < 3.14 : mink unconstrained, so mujoco 3.6 stays reachable
  - python >= 3.14: mink>=1.3.0

Nothing is lost on 3.14, where mujoco 3.6 has no wheels to begin with
(3.6.0 ships cp310-cp313 only; cp314 first appears in 3.9.0).

Verified end to end:

  py3.10 + .[examples] + mujoco==3.6.0 -> mujoco 3.6.0, mink 1.1.0,
      test_myo OK, editor+heightfields 14 passed / 70 subtests
  py3.14 + .[examples]                 -> mujoco 3.12.0, mink 1.3.0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cla-assistant

cla-assistant Bot commented Aug 22, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@Vittorio-Caggiano

Copy link
Copy Markdown
Collaborator

@M-Colley thanks for your PR and interest in myosuite. We are going to make a new release which should support the latest mujoco too. Do you need this version of myosuite compatible with the latest mujoco? in case, can you join slack and we can discuss more about it 1:1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants