Skip to content

Commit 33bfdce

Browse files
Merge remote-tracking branch 'upstream/main' into codex/pr233-push
2 parents 82dfba6 + 8161bba commit 33bfdce

38 files changed

Lines changed: 2917 additions & 196 deletions

.github/workflows/build.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,15 @@ jobs:
2222
cache-dependency-glob: test/requirements.txt
2323
- name: Test with pytest
2424
run: uv run --with-requirements test/requirements.txt pytest -n auto
25+
26+
package:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
30+
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
31+
with:
32+
python-version: "3.12"
33+
- name: Derive the registry
34+
run: uv run --no-project build_registry.py --no-archives --jobs "$(nproc)"
35+
- name: Test the package
36+
run: cd python && uv run --group dev pytest -n auto

.github/workflows/release.yml

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Every merge that touches a model directory or the package is released as
2+
# vYYYY.M.N. Archives go to the long-lived `assets` GitHub release and are
3+
# re-verified from their public URLs before anything reaches PyPI, which is
4+
# immutable. The version is read from the tag, which is pushed last so a failed
5+
# publish leaves no tag behind.
6+
name: release
7+
8+
on:
9+
push:
10+
branches: [main]
11+
workflow_dispatch:
12+
13+
concurrency: release
14+
15+
jobs:
16+
release:
17+
runs-on: ubuntu-latest
18+
environment: pypi
19+
permissions:
20+
contents: write # release assets, tag
21+
id-token: write # trusted publishing
22+
steps:
23+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
24+
with:
25+
fetch-depth: 0
26+
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
27+
with:
28+
version: "0.12.1"
29+
- run: uv python install 3.12
30+
31+
- name: Pick the version, or stop if nothing to release
32+
id: version
33+
run: |
34+
last=$(git tag --list 'v*' --sort=-v:refname | head -1)
35+
if [ -n "$last" ] && [ "$GITHUB_EVENT_NAME" = push ] && ! git diff --name-only "$last" HEAD \
36+
| grep -vE '^(\.|assets/|test/)' | grep -qE '/|^(catalog|build_registry)\.py$'; then
37+
echo "no model directory or package change since $last"; exit 0
38+
fi
39+
month=$(date -u +%Y.%-m)
40+
n=$(git tag --list "v$month.*" | sed "s/^v$month\.//" | sort -n | tail -1)
41+
version="$month.$(( ${n:--1} + 1 ))"
42+
git tag "v$version" # local until publish succeeds; the build reads the version from it
43+
echo "version=$version" >> "$GITHUB_OUTPUT"
44+
45+
- name: Build the archives not yet released, and the registry
46+
if: steps.version.outputs.version
47+
env:
48+
GH_TOKEN: ${{ github.token }}
49+
run: |
50+
gh release view assets --json assets --jq '[.assets[] | select(.digest) | {key: .name, value: {sha256: (.digest | ltrimstr("sha256:")), download_size: .size}}] | from_entries' > published.json || echo '{}' > published.json
51+
uv run --no-project build_registry.py --jobs "$(nproc)" --published published.json
52+
53+
- name: Upload new archives
54+
if: steps.version.outputs.version
55+
env:
56+
GH_TOKEN: ${{ github.token }}
57+
run: |
58+
gh release view assets >/dev/null 2>&1 || gh release create assets --title "Model archives" \
59+
--notes "Content-addressed archives used by the mujoco-menagerie package. Do not delete." --target "$GITHUB_SHA"
60+
existing=$(gh release view assets --json assets --jq '.assets[].name')
61+
for f in python/dist-assets/*.tar.xz; do
62+
grep -qx "$(basename "$f")" <<<"$existing" || gh release upload assets "$f"
63+
done
64+
65+
- name: Re-verify every archive from its public URL
66+
if: steps.version.outputs.version
67+
env:
68+
PYTHONPATH: python/src
69+
run: |
70+
uv run --no-project python - <<'EOF'
71+
import hashlib, json, urllib.request
72+
from mujoco_menagerie._cache import DEFAULT_BASE_URL
73+
for name, r in json.load(open('python/src/mujoco_menagerie/registry.json'))['robots'].items():
74+
data = urllib.request.urlopen(f"{DEFAULT_BASE_URL}/{r['asset']}").read()
75+
assert hashlib.sha256(data).hexdigest() == r['sha256'] and len(data) == r['download_size'], name
76+
EOF
77+
78+
- name: Build, smoke test, publish
79+
if: steps.version.outputs.version
80+
env:
81+
VERSION: ${{ steps.version.outputs.version }}
82+
run: |
83+
make build
84+
ls "dist/mujoco_menagerie-$VERSION-py3-none-any.whl"
85+
uv publish
86+
87+
- name: Tag
88+
if: steps.version.outputs.version
89+
env:
90+
VERSION: ${{ steps.version.outputs.version }}
91+
run: git push origin "v$VERSION"

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
.DS_Store
22
uv.lock
33
gallery.md
4+
# Generated by build_registry.py; only meaningful at a tagged commit.
5+
python/src/mujoco_menagerie/registry.json
6+
python/dist-assets/
7+
python/dist/
8+
dist/

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
All notable changes to this repository will be documented here.
44

5+
## [2026-09-01]
6+
7+
- Added the `mujoco-menagerie` Python package under `python/`: models download on first use into a content-addressed cache, pinned by package version. `build_registry.py` derives the registry from the checkout; `release.yml` publishes archives and the wheel on a `vYYYY.M.N` tag. Extracted the gallery's catalog tables into `catalog.py`, shared by both tools, and registered seven model directories that were missing from the README gallery.
8+
59
## [2026-07-04]
610

711
- Cleaned up manual `<statistic>` camera overrides across scene XMLs to improve visualizer default framings. Removed arbitrary `center` attributes, only keeping `extent` where finite floor surfaces or heightfields require custom framing bounds.

CONTRIBUTING.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ finer control:
4646

4747
CI runs the same things, so a green `make all` locally means a green CI.
4848

49+
## Releases
50+
51+
Menagerie ships as the `mujoco-menagerie` package ([`python/`](python/DOC.md)).
52+
Every merge that touches a model directory or the package is released
53+
automatically as `YYYY.M.N`, so every model fix has a version. Everything in
54+
the package is derived from the checkout by `build_registry.py`, which CI runs
55+
on every PR. Every model directory must appear in `catalog.py`'s `MODEL_MAP`; a
56+
directory with several `scene*.xml` and no `scene.xml` names its default in
57+
`PREVIEW_OVERRIDES`.
58+
4959
## XML style
5060

5161
You can browse existing models to get a general sense of the style we adopt for

LICENSE

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4257,6 +4257,213 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
42574257
SOFTWARE.
42584258

42594259

4260+
================================================================================
4261+
License for contents in the directory 'python/'
4262+
================================================================================
4263+
4264+
Apache License
4265+
Version 2.0, January 2004
4266+
http://www.apache.org/licenses/
4267+
4268+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
4269+
4270+
1. Definitions.
4271+
4272+
"License" shall mean the terms and conditions for use, reproduction,
4273+
and distribution as defined by Sections 1 through 9 of this document.
4274+
4275+
"Licensor" shall mean the copyright owner or entity authorized by
4276+
the copyright owner that is granting the License.
4277+
4278+
"Legal Entity" shall mean the union of the acting entity and all
4279+
other entities that control, are controlled by, or are under common
4280+
control with that entity. For the purposes of this definition,
4281+
"control" means (i) the power, direct or indirect, to cause the
4282+
direction or management of such entity, whether by contract or
4283+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
4284+
outstanding shares, or (iii) beneficial ownership of such entity.
4285+
4286+
"You" (or "Your") shall mean an individual or Legal Entity
4287+
exercising permissions granted by this License.
4288+
4289+
"Source" form shall mean the preferred form for making modifications,
4290+
including but not limited to software source code, documentation
4291+
source, and configuration files.
4292+
4293+
"Object" form shall mean any form resulting from mechanical
4294+
transformation or translation of a Source form, including but
4295+
not limited to compiled object code, generated documentation,
4296+
and conversions to other media types.
4297+
4298+
"Work" shall mean the work of authorship, whether in Source or
4299+
Object form, made available under the License, as indicated by a
4300+
copyright notice that is included in or attached to the work
4301+
(an example is provided in the Appendix below).
4302+
4303+
"Derivative Works" shall mean any work, whether in Source or Object
4304+
form, that is based on (or derived from) the Work and for which the
4305+
editorial revisions, annotations, elaborations, or other modifications
4306+
represent, as a whole, an original work of authorship. For the purposes
4307+
of this License, Derivative Works shall not include works that remain
4308+
separable from, or merely link (or bind by name) to the interfaces of,
4309+
the Work and Derivative Works thereof.
4310+
4311+
"Contribution" shall mean any work of authorship, including
4312+
the original version of the Work and any modifications or additions
4313+
to that Work or Derivative Works thereof, that is intentionally
4314+
submitted to Licensor for inclusion in the Work by the copyright owner
4315+
or by an individual or Legal Entity authorized to submit on behalf of
4316+
the copyright owner. For the purposes of this definition, "submitted"
4317+
means any form of electronic, verbal, or written communication sent
4318+
to the Licensor or its representatives, including but not limited to
4319+
communication on electronic mailing lists, source code control systems,
4320+
and issue tracking systems that are managed by, or on behalf of, the
4321+
Licensor for the purpose of discussing and improving the Work, but
4322+
excluding communication that is conspicuously marked or otherwise
4323+
designated in writing by the copyright owner as "Not a Contribution."
4324+
4325+
"Contributor" shall mean Licensor and any individual or Legal Entity
4326+
on behalf of whom a Contribution has been received by Licensor and
4327+
subsequently incorporated within the Work.
4328+
4329+
2. Grant of Copyright License. Subject to the terms and conditions of
4330+
this License, each Contributor hereby grants to You a perpetual,
4331+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
4332+
copyright license to reproduce, prepare Derivative Works of,
4333+
publicly display, publicly perform, sublicense, and distribute the
4334+
Work and such Derivative Works in Source or Object form.
4335+
4336+
3. Grant of Patent License. Subject to the terms and conditions of
4337+
this License, each Contributor hereby grants to You a perpetual,
4338+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
4339+
(except as stated in this section) patent license to make, have made,
4340+
use, offer to sell, sell, import, and otherwise transfer the Work,
4341+
where such license applies only to those patent claims licensable
4342+
by such Contributor that are necessarily infringed by their
4343+
Contribution(s) alone or by combination of their Contribution(s)
4344+
with the Work to which such Contribution(s) was submitted. If You
4345+
institute patent litigation against any entity (including a
4346+
cross-claim or counterclaim in a lawsuit) alleging that the Work
4347+
or a Contribution incorporated within the Work constitutes direct
4348+
or contributory patent infringement, then any patent licenses
4349+
granted to You under this License for that Work shall terminate
4350+
as of the date such litigation is filed.
4351+
4352+
4. Redistribution. You may reproduce and distribute copies of the
4353+
Work or Derivative Works thereof in any medium, with or without
4354+
modifications, and in Source or Object form, provided that You
4355+
meet the following conditions:
4356+
4357+
(a) You must give any other recipients of the Work or
4358+
Derivative Works a copy of this License; and
4359+
4360+
(b) You must cause any modified files to carry prominent notices
4361+
stating that You changed the files; and
4362+
4363+
(c) You must retain, in the Source form of any Derivative Works
4364+
that You distribute, all copyright, patent, trademark, and
4365+
attribution notices from the Source form of the Work,
4366+
excluding those notices that do not pertain to any part of
4367+
the Derivative Works; and
4368+
4369+
(d) If the Work includes a "NOTICE" text file as part of its
4370+
distribution, then any Derivative Works that You distribute must
4371+
include a readable copy of the attribution notices contained
4372+
within such NOTICE file, excluding those notices that do not
4373+
pertain to any part of the Derivative Works, in at least one
4374+
of the following places: within a NOTICE text file distributed
4375+
as part of the Derivative Works; within the Source form or
4376+
documentation, if provided along with the Derivative Works; or,
4377+
within a display generated by the Derivative Works, if and
4378+
wherever such third-party notices normally appear. The contents
4379+
of the NOTICE file are for informational purposes only and
4380+
do not modify the License. You may add Your own attribution
4381+
notices within Derivative Works that You distribute, alongside
4382+
or as an addendum to the NOTICE text from the Work, provided
4383+
that such additional attribution notices cannot be construed
4384+
as modifying the License.
4385+
4386+
You may add Your own copyright statement to Your modifications and
4387+
may provide additional or different license terms and conditions
4388+
for use, reproduction, or distribution of Your modifications, or
4389+
for any such Derivative Works as a whole, provided Your use,
4390+
reproduction, and distribution of the Work otherwise complies with
4391+
the conditions stated in this License.
4392+
4393+
5. Submission of Contributions. Unless You explicitly state otherwise,
4394+
any Contribution intentionally submitted for inclusion in the Work
4395+
by You to the Licensor shall be under the terms and conditions of
4396+
this License, without any additional terms or conditions.
4397+
Notwithstanding the above, nothing herein shall supersede or modify
4398+
the terms of any separate license agreement you may have executed
4399+
with Licensor regarding such Contributions.
4400+
4401+
6. Trademarks. This License does not grant permission to use the trade
4402+
names, trademarks, service marks, or product names of the Licensor,
4403+
except as required for reasonable and customary use in describing the
4404+
origin of the Work and reproducing the content of the NOTICE file.
4405+
4406+
7. Disclaimer of Warranty. Unless required by applicable law or
4407+
agreed to in writing, Licensor provides the Work (and each
4408+
Contributor provides its Contributions) on an "AS IS" BASIS,
4409+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
4410+
implied, including, without limitation, any warranties or conditions
4411+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
4412+
PARTICULAR PURPOSE. You are solely responsible for determining the
4413+
appropriateness of using or redistributing the Work and assume any
4414+
risks associated with Your exercise of permissions under this License.
4415+
4416+
8. Limitation of Liability. In no event and under no legal theory,
4417+
whether in tort (including negligence), contract, or otherwise,
4418+
unless required by applicable law (such as deliberate and grossly
4419+
negligent acts) or agreed to in writing, shall any Contributor be
4420+
liable to You for damages, including any direct, indirect, special,
4421+
incidental, or consequential damages of any character arising as a
4422+
result of this License or out of the use or inability to use the
4423+
Work (including but not limited to damages for loss of goodwill,
4424+
work stoppage, computer failure or malfunction, or any and all
4425+
other commercial damages or losses), even if such Contributor
4426+
has been advised of the possibility of such damages.
4427+
4428+
9. Accepting Warranty or Additional Liability. While redistributing
4429+
the Work or Derivative Works thereof, You may choose to offer,
4430+
and charge a fee for, acceptance of support, warranty, indemnity,
4431+
or other liability obligations and/or rights consistent with this
4432+
License. However, in accepting such obligations, You may act only
4433+
on Your own behalf and on Your sole responsibility, not on behalf
4434+
of any other Contributor, and only if You agree to indemnify,
4435+
defend, and hold each Contributor harmless for any liability
4436+
incurred by, or claims asserted against, such Contributor by reason
4437+
of your accepting any such warranty or additional liability.
4438+
4439+
END OF TERMS AND CONDITIONS
4440+
4441+
APPENDIX: How to apply the Apache License to your work.
4442+
4443+
To apply the Apache License to your work, attach the following
4444+
boilerplate notice, with the fields enclosed by brackets "[]"
4445+
replaced with your own identifying information. (Don't include
4446+
the brackets!) The text should be enclosed in the appropriate
4447+
comment syntax for the file format. We also recommend that a
4448+
file or class name and description of purpose be included on the
4449+
same "printed page" as the copyright notice for easier
4450+
identification within third-party archives.
4451+
4452+
Copyright [yyyy] [name of copyright owner]
4453+
4454+
Licensed under the Apache License, Version 2.0 (the "License");
4455+
you may not use this file except in compliance with the License.
4456+
You may obtain a copy of the License at
4457+
4458+
http://www.apache.org/licenses/LICENSE-2.0
4459+
4460+
Unless required by applicable law or agreed to in writing, software
4461+
distributed under the License is distributed on an "AS IS" BASIS,
4462+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4463+
See the License for the specific language governing permissions and
4464+
limitations under the License.
4465+
4466+
42604467
================================================================================
42614468
License for contents in the directory 'rainbow_robotics_rby1/'
42624469
================================================================================

0 commit comments

Comments
 (0)