From 230e71c5fffe3e3b40ace9688b437def1eb68889 Mon Sep 17 00:00:00 2001 From: TATP-233 Date: Thu, 10 Sep 2026 13:49:06 +0800 Subject: [PATCH] feat(superdex): published-wheel install, FR3 HF assets, unisim-core/unilab-rl 1.2.0 - Add the `superdex` optional extra delegating to `unisim-core[superdex]` (published SuperDex Physics/Robotics wheels, CPython 3.12/3.13 on Linux x86_64), replacing the temporary source-build setup; simplify the bilingual installation docs accordingly. - Guard `sim=mujoco` runtime checks on the `mujoco_uni` binding since plain `mujoco` now also arrives with the superdex extra. - Host FR3 native bot assets on Hugging Face (unilabsim/unilab-robots) like other robot meshes: the asset hub downloads `bots/arms/fr3_v2` on first use, `unilab-pull-assets --robot fr3_v2` pre-fetches, and SUPERDEX_ASSETS_PATH / env.superdex_assets_root remain audited local overrides. Exclude the downloaded bots from the wheel and git. - FR3 owner defaults play to the native interactive viewer (single env); record playback stays unavailable without an MJCF visual model. - Add a bilingual Go2 task guide (train + eval, record/interactive/sim2sim) to the SuperDex backend docs. - Bump unisim-core to >=1.2.0 and unilab-rl to ==1.2.0 (uv.lock and uv.rocm.lock refreshed); README ecosystem section lists the downstream wuji_unilab and legged-manipulation_unilab repos. Refs #1533, #1534 --- .gitignore | 1 + Makefile | 2 +- README.md | 12 +- README_zh.md | 11 +- docs/sphinx/source/changelog.md | 41 +++++ .../en/1-getting_started/2-installation.md | 2 + .../en/2-user_guide/3-backends/8-superdex.md | 118 ++++++++---- .../zh_CN/1-getting_started/2-installation.md | 2 + .../2-user_guide/3-backends/8-superdex.md | 102 +++++++---- pyproject.rocm.toml | 4 +- pyproject.toml | 23 ++- src/unilab/assets/hub.py | 72 +++++--- src/unilab/assets/pull.py | 24 ++- src/unilab/cli.py | 14 +- .../ppo/task/fr3_joint_target/superdex.yaml | 4 +- tests/assets/test_superdex_assets.py | 61 +++++- .../test_mujoco_scene_context_visual.py | 4 + tests/base/test_backend_imports.py | 2 +- tests/envs/test_fr3_superdex.py | 15 +- tests/test_cli.py | 8 +- tests/test_cli_runtime_requirements.py | 19 +- tests/test_pull_assets.py | 39 +++- tests/training/test_training_helpers.py | 3 + uv.lock | 173 +++++++++++++++++- uv.rocm.lock | 62 +++---- 25 files changed, 643 insertions(+), 175 deletions(-) diff --git a/.gitignore b/.gitignore index 32d4f98ef..1e768f36d 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,7 @@ src/unilab/assets/motions/x2/*.npz src/unilab/assets/motions/x2/*.csv # Robot mesh assets (downloaded from HF at runtime) +src/unilab/assets/bots/ src/unilab/assets/robots/x2/meshes/*.STL src/unilab/assets/robots/g1/assets/ src/unilab/assets/robots/g1/textures/ diff --git a/Makefile b/Makefile index ff1b41f5e..9b052837a 100644 --- a/Makefile +++ b/Makefile @@ -127,7 +127,7 @@ clean: find . -type d -name ".ruff_cache" -exec rm -rf {} + find . -type d -name "htmlcov" -exec rm -rf {} + find . -type f -name ".coverage" -delete - rm -f train_appo.log train_sac.log train_flashsac.log train_rsl_rl.log MUJOCO_LOG.TXT + rm -f train_appo.log train_td3.log train_sac.log train_flashsac.log train_rsl_rl.log MUJOCO_LOG.TXT find src/unilab/assets/.cache -type f ! -name '.gitkeep' -delete 2>/dev/null || true find src/unilab/assets/caches -type f ! -name '.gitkeep' -delete 2>/dev/null || true find src/unilab/assets/checkpoints -type f ! -name '.gitkeep' -delete 2>/dev/null || true diff --git a/README.md b/README.md index 9de8f9dad..bfe6dcf6f 100644 --- a/README.md +++ b/README.md @@ -104,11 +104,13 @@ and [support matrix](https://unilabsim.github.io/UniLab-doc/en/5-reference/5-sup ## Ecosystem UniLab is designed to be a shared task and training surface for robot-specific -repositories. Current downstream examples include -[MicroDuck RL](https://github.com/unilabsim/microduck_rl_unilab) and -[EngineAI RL](https://github.com/unilabsim/engineai_rl_unilab). They can ship -robot recipes independently while consuming the same task, backend, and RL -contracts. +repositories. They can ship robot recipes independently while consuming the +same task, backend, and RL contracts. Current downstream examples: + +- [MicroDuck RL](https://github.com/unilabsim/microduck_rl_unilab) +- [EngineAI RL](https://github.com/unilabsim/engineai_rl_unilab) +- [Wuji](https://github.com/unilabsim/wuji_unilab) +- [Legged Manipulation](https://github.com/unilabsim/legged-manipulation_unilab) ## Documentation diff --git a/README_zh.md b/README_zh.md index 1dc820493..6303a9527 100644 --- a/README_zh.md +++ b/README_zh.md @@ -96,10 +96,13 @@ uv run train --algo sac --task g1_walk_flat --sim mujoco ## 生态 -UniLab 被设计为机器人专属仓库共享的任务与训练界面。目前的下游示例包括 -[MicroDuck RL](https://github.com/unilabsim/microduck_rl_unilab) 和 -[EngineAI RL](https://github.com/unilabsim/engineai_rl_unilab)。它们可以独立发布机器人 -recipe,同时消费同一套 task、backend 和 RL contract。 +UniLab 被设计为机器人专属仓库共享的任务与训练界面。下游仓库可以独立发布机器人 +recipe,同时消费同一套 task、backend 和 RL contract。目前的下游示例: + +- [MicroDuck RL](https://github.com/unilabsim/microduck_rl_unilab) +- [EngineAI RL](https://github.com/unilabsim/engineai_rl_unilab) +- [Wuji](https://github.com/unilabsim/wuji_unilab) +- [Legged Manipulation](https://github.com/unilabsim/legged-manipulation_unilab) ## 文档 diff --git a/docs/sphinx/source/changelog.md b/docs/sphinx/source/changelog.md index eeba7911a..bcf43b539 100644 --- a/docs/sphinx/source/changelog.md +++ b/docs/sphinx/source/changelog.md @@ -13,6 +13,47 @@ UniLab 遵循[语义化版本](https://semver.org/)。本共享页面以中英 ## Unreleased / 未发布 +- Update the required `unisim-core` release to `>=1.2.0` and the pinned + `unilab-rl` release to `==1.2.0`, including the ROCm profile. + 将必需的 `unisim-core` 版本更新为 `>=1.2.0`,并将钉定的 `unilab-rl` 版本更新为 + `==1.2.0`,ROCm 配置档同步更新。 + +- Host the FR3 SuperDex native bot assets (collision SDF, render GLB, license) + on the Hugging Face dataset + [unilabsim/unilab-robots](https://huggingface.co/datasets/unilabsim/unilab-robots), + consistent with the other robot mesh assets. The asset hub downloads the + `bots/arms/fr3_v2` snapshot into `src/unilab/assets/` on first use, and + `uv run unilab-pull-assets --robot fr3_v2` pre-fetches it; + `SUPERDEX_ASSETS_PATH` / `env.superdex_assets_root` remain as overrides for + auditing a local `project_superdex` checkout and take precedence without + downloading. + FR3 SuperDex 原生 bot 资产(collision SDF、render GLB、许可证)改为托管在 + Hugging Face 数据集 + [unilabsim/unilab-robots](https://huggingface.co/datasets/unilabsim/unilab-robots), + 与其他机器人 mesh 资产的处理方式一致。asset hub 首次使用时自动把 + `bots/arms/fr3_v2` 快照下载到 `src/unilab/assets/`,也可用 + `uv run unilab-pull-assets --robot fr3_v2` 预拉取; + `SUPERDEX_ASSETS_PATH` / `env.superdex_assets_root` 保留为审计本地 + `project_superdex` checkout 的覆盖方式,优先级更高且不会触发下载。 + +- Add a `superdex` optional extra (`uv sync --extra superdex` or + `pip install "unilab[superdex]"`) that pulls the published SuperDex + Physics/Robotics 1.0.0 wheels (CPython 3.12/3.13, Linux x86_64) through + `unisim-core[superdex]`, replacing the temporary source-build setup. The + `sim=mujoco` runtime check now guards on the `mujoco_uni` binding, since + plain `mujoco` also arrives with the superdex extra. + SuperDex native interactive playback crashing on the first rendered frame + (`eval --sim superdex --render-mode interactive`) was first fixed in + `unisim-core` 1.1.6; the required release line is now `>=1.2.0`. + 新增 `superdex` optional extra(`uv sync --extra superdex` 或 + `pip install "unilab[superdex]"`),通过 `unisim-core[superdex]` + 安装已发布的 SuperDex Physics/Robotics 1.0.0 wheel(CPython 3.12/3.13、 + Linux x86_64),取代临时的源码编译安装方式。`sim=mujoco` 的运行时检查 + 改为检查 `mujoco_uni` 绑定,因为普通 `mujoco` 包也会随 superdex extra + 装入。SuperDex 原生 interactive 回放首帧渲染崩溃的问题 + (`eval --sim superdex --render-mode interactive`)最早在 `unisim-core` + 1.1.6 修复;当前必需的版本线为 `>=1.2.0`。 + - Go2 arm manipulation/locomotion, its legacy helpers, assets, tools and HIM-PPO owners moved to [legged-manipulation_unilab](https://github.com/unilabsim/legged-manipulation_unilab) under [#1528](https://github.com/unilabsim/UniLab/issues/1528). Dedicated source diff --git a/docs/sphinx/source/en/1-getting_started/2-installation.md b/docs/sphinx/source/en/1-getting_started/2-installation.md index 7ef2c90a3..3fedd9ea8 100644 --- a/docs/sphinx/source/en/1-getting_started/2-installation.md +++ b/docs/sphinx/source/en/1-getting_started/2-installation.md @@ -183,6 +183,7 @@ uv sync --extra mujoco --extra mjwarp --extra newton | MJWarp | `uv sync --extra mujoco --extra mjwarp` | NVIDIA CUDA and an explicit CUDA process device | | Genesis | `uv sync --extra genesis` | The validated path uses Linux x86_64, an NVIDIA GPU, and the pinned torch/Genesis versions | | Newton | `uv sync --extra newton` | NVIDIA CUDA; can be combined with the `mujoco` / `mjwarp` extras in one environment | +| SuperDex | `uv sync --extra superdex` | Published wheels support Linux x86_64 with CPython 3.12/3.13 only; FR3 assets download from Hugging Face on first use (`SUPERDEX_ASSETS_PATH` overrides with a local checkout) | | Drake | `make setup-drake` | C++20, Eigen/fmt/spdlog, and an existing Drake prefix or the script's download path | | IsaacGym | `bash scripts/tools/setup_isaacgym_env.sh` | Linux x86_64, NVIDIA driver, and a separate Python 3.8 worker environment | | IsaacSim | `bash scripts/tools/setup_isaacsim_env.sh` | Linux x86_64, NVIDIA CUDA, a separate Python 3.11 worker, and Kit EULA acceptance | @@ -198,6 +199,7 @@ runtime variables, renderer requirements, and verification commands: - {doc}`Genesis <../2-user_guide/3-backends/5-genesis>` - {doc}`Drake <../2-user_guide/3-backends/6-drake>` - {doc}`Newton <../2-user_guide/3-backends/7-newton>` +- {doc}`SuperDex <../2-user_guide/3-backends/8-superdex>` - {doc}`IsaacGym <../2-user_guide/3-backends/3-isaacgym>` - {doc}`IsaacSim <../2-user_guide/3-backends/4-isaacsim>` diff --git a/docs/sphinx/source/en/2-user_guide/3-backends/8-superdex.md b/docs/sphinx/source/en/2-user_guide/3-backends/8-superdex.md index db3b46266..73f1d13c8 100644 --- a/docs/sphinx/source/en/2-user_guide/3-backends/8-superdex.md +++ b/docs/sphinx/source/en/2-user_guide/3-backends/8-superdex.md @@ -9,52 +9,56 @@ training checks do not establish full-training performance or platform support. The implementation is tracked in [#1534](https://github.com/Motphys/UniLab/issues/1534) under [roadmap #1533](https://github.com/Motphys/UniLab/issues/1533). -## Local Development Setup +## Installation -This development profile uses locally linked UniSim and UniLab checkouts; it -does not require a new published version. SuperDex Physics/Robotics 1.0.0 requires -Python 3.12. CPU physics does not require CUDA. Native rendering and video are -not part of the FR3 owner; training defaults to `no_play=true`. - -In the UniLab checkout, use an existing Python 3.12 virtual environment or create -one, then install the local packages: - -For the temporary local SuperDex source build used by this roadmap, first run: +SuperDex Physics/Robotics 1.0.0 is published as Python wheels and is an +optional UniLab extra; no native source build is required. The wheels carry +the native batch executor and support CPython 3.12/3.13 on Linux x86_64 only; +on other platforms the extra is empty and the CLI reports a targeted runtime +diagnostic. CPU physics does not require CUDA. The FR3 owner has no record +(video) playback — the `.superdex_bot` asset carries no MJCF visual model — so +play defaults to the native interactive viewer (`play_render_mode=interactive` +with `play_env_num=1`); use `training.play_render_mode=none` for headless runs. ```bash -bash scripts/tools/setup_superdex_env.sh -source ~/.cache/unisim/superdex/env.sh +# Source checkout (default Python 3.13; wheels support CPython 3.12/3.13): +uv sync --extra superdex + +# From PyPI: +pip install "unilab[superdex]" ``` -With no arguments the script clones the modified -`unilabsim/project_superdex` integration branch, installs the public SuperDex -Python facade, builds `mochi_physics_pybind` and `superdex_robotics_pybind` in -Release mode, and installs the local UniSim/UniRL/UniLab checkouts editable. It -does not publish or install a SuperDex wheel from PyPI. The generated -`env.sh` exports the assets and native-extension paths. Re-run the script after -changing the SuperDex checkout; CMake reuses the existing build directory. +The extra delegates version pins to UniSim through `unisim-core[superdex]`. +UniSim's superdex extra already carries the plain `mujoco` package (used for +MJCF conversion and the offline playback renderer); `mujoco-uni-runtime` is +not required — only the MuJoCo physics backend needs it. The current wheels +are a temporary unilabsim build (`superdex-physics-uni` / +`superdex-robotics-uni`); once the upstream project_superdex release publishes +the `superdex-physics` / `superdex-robotics` wheels, UniSim switches the +package names and UniLab needs no change. + +Native FR3 assets are hosted on Hugging Face +([unilabsim/unilab-robots](https://huggingface.co/datasets/unilabsim/unilab-robots)), +like the other robot mesh assets; the wheels do not carry robot binaries. The +asset hub registers `bots/arms/fr3_v2/fr3_v2.superdex_bot` and downloads the +snapshot into `src/unilab/assets/` on first use, checking its collision SDF, +render files, `LICENSE` and `NOTICE` before constructing physics. To pre-fetch +the assets (e.g. for CI or offline prep): ```bash -uv venv --python 3.12 -export UNILAB_LOCAL_UNISIM=/absolute/path/to/unisim -uv pip install -e "${UNILAB_LOCAL_UNISIM}[superdex,mujoco]" -e . --group pyproject.toml:dev -export UV_NO_SYNC=1 -export SUPERDEX_ASSETS_PATH=/absolute/path/to/project_superdex/assets +uv run unilab-pull-assets --robot fr3_v2 ``` -`UNILAB_LOCAL_UNISIM` enables the repository's local dependency validation: -tests require an editable installation and check that its metadata and imported -module point to exactly that checkout. Without this variable, the normal -indexed-release requirement remains in force. `UV_NO_SYNC=1` preserves the local -links when running existing Make targets; `uv sync` would re-resolve the locked -release profile. +To audit a local `project_superdex` checkout instead, set +`SUPERDEX_ASSETS_PATH=/absolute/path/to/project_superdex/assets`, or set +`env.superdex_assets_root=/absolute/path/to/project_superdex/assets` to +override it for a specific owner invocation. An explicit root takes precedence +over the Hugging Face download and never downloads. -Native FR3 assets remain in the upstream SuperDex checkout. The asset hub -registers `bots/arms/fr3_v2/fr3_v2.superdex_bot`, checking its collision SDF, -render files, `LICENSE` and `NOTICE` before constructing physics. No native -robot binaries are bundled or downloaded by UniLab. Set -`env.superdex_assets_root=/absolute/path/to/project_superdex/assets` to override -`SUPERDEX_ASSETS_PATH` for a specific owner invocation. +A local source build is only needed when changing the SuperDex engine itself: +`bash scripts/tools/setup_superdex_env.sh` clones the integration branch, +builds the native extensions and links the local UniSim/UniLab checkouts +editable. Regular use does not need it. ## Run the FR3 Task @@ -70,9 +74,46 @@ research profile, not rated hardware limits. `superdex_effort_limits` declares the same bounds at the native backend boundary. The SDK remains single-threaded; the native scene executor below owns all supported CPU parallelism. +## Run the Go2 Task + +The `go2_joystick_flat/superdex` owner trains and evaluates the Go2 quadruped +on SuperDex. It inherits the MuJoCo owner's policy I/O (49 actor observations, +52 critic observations, 12 position-target actions) and control timing, +declares its own command ranges and reward weights, and explicitly opts into +contact approximation; see "Validation and Ownership" below for the contract +details. + +Train directly on SuperDex (CPU physics, automatic native workers): + +```bash +uv run train --algo ppo --task go2_joystick_flat --sim superdex +``` + +The owner defaults to 1024 environments and 400 iterations. Logs and +checkpoints land in `logs/rsl_rl_ppo/Go2JoystickFlat/_superdex/`. + +Evaluate a trained run with `--load-run`. Record playback is the default: it +steps 200 frames across 16 environments and writes `play_video.mp4` into the +run directory through the offline MuJoCo renderer while SuperDex remains the +physics backend: + +```bash +uv run eval --algo ppo --task go2_joystick_flat --sim superdex \ + --load-run 2026-09-10_10-50-00_superdex +``` + +For the native SuperDex (Polyscope) viewer instead of a video, add +`--render-mode interactive`; the CLI forces `training.play_env_num=1` and the +owner layer switches the env to the serial executor for that run. + +A checkpoint trained on MuJoCo can be evaluated on SuperDex directly +(sim2sim): pass its run directory to `--load-run`. The play entrypoint +validates the source `run_config.json` against the sim2sim contract before +constructing the environment and rejects incompatible policy I/O. + ## Default CPU Environment Parallelism -The backend uses SuperDex's source-built `SceneBatchExecutor`, a persistent C++ +The backend uses the `SceneBatchExecutor` shipped in the SuperDex wheel, a persistent C++ thread pool that owns the barrier across independent scenes. Each substep writes batched generalized forces, advances scenes, and returns articulated/link state, contact sensors and solver status without per-environment Python binding calls. @@ -172,7 +213,8 @@ uv run --no-sync pytest tests/assets/test_superdex_assets.py \ tests/envs/test_fr3_superdex.py tests/test_cli_runtime_requirements.py -q ``` -The optional native tests require the SDK and `SUPERDEX_ASSETS_PATH`; they cover +The optional native tests require the SDK and the FR3 assets (downloaded from +Hugging Face on demand, or provided through `SUPERDEX_ASSETS_PATH`); they cover finite rollout data, selected reset isolation, immediate observation refresh and a spawned `EnvFactory`. Missing runtime/assets produce an explicit skip; such a run is not native validation. The base asset/config tests need no native diff --git a/docs/sphinx/source/zh_CN/1-getting_started/2-installation.md b/docs/sphinx/source/zh_CN/1-getting_started/2-installation.md index f2a9685b1..ba055330d 100644 --- a/docs/sphinx/source/zh_CN/1-getting_started/2-installation.md +++ b/docs/sphinx/source/zh_CN/1-getting_started/2-installation.md @@ -165,6 +165,7 @@ uv sync --extra mujoco --extra mjwarp --extra newton | MJWarp | `uv sync --extra mujoco --extra mjwarp` | NVIDIA CUDA 和显式 CUDA process device | | Genesis | `uv sync --extra genesis` | 已验证路径使用 Linux x86_64、NVIDIA GPU 及固定版本 torch/Genesis | | Newton | `uv sync --extra newton` | NVIDIA CUDA;可与 `mujoco` / `mjwarp` extra 组合进同一环境 | +| SuperDex | `uv sync --extra superdex` | 已发布 wheel 仅支持 Linux x86_64、CPython 3.12/3.13;FR3 资产首次使用时自动从 Hugging Face 下载(`SUPERDEX_ASSETS_PATH` 可指定本地 checkout 覆盖) | | Drake | `make setup-drake` | C++20、Eigen/fmt/spdlog,以及已有 Drake prefix 或脚本下载路径 | | IsaacGym | `bash scripts/tools/setup_isaacgym_env.sh` | Linux x86_64、NVIDIA driver 和独立 Python 3.8 worker 环境 | | IsaacSim | `bash scripts/tools/setup_isaacsim_env.sh` | Linux x86_64、NVIDIA CUDA、独立 Python 3.11 worker 和 Kit EULA 接受 | @@ -179,6 +180,7 @@ Drake、IsaacGym 和 IsaacSim 的 setup 脚本会将外部 runtime 安装到仓 - {doc}`Genesis <../2-user_guide/3-backends/5-genesis>` - {doc}`Drake <../2-user_guide/3-backends/6-drake>` - {doc}`Newton <../2-user_guide/3-backends/7-newton>` +- {doc}`SuperDex <../2-user_guide/3-backends/8-superdex>` - {doc}`IsaacGym <../2-user_guide/3-backends/3-isaacgym>` - {doc}`IsaacSim <../2-user_guide/3-backends/4-isaacsim>` diff --git a/docs/sphinx/source/zh_CN/2-user_guide/3-backends/8-superdex.md b/docs/sphinx/source/zh_CN/2-user_guide/3-backends/8-superdex.md index cfa9f1681..1f802bab6 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/3-backends/8-superdex.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/3-backends/8-superdex.md @@ -8,44 +8,50 @@ owner 为固定基 `FR3JointTarget`,配置位于 实施见 [#1534](https://github.com/Motphys/UniLab/issues/1534),所属 roadmap 为 [#1533](https://github.com/Motphys/UniLab/issues/1533)。 -## 本地开发安装 +## 安装 -该开发配置使用本地链接的 UniSim 与 UniLab,不要求发布新版本。SuperDex -Physics/Robotics 1.0.0 要求 Python 3.12;CPU 物理不需要 CUDA。FR3 owner 暂不包含 -原生渲染和视频,默认 `no_play=true`。 - -本 roadmap 的临时方案使用改动后的 SuperDex 源码编译 native extension。先运行: +SuperDex Physics/Robotics 1.0.0 已发布 Python wheel,是 UniLab 的 optional +extra,不再需要源码编译 native extension。wheel 携带 native batch executor, +仅支持 CPython 3.12/3.13 的 Linux x86_64;其他平台上该 extra 为空,CLI 会给出 +针对性的运行时诊断。CPU 物理不需要 CUDA。FR3 owner 没有 record(视频)回放—— +`.superdex_bot` 资产没有 MJCF visual model——play 默认走 native interactive +viewer(`play_render_mode=interactive`,`play_env_num=1`);无显示环境下使用 +`training.play_render_mode=none`。 ```bash -bash scripts/tools/setup_superdex_env.sh -source ~/.cache/unisim/superdex/env.sh +# 源码 checkout(默认 Python 3.13;wheel 支持 CPython 3.12/3.13): +uv sync --extra superdex + +# 从 PyPI 安装: +pip install "unilab[superdex]" ``` -不传参数时,脚本会自动 clone `unilabsim/project_superdex` 的 integration branch, -安装 SuperDex Python facade,以 Release 模式编译 `mochi_physics_pybind` 和 -`superdex_robotics_pybind`,并将本地 UniSim、UniRL、UniLab 以 editable 方式安装。 -默认输出到 `~/.cache/unisim/superdex`,可通过 `UNISIM_SUPERDEX_HOME` 覆盖。它不会 -发布或从 PyPI 安装 SuperDex wheel;完成后 source 生成的 `env.sh` 即可使用。修改 -SuperDex 源码后可重复执行,CMake 会复用已有 build 目录。 +该 extra 通过 `unisim-core[superdex]` 委托 UniSim 钉定版本;UniSim 的 +superdex extra 已包含普通 `mujoco` 包(MJCF 转换与离线回放渲染使用),不需要 +`mujoco-uni-runtime`(仅 MuJoCo 物理后端需要)。当前 wheel 为临时 +unilabsim 构建(`superdex-physics-uni`/`superdex-robotics-uni`);上游 +project_superdex 发布正式 `superdex-physics`/`superdex-robotics` wheel 后, +UniSim 会切换包名,UniLab 侧无需改动。 -在 UniLab checkout 中使用已有的 Python 3.12 环境,或创建环境后安装本地包: +FR3 原生资产与其他机器人 mesh 资产一样托管在 Hugging Face +([unilabsim/unilab-robots](https://huggingface.co/datasets/unilabsim/unilab-robots)), +wheel 不携带机器人二进制。asset hub 注册 +`bots/arms/fr3_v2/fr3_v2.superdex_bot`,首次使用时自动把快照下载到 +`src/unilab/assets/`,并在物理构造前验证 collision SDF、render、`LICENSE` 和 +`NOTICE`。需要预拉取(如 CI 或离线准备)时: ```bash -uv venv --python 3.12 -export UNILAB_LOCAL_UNISIM=/absolute/path/to/unisim -uv pip install -e "${UNILAB_LOCAL_UNISIM}[superdex,mujoco]" -e . --group pyproject.toml:dev -export UV_NO_SYNC=1 -export SUPERDEX_ASSETS_PATH=/absolute/path/to/project_superdex/assets +uv run unilab-pull-assets --robot fr3_v2 ``` -`UNILAB_LOCAL_UNISIM` 启用严格的本地依赖验证:测试同时检查 editable 安装元数据 -和实际 import 路径确实指向指定 checkout。不设置时保留正常的索引发布包检查。 -`UV_NO_SYNC=1` 让现有 Make 目标保留本地链接;`uv sync` 会重新解析锁定的发布依赖。 +若要审计本地 `project_superdex` checkout,可设置 +`SUPERDEX_ASSETS_PATH=/absolute/path/to/project_superdex/assets`;单次运行也可通过 +`env.superdex_assets_root=/absolute/path/to/project_superdex/assets` 覆盖。显式 +root 优先于 Hugging Face 下载,且不会触发下载。 -FR3 原生资产保留在上游 checkout。asset hub 注册 -`bots/arms/fr3_v2/fr3_v2.superdex_bot`,在物理构造前验证 collision SDF、render、 -`LICENSE` 和 `NOTICE`。UniLab 不打包或下载这些二进制。单次运行可通过 -`env.superdex_assets_root=/absolute/path/to/project_superdex/assets` 覆盖环境变量。 +只有修改 SuperDex 引擎源码本身时才需要本地源码构建: +`bash scripts/tools/setup_superdex_env.sh` 会 clone integration branch、编译 +native extension 并以 editable 方式链接本地 UniSim/UniLab;常规使用不需要它。 ## 运行 FR3 任务 @@ -60,9 +66,42 @@ uv run --no-sync train --algo ppo --task fr3_joint_target --sim superdex \ `superdex_effort_limits` 在 native backend 边界声明同样的上限。SDK 固定为单线程; 下面的 native scene executor 是唯一支持的 CPU 并行层。 +## 运行 Go2 任务 + +`go2_joystick_flat/superdex` owner 在 SuperDex 上训练和评估 Go2 四足机器人。 +它继承 MuJoCo owner 的 policy I/O(49 维 actor 观测、52 维 critic 观测、 +12 维位置目标动作)与控制时序,声明自己的 command 范围和 reward 权重,并显式 +接受接触近似;contract 细节见下文"验证与归属"。 + +直接在 SuperDex 上训练(CPU 物理,自动 native worker): + +```bash +uv run train --algo ppo --task go2_joystick_flat --sim superdex +``` + +owner 默认 1024 个环境、400 轮迭代。日志和 checkpoint 写入 +`logs/rsl_rl_ppo/Go2JoystickFlat/_superdex/`。 + +用 `--load-run` 评估已训练的 run。默认 record 回放:跨 16 个环境推进 200 帧, +通过离线 MuJoCo renderer 把 `play_video.mp4` 写入 run 目录,物理仍由 SuperDex +执行: + +```bash +uv run eval --algo ppo --task go2_joystick_flat --sim superdex \ + --load-run 2026-09-10_10-50-00_superdex +``` + +如需 native SuperDex(Polyscope)viewer 而不是视频,加 +`--render-mode interactive`;CLI 会强制 `training.play_env_num=1`,owner 层同时 +把该次运行的 env 切到 serial executor。 + +在 MuJoCo 上训练的 checkpoint 可以直接在 SuperDex 上评估(sim2sim):把它的 +run 目录传给 `--load-run`。play 入口会在构造环境前按 sim2sim contract 验证来源 +`run_config.json`,并拒绝不兼容的 policy I/O。 + ## 默认 CPU 环境并行 -backend 使用 SuperDex 源码构建的 `SceneBatchExecutor`。它是跨独立 scene 的常驻 +backend 使用 SuperDex wheel 携带的 `SceneBatchExecutor`。它是跨独立 scene 的常驻 C++ 线程池:每个子步批量写入广义力、推进 scene,并回写 articulation/link state、 contact sensor 和 solver status,不再逐环境跨越 Python binding。资产物化、reset 和 cache frame 转换仍由 UniSim adapter 负责。这是 CPU 线程并行,不是 GPU physics;它不改变 @@ -145,9 +184,10 @@ uv run --no-sync pytest tests/assets/test_superdex_assets.py \ tests/envs/test_fr3_superdex.py tests/test_cli_runtime_requirements.py -q ``` -原生测试要求 SDK 和 `SUPERDEX_ASSETS_PATH`,覆盖有限数值 rollout、局部 reset -隔离、即时观测刷新及 spawn `EnvFactory`。缺失 SDK/资产会明确 skip,不能将 skip -记为原生验证通过。基础资产和配置测试不依赖原生资产 checkout。 +原生测试要求 SDK 和 FR3 资产(按需从 Hugging Face 下载,或通过 +`SUPERDEX_ASSETS_PATH` 提供),覆盖有限数值 rollout、局部 reset 隔离、即时观测 +刷新及 spawn `EnvFactory`。缺失 SDK/资产会明确 skip,不能将 skip 记为原生验证 +通过。基础资产和配置测试不依赖原生资产 checkout。 引擎转换与物理由 UniSim 拥有;资产注册、Hydra 与任务 term 由 UniLab 拥有。 相关约束见 {doc}`/adr/ADR-0007-unisim-extraction-boundary`、 diff --git a/pyproject.rocm.toml b/pyproject.rocm.toml index d0f4f1448..7e070bc87 100644 --- a/pyproject.rocm.toml +++ b/pyproject.rocm.toml @@ -25,10 +25,10 @@ dependencies = [ "numpy", # Physics implementations are provided by the independently released # unisim-core package from the production PyPI index. - "unisim-core>=1.1.5", + "unisim-core>=1.2.0", # RL algorithms and async runtimes live in the independently released # uni-rl package (distribution name ``unilab-rl``); see pyproject.toml. - "unilab-rl==1.1.3", + "unilab-rl==1.2.0", "torch==2.11.0", "triton-rocm==3.6.0 ; sys_platform == 'linux' and platform_machine == 'x86_64'", "gymnasium", diff --git a/pyproject.toml b/pyproject.toml index 7798912ee..199b0debc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,9 +6,10 @@ build-backend = "uv_build" # Robot meshes/textures are hosted on Hugging Face (unilabsim/unilab-robots) # and downloaded into these paths on first use; keep them out of the # wheel/sdist even when they exist in the source tree. XML and small metadata -# stay packaged. Directories must stay in sync with ROBOT_ASSET_SPECS in -# src/unilab/assets/hub.py. +# stay packaged. Directories must stay in sync with ROBOT_ASSET_SPECS and +# SUPERDEX_ROBOT_ASSET_SPECS in src/unilab/assets/hub.py. source-exclude = [ + "/src/unilab/assets/bots", "/src/unilab/assets/robots/a2/assets", "/src/unilab/assets/robots/allegro_hand/assets", "/src/unilab/assets/robots/g1/assets", @@ -41,12 +42,12 @@ dependencies = [ "numpy", # Physics implementations are provided by the independently released # unisim-core package from the production PyPI index. - "unisim-core>=1.1.5", + "unisim-core>=1.2.0", # RL algorithms and async runtimes (PPO/APPO/SAC/TD3 runners, # collectors, IPC, logging) live in the independently released uni-rl # package (distribution name ``unilab-rl``), consumed via the injected # env contract (uni_rl.env_contract.EnvFactory). Published on PyPI. - "unilab-rl==1.1.3", + "unilab-rl==1.2.0", "numba>=0.67", "prettytable>=3.10", # torch is a range (not an exact pin) so that published PyPI metadata lets @@ -164,6 +165,20 @@ genesis = [ "genesis-world==1.3.3", ] viser = ["viser>=1.0.26", "trimesh>=3.21.7"] +# SuperDex Physics/Robotics 1.0.0 ships as published wheels; the exact pins and +# the temporary superdex-uni build names are owned by unisim-core's superdex +# extra (they revert to superdex-physics/-robotics once the upstream +# project_superdex release lands). That extra already carries plain `mujoco` +# for MJCF conversion and the offline playback renderer; mujoco-uni-runtime is +# deliberately NOT bound here, since only the MuJoCo physics backend +# (unisim.backend.mujoco.backend) needs it and UniLab guards that backend on +# the `mujoco_uni` module. The wheels are CPython 3.12/3.13 Linux x86_64 only, +# so the marker keeps `uv lock` resolvable for the other +# required-environments; elsewhere the extra is empty and the CLI reports a +# targeted runtime diagnostic. +superdex = [ + "unisim-core[superdex] ; python_version >= '3.12' and sys_platform == 'linux' and platform_machine == 'x86_64'", +] [dependency-groups] dev = ["pytest", "pytest-cov", "ruff", "mypy", "pyright>=1.1.408"] diff --git a/src/unilab/assets/hub.py b/src/unilab/assets/hub.py index 447a066cc..c3846fc68 100644 --- a/src/unilab/assets/hub.py +++ b/src/unilab/assets/hub.py @@ -50,9 +50,12 @@ "x2": (("robots/x2/meshes", "pelvis.STL", "*.STL", "STL"),), } -# Upstream native robots stay in the user's audited SuperDex asset checkout. -# This registry deliberately has no download fallback or SDK import. Relative -# model names in task owners are resolved only beneath the configured root. +# Native SuperDex robots. When env.superdex_assets_root / SUPERDEX_ASSETS_PATH +# points at an audited upstream checkout, assets resolve there and nothing is +# downloaded. Without an explicit root, registered bots are downloaded from the +# HF robot repo into ASSETS_ROOT_PATH on first use, like every other robot +# asset. Each entry lists the collision, render and license files that must +# exist before physics construction. SUPERDEX_ROBOT_ASSET_SPECS: dict[str, tuple[str, ...]] = { "bots/arms/fr3_v2/fr3_v2.superdex_bot": ( "LICENSE", @@ -64,20 +67,44 @@ def resolve_superdex_robot_asset(model_file: str, *, assets_root: str | None = None) -> str: - """Resolve a registered native robot in a local SuperDex asset checkout. - - ``assets_root`` or ``SUPERDEX_ASSETS_PATH`` points to the upstream ``assets`` - directory, not the repository root. Required collision, visual and license - files are checked before physics construction. No files are downloaded or - copied into UniLab's package. + """Resolve a registered native SuperDex robot, downloading from HF if needed. + + ``assets_root`` or ``SUPERDEX_ASSETS_PATH`` points to an audited upstream + ``assets`` directory (not the repository root) and takes precedence; in + that mode nothing is downloaded. Without an explicit root, registered + ``bots/...`` names resolve beneath ``ASSETS_ROOT_PATH`` and are downloaded + from the Hugging Face robot repo on first use, like other robot assets. + Required collision, visual and license files are checked before physics + construction either way. """ root_value = assets_root if assets_root is not None else os.environ.get("SUPERDEX_ASSETS_PATH") - if not root_value or not root_value.strip(): - raise FileNotFoundError( - "SuperDex native assets require env.superdex_assets_root or SUPERDEX_ASSETS_PATH " - "pointing to the project_superdex/assets directory" - ) - root = Path(root_value).expanduser().resolve() + if root_value and root_value.strip(): + return _resolve_superdex_under_root(model_file, Path(root_value).expanduser().resolve()) + + supplied = Path(model_file).expanduser() + if supplied.is_absolute(): + try: + relative = supplied.resolve().relative_to(ASSETS_ROOT_PATH.resolve()).as_posix() + except ValueError: + raise ValueError( + f"SuperDex robot asset is not registered: {model_file}. Provide a " + "registered bots/... name or set env.superdex_assets_root / " + "SUPERDEX_ASSETS_PATH for a local checkout" + ) from None + else: + relative = supplied.as_posix() + if relative not in SUPERDEX_ROBOT_ASSET_SPECS: + raise ValueError(f"SuperDex robot asset is not registered: {relative}") + directory = posixpath.dirname(relative) + _resolve_snapshot_dir( + directory, repo_id=_HF_ROBOTS_REPO_ID, marker=posixpath.basename(relative) + ) + _check_superdex_asset_completeness(ASSETS_ROOT_PATH, relative) + return str(ASSETS_ROOT_PATH / relative) + + +def _resolve_superdex_under_root(model_file: str, root: Path) -> str: + """Resolve a registered native robot in an audited local SuperDex checkout.""" supplied = Path(model_file).expanduser() resolved = (supplied if supplied.is_absolute() else root / supplied).resolve() try: @@ -86,17 +113,20 @@ def resolve_superdex_robot_asset(model_file: str, *, assets_root: str | None = N raise ValueError(f"SuperDex robot asset must be inside configured root {root}") from exc if relative not in SUPERDEX_ROBOT_ASSET_SPECS: raise ValueError(f"SuperDex robot asset is not registered: {relative}") - required = ( - resolved, - *(resolved.parent / item for item in SUPERDEX_ROBOT_ASSET_SPECS[relative]), - ) + _check_superdex_asset_completeness(root, relative) + return str(resolved) + + +def _check_superdex_asset_completeness(root: Path, relative: str) -> None: + """Fail before physics construction when a registered bot is incomplete.""" + base = root / relative + required = (base, *(base.parent / item for item in SUPERDEX_ROBOT_ASSET_SPECS[relative])) missing = [str(path) for path in required if not path.is_file()] if missing: raise FileNotFoundError( - "SuperDex registered robot asset is incomplete; restore the upstream checkout " + "SuperDex registered robot asset is incomplete; restore the asset directory " f"including collision/render files and license notices: {', '.join(missing)}" ) - return str(resolved) def resolve_motion_files( diff --git a/src/unilab/assets/pull.py b/src/unilab/assets/pull.py index cd2696a96..168240ef4 100644 --- a/src/unilab/assets/pull.py +++ b/src/unilab/assets/pull.py @@ -9,6 +9,7 @@ Usage: uv run unilab-pull-assets # pull the default robot (x2) uv run unilab-pull-assets --robot g1 + uv run unilab-pull-assets --robot fr3_v2 # SuperDex native bot uv run unilab-pull-assets --robot all # pull every registered robot """ @@ -20,7 +21,12 @@ from dataclasses import dataclass from pathlib import Path -from unilab.assets.hub import ROBOT_ASSET_SPECS, resolve_robot_asset_dir +from unilab.assets.hub import ( + ROBOT_ASSET_SPECS, + SUPERDEX_ROBOT_ASSET_SPECS, + resolve_robot_asset_dir, + resolve_superdex_robot_asset, +) _ALL = "all" @@ -32,6 +38,14 @@ class _AssetSummary: label: str +def _superdex_bot_names() -> dict[str, str]: + """Map a short bot name (``fr3_v2``) to its ``SUPERDEX_ROBOT_ASSET_SPECS`` key.""" + return { + key.rsplit("/", 1)[-1].replace(".superdex_bot", ""): key + for key in SUPERDEX_ROBOT_ASSET_SPECS + } + + def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( @@ -49,10 +63,16 @@ def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: def _sorted_robots() -> list[str]: - return sorted(ROBOT_ASSET_SPECS) + return sorted(ROBOT_ASSET_SPECS) + sorted(_superdex_bot_names()) def _pull_robot(robot: str) -> list[_AssetSummary]: + superdex_bots = _superdex_bot_names() + if robot in superdex_bots: + resolved = resolve_superdex_robot_asset(superdex_bots[robot]) + target = Path(resolved).parent + count = sum(1 for path in target.rglob("*") if path.is_file()) + return [_AssetSummary(target=target, count=count, label="asset")] summaries: list[_AssetSummary] = [] for directory, marker, pattern, label in ROBOT_ASSET_SPECS[robot]: target = resolve_robot_asset_dir(directory, marker=marker, show_progress=False) diff --git a/src/unilab/cli.py b/src/unilab/cli.py index 9fad69e91..acb288204 100644 --- a/src/unilab/cli.py +++ b/src/unilab/cli.py @@ -109,7 +109,10 @@ def _check_load_run(load_run: str) -> None: def _check_runtime_requirements(algo: str, sim: str) -> None: - if sim == "mujoco" and find_spec("mujoco") is None: + # The MuJoCo physics backend (unisim.backend.mujoco.backend) needs the + # mujoco-uni-runtime native binding; plain `mujoco` can also arrive via + # other extras (e.g. superdex), so gate on `mujoco_uni` here. + if sim == "mujoco" and (find_spec("mujoco") is None or find_spec("mujoco_uni") is None): raise SystemExit( "sim=mujoco requires the MuJoCo extra. Install it with " "`pip install unilab[mujoco]` (or `uv sync --extra mujoco` in a source checkout)." @@ -134,15 +137,16 @@ def _check_runtime_requirements(algo: str, sim: str) -> None: from unisim.backend.superdex.dependencies import superdex_dependencies_available except ImportError as exc: raise SystemExit( - "sim=superdex requires the locally linked UniSim SuperDex development checkout; " + "sim=superdex requires unisim-core>=1.1.5 with the SuperDex adapter; " "the installed unisim-core does not provide that adapter." ) from exc if not superdex_dependencies_available(): raise SystemExit( - "sim=superdex requires Python 3.12 or 3.13 and the SuperDex Physics/Robotics " - "runtime. Install the locally linked UniSim superdex extra in a supported " - "Python environment; see the SuperDex backend page for local development setup." + "sim=superdex requires Python 3.12 or 3.13 on Linux x86_64 and the " + "SuperDex Physics/Robotics runtime. Install it with " + "`uv sync --extra superdex` in a source checkout " + "(or `pip install unilab[superdex]`)." ) if sim == "motrix" and find_spec("motrixsim") is None: raise SystemExit( diff --git a/src/unilab/conf/ppo/task/fr3_joint_target/superdex.yaml b/src/unilab/conf/ppo/task/fr3_joint_target/superdex.yaml index 2e005373a..33960298c 100644 --- a/src/unilab/conf/ppo/task/fr3_joint_target/superdex.yaml +++ b/src/unilab/conf/ppo/task/fr3_joint_target/superdex.yaml @@ -7,8 +7,8 @@ training: task_name: FR3JointTarget sim_backend: superdex device: cpu - no_play: true - play_render_mode: none + play_render_mode: interactive + play_env_num: 1 algo: num_envs: 2 diff --git a/tests/assets/test_superdex_assets.py b/tests/assets/test_superdex_assets.py index 62001653a..b042701ae 100644 --- a/tests/assets/test_superdex_assets.py +++ b/tests/assets/test_superdex_assets.py @@ -1,9 +1,10 @@ -"""Native SuperDex assets resolve only through the audited local registry.""" +"""Native SuperDex assets resolve via an audited local root or the HF hub.""" from pathlib import Path import pytest +from unilab.assets import hub from unilab.assets.hub import SUPERDEX_ROBOT_ASSET_SPECS, resolve_superdex_robot_asset MODEL = "bots/arms/fr3_v2/fr3_v2.superdex_bot" @@ -29,10 +30,36 @@ def test_local_superdex_asset_root_precedence_and_absolute_paths( assert resolve_superdex_robot_asset(MODEL) == expected -def test_superdex_assets_require_explicit_local_root(monkeypatch: pytest.MonkeyPatch) -> None: +def _fake_snapshot_dir(asset_root: Path, calls: list[tuple[str, str, str]]): + def fake(directory: str, *, repo_id: str, marker: str, show_progress: bool = True) -> Path: + calls.append((directory, repo_id, marker)) + return asset_root / directory + + return fake + + +def test_superdex_assets_download_from_hub_without_local_root( + asset_root: Path, monkeypatch: pytest.MonkeyPatch +) -> None: monkeypatch.delenv("SUPERDEX_ASSETS_PATH", raising=False) - with pytest.raises(FileNotFoundError, match="SUPERDEX_ASSETS_PATH"): - resolve_superdex_robot_asset(MODEL) + monkeypatch.setattr(hub, "ASSETS_ROOT_PATH", asset_root) + calls: list[tuple[str, str, str]] = [] + monkeypatch.setattr(hub, "_resolve_snapshot_dir", _fake_snapshot_dir(asset_root, calls)) + + assert resolve_superdex_robot_asset(MODEL) == str(asset_root / MODEL) + assert calls == [("bots/arms/fr3_v2", hub._HF_ROBOTS_REPO_ID, "fr3_v2.superdex_bot")] + + +def test_superdex_assets_explicit_root_never_downloads( + asset_root: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + def fail(*args: object, **kwargs: object) -> None: + raise AssertionError("audited local root must not trigger HF downloads") + + monkeypatch.setattr(hub, "_resolve_snapshot_dir", fail) + assert resolve_superdex_robot_asset(MODEL, assets_root=str(asset_root)) == str( + asset_root / MODEL + ) def test_superdex_assets_reject_unregistered_and_escaping_paths(asset_root: Path) -> None: @@ -42,8 +69,34 @@ def test_superdex_assets_reject_unregistered_and_escaping_paths(asset_root: Path resolve_superdex_robot_asset("../outside.superdex_bot", assets_root=str(asset_root)) +def test_superdex_hub_mode_rejects_unregistered_paths( + monkeypatch: pytest.MonkeyPatch, tmp_path: Path +) -> None: + monkeypatch.delenv("SUPERDEX_ASSETS_PATH", raising=False) + monkeypatch.setattr(hub, "ASSETS_ROOT_PATH", tmp_path) + calls: list[tuple[str, str, str]] = [] + monkeypatch.setattr(hub, "_resolve_snapshot_dir", _fake_snapshot_dir(tmp_path, calls)) + with pytest.raises(ValueError, match="not registered"): + resolve_superdex_robot_asset("bots/arms/unknown/unknown.superdex_bot") + with pytest.raises(ValueError, match="not registered"): + resolve_superdex_robot_asset("/outside/fr3_v2.superdex_bot") + assert calls == [] + + def test_superdex_assets_fail_before_sdk_on_incomplete_collision(asset_root: Path) -> None: missing = asset_root / Path(MODEL).parent / "collision/fr3_link4_collision.mochi.h5" missing.unlink() with pytest.raises(FileNotFoundError, match="fr3_link4_collision"): resolve_superdex_robot_asset(MODEL, assets_root=str(asset_root)) + + +def test_superdex_hub_mode_checks_completeness_after_download( + asset_root: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.delenv("SUPERDEX_ASSETS_PATH", raising=False) + monkeypatch.setattr(hub, "ASSETS_ROOT_PATH", asset_root) + (asset_root / Path(MODEL).parent / "NOTICE").unlink() + calls: list[tuple[str, str, str]] = [] + monkeypatch.setattr(hub, "_resolve_snapshot_dir", _fake_snapshot_dir(asset_root, calls)) + with pytest.raises(FileNotFoundError, match="NOTICE"): + resolve_superdex_robot_asset(MODEL) diff --git a/tests/base/backend/test_mujoco_scene_context_visual.py b/tests/base/backend/test_mujoco_scene_context_visual.py index 0ff80c05b..0c7182d31 100644 --- a/tests/base/backend/test_mujoco_scene_context_visual.py +++ b/tests/base/backend/test_mujoco_scene_context_visual.py @@ -9,6 +9,10 @@ from pathlib import Path +import pytest + +pytest.importorskip("mujoco_uni") + from unisim.backend.mujoco.backend import _build_mujoco_scene_context from unilab.base.scene import SceneCfg diff --git a/tests/base/test_backend_imports.py b/tests/base/test_backend_imports.py index 187d8c39e..a21e0eb91 100644 --- a/tests/base/test_backend_imports.py +++ b/tests/base/test_backend_imports.py @@ -86,7 +86,7 @@ def test_mujoco_backend_import_path_does_not_eagerly_import_motrix() -> None: print("mujoco_runtime", "mujoco" in sys.modules) print("mujoco_backend", "unisim.backend.mujoco.backend" in sys.modules) - if importlib.util.find_spec("mujoco") is not None: + if importlib.util.find_spec("mujoco_uni") is not None: import unisim.backend.mujoco.backend print("mujoco_backend imported") else: diff --git a/tests/envs/test_fr3_superdex.py b/tests/envs/test_fr3_superdex.py index 3b491d59a..36a435ec2 100644 --- a/tests/envs/test_fr3_superdex.py +++ b/tests/envs/test_fr3_superdex.py @@ -3,7 +3,6 @@ from __future__ import annotations import multiprocessing as mp -import os from pathlib import Path from typing import Any @@ -44,7 +43,8 @@ def test_fr3_owner_has_torque_control_without_free_root_terms( assert list(cfg.observations["policy"].terms) == ["target_error", "joint_vel", "actions"] assert cfg.superdex_effort_limits == [20.0] * 4 + [5.0] * 3 assert cfg.superdex_num_workers == 0 - assert owner.training.no_play and owner.training.device == "cpu" + assert owner.training.play_render_mode == "interactive" + assert owner.training.play_env_num == 1 and owner.training.device == "cpu" assert "superdex" in cli.SUPPORTED_SIMS monkeypatch.setattr(cli, "_check_runtime_requirements", lambda *_: None) command = cli.build_command( @@ -70,10 +70,17 @@ def test_superdex_owner_options_reject_invalid_values(kwargs: dict[str, Any]) -> def _require_runtime() -> None: - if not os.environ.get("SUPERDEX_ASSETS_PATH"): - pytest.skip("native FR3 integration requires SUPERDEX_ASSETS_PATH") pytest.importorskip("superdex.physics") pytest.importorskip("superdex.robotics") + from unilab.assets.hub import resolve_superdex_robot_asset + + try: + resolve_superdex_robot_asset("bots/arms/fr3_v2/fr3_v2.superdex_bot") + except Exception as exc: # noqa: BLE001 - any resolution failure means skip + pytest.skip( + "native FR3 integration needs the FR3 assets: allow Hugging Face download " + f"or set SUPERDEX_ASSETS_PATH to a local checkout ({exc})" + ) def test_fr3_native_rollout_and_selected_reset() -> None: diff --git a/tests/test_cli.py b/tests/test_cli.py index f483cb722..ce5bac489 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -224,7 +224,7 @@ def test_eval_mujoco_interactive_routes_to_dedicated_viewer( monkeypatch.setattr( cli, "find_spec", - lambda name: ModuleSpec(name, loader=None) if name == "mujoco" else None, + lambda name: ModuleSpec(name, loader=None) if name in {"mujoco", "mujoco_uni"} else None, ) command = cli.build_command( @@ -270,7 +270,7 @@ def test_eval_mujoco_interactive_honors_profile_and_render_override( monkeypatch.setattr( cli, "find_spec", - lambda name: ModuleSpec(name, loader=None) if name == "mujoco" else None, + lambda name: ModuleSpec(name, loader=None) if name in {"mujoco", "mujoco_uni"} else None, ) command = cli.build_command( @@ -398,7 +398,7 @@ def test_eval_mujoco_interactive_preserves_explicit_action_mode( monkeypatch.setattr( cli, "find_spec", - lambda name: ModuleSpec(name, loader=None) if name == "mujoco" else None, + lambda name: ModuleSpec(name, loader=None) if name in {"mujoco", "mujoco_uni"} else None, ) command = cli.build_command( @@ -554,7 +554,7 @@ def test_eval_mujoco_interactive_falls_back_to_sibling_owner( monkeypatch.setattr( cli, "find_spec", - lambda name: ModuleSpec(name, loader=None) if name == "mujoco" else None, + lambda name: ModuleSpec(name, loader=None) if name in {"mujoco", "mujoco_uni"} else None, ) command = cli.build_command( diff --git a/tests/test_cli_runtime_requirements.py b/tests/test_cli_runtime_requirements.py index cb83b19d8..572361b8c 100644 --- a/tests/test_cli_runtime_requirements.py +++ b/tests/test_cli_runtime_requirements.py @@ -12,6 +12,17 @@ def test_check_runtime_requirements_requires_mujoco_extra(monkeypatch: pytest.Mo cli._check_runtime_requirements("ppo", "mujoco") +def test_check_runtime_requirements_mujoco_needs_the_uni_runtime( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Plain `mujoco` can arrive via other extras (e.g. superdex); the MuJoCo + # physics backend is only usable with the mujoco-uni-runtime binding. + monkeypatch.setattr(cli, "find_spec", lambda name: None if name == "mujoco_uni" else object()) + + with pytest.raises(SystemExit, match="sim=mujoco requires the MuJoCo extra"): + cli._check_runtime_requirements("ppo", "mujoco") + + def test_check_runtime_requirements_requires_motrix_extra(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(cli, "find_spec", lambda name: None if name == "motrixsim" else object()) @@ -47,15 +58,17 @@ def test_superdex_missing_runtime_reports_python_and_sdk(monkeypatch: pytest.Mon from unisim.backend.superdex import dependencies monkeypatch.setattr(dependencies, "superdex_dependencies_available", lambda: False) - with pytest.raises(SystemExit, match="Python 3.12.*Physics/Robotics"): + with pytest.raises( + SystemExit, match=r"Python 3\.12.*Physics/Robotics.*uv sync --extra superdex" + ): cli._check_runtime_requirements("ppo", "superdex") -def test_superdex_old_unisim_reports_local_link_requirement( +def test_superdex_old_unisim_reports_adapter_requirement( monkeypatch: pytest.MonkeyPatch, ) -> None: import sys monkeypatch.setitem(sys.modules, "unisim.backend.superdex.dependencies", None) - with pytest.raises(SystemExit, match="locally linked UniSim SuperDex"): + with pytest.raises(SystemExit, match="unisim-core>=1.1.5 with the SuperDex adapter"): cli._check_runtime_requirements("ppo", "superdex") diff --git a/tests/test_pull_assets.py b/tests/test_pull_assets.py index 082fd02c6..957992e8d 100644 --- a/tests/test_pull_assets.py +++ b/tests/test_pull_assets.py @@ -67,6 +67,27 @@ def fake_resolver(directory: str, *, marker: str, show_progress: bool) -> Path: assert lines[-1].startswith("Robot assets ready: 1 robots, 2 directories, 56 files") +def test_pull_assets_fr3_v2_uses_superdex_resolver( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, + capsys: pytest.CaptureFixture[str], +): + target = _populate(tmp_path / "fr3_v2", suffix=".h5", count=3) + calls: list[str] = [] + + def fake_superdex_resolver(model_file: str) -> str: + calls.append(model_file) + return str(target / "fr3_v2.superdex_bot") + + monkeypatch.setattr(pull_assets, "resolve_superdex_robot_asset", fake_superdex_resolver) + + assert pull_assets.main(["--robot", "fr3_v2"]) == 0 + assert calls == ["bots/arms/fr3_v2/fr3_v2.superdex_bot"] + lines = capsys.readouterr().out.strip().splitlines() + assert lines[0] == "Downloading fr3_v2 assets ..." + assert lines[-1].startswith("Robot assets ready: 1 robots, 1 directories, 3 files") + + def test_pull_assets_all_covers_every_registered_robot( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, @@ -75,26 +96,34 @@ def test_pull_assets_all_covers_every_registered_robot( from unilab.assets.hub import ROBOT_ASSET_SPECS target = _populate(tmp_path / "dir", suffix=".stl", count=1) + superdex_target = _populate(tmp_path / "fr3_v2", suffix=".h5", count=1) calls: list[tuple[str, bool]] = [] + superdex_calls: list[str] = [] def fake_resolver(directory: str, *, marker: str, show_progress: bool) -> Path: calls.append((directory, show_progress)) return target + def fake_superdex_resolver(model_file: str) -> str: + superdex_calls.append(model_file) + return str(superdex_target / "fr3_v2.superdex_bot") + monkeypatch.setattr(pull_assets, "resolve_robot_asset_dir", fake_resolver) + monkeypatch.setattr(pull_assets, "resolve_superdex_robot_asset", fake_superdex_resolver) + robots = sorted(ROBOT_ASSET_SPECS) + sorted(pull_assets._superdex_bot_names()) assert pull_assets.main(["--robot", "all"]) == 0 assert calls == [ (directory, False) for robot in sorted(ROBOT_ASSET_SPECS) for directory, _marker, _pattern, _label in ROBOT_ASSET_SPECS[robot] ] + superdex_bots = pull_assets._superdex_bot_names() + assert superdex_calls == [superdex_bots[name] for name in sorted(superdex_bots)] output_lines = capsys.readouterr().out.strip().splitlines() - assert len(output_lines) == len(ROBOT_ASSET_SPECS) + 1 - assert output_lines[:-1] == [ - f"Downloading {robot} assets ..." for robot in sorted(ROBOT_ASSET_SPECS) - ] - assert output_lines[-1].startswith(f"Robot assets ready: {len(ROBOT_ASSET_SPECS)} robots") + assert len(output_lines) == len(robots) + 1 + assert output_lines[:-1] == [f"Downloading {robot} assets ..." for robot in robots] + assert output_lines[-1].startswith(f"Robot assets ready: {len(robots)} robots") def test_pull_assets_verbose_keeps_output_compact( diff --git a/tests/training/test_training_helpers.py b/tests/training/test_training_helpers.py index 219251d22..c0afecf8d 100644 --- a/tests/training/test_training_helpers.py +++ b/tests/training/test_training_helpers.py @@ -8,6 +8,9 @@ from hydra import compose, initialize_config_dir from hydra.core.global_hydra import GlobalHydra from omegaconf import OmegaConf + +pytest.importorskip("mujoco_uni") + from unisim.backend.base import RenderClosedError from unisim.backend.motrix.backend import MotrixBackend from unisim.backend.motrix.playback import run_motrix_playback diff --git a/uv.lock b/uv.lock index 6fc206041..d79f1dba6 100644 --- a/uv.lock +++ b/uv.lock @@ -681,6 +681,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d", size = 120019, upload-time = "2026-01-19T02:36:55.663Z" }, ] +[[package]] +name = "docker" +version = "7.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/88/7f/731ff914b0255d3d065f45fd4e626d4b8c95dbcbaada049f337a6ac16410/docker-7.2.0.tar.gz", hash = "sha256:cebb93773d334f778e023a7ee352a8d6e13ab1bd3b863a4d4a59dec897df43ac", size = 118731, upload-time = "2026-07-09T14:53:46.39Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/23/529140fe1aab80fc6992f93a706deec709140a6397439139a054e1515c45/docker-7.2.0-py3-none-any.whl", hash = "sha256:a3f45fdeb9165e2d25d9a1d02ddf3bc70fb572cf5ebbf9b58558c22caf29b71f", size = 148775, upload-time = "2026-07-09T14:53:45.224Z" }, +] + [[package]] name = "dracopy" version = "2.0.0" @@ -1296,6 +1309,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/fa/391e437a34e55095173dca5f24070d89cbc233ff85bf1c29c93248c6588d/imageio-2.37.3-py3-none-any.whl", hash = "sha256:46f5bb8522cd421c0f5ae104d8268f569d856b29eb1a13b92829d1970f32c9f0", size = 317646, upload-time = "2026-03-09T11:31:10.771Z" }, ] +[package.optional-dependencies] +ffmpeg = [ + { name = "imageio-ffmpeg" }, + { name = "psutil" }, +] + [[package]] name = "imageio-ffmpeg" version = "0.6.0" @@ -3355,6 +3374,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] +[[package]] +name = "polyscope" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/57/bf8bfc975ff6ab7547ae68db4f87ffb3fc7861acbe0fdd08cd4de9b66db1/polyscope-2.5.0.tar.gz", hash = "sha256:3a97e57297b231a9fc93a98c4f9eab852819d79f0807ce64071cdc9dabd53868", size = 14746772, upload-time = "2025-08-19T08:32:52.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/6e/f430ff90f08cfa4f01b730c3ad80e5304a91a61241d657ab6317d78d9f96/polyscope-2.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:211b80b35e50ed4e48cff6a31630ff1cc3961b38c7f79408fd4f29f1e70eed8b", size = 7815655, upload-time = "2025-08-19T08:29:21.862Z" }, + { url = "https://files.pythonhosted.org/packages/21/4d/4ddc9be541c37044087b612e43eaeb3ff630f317ae6c0f4de2a69b4ff7b3/polyscope-2.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0788ffe1bd8f2a5fc21eb2528634345ce02fb756d7b7c297513aa5e03294ce52", size = 10004583, upload-time = "2025-08-19T08:29:28.649Z" }, + { url = "https://files.pythonhosted.org/packages/6f/55/188740d8c1e55b02bf0e21c12775a7f374f293ff33044b7aef1d86ad9ea3/polyscope-2.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88302bfe110c64c8ae3a1433911aca29a9b881285c8b0d7ee333304fbdf05fce", size = 7814868, upload-time = "2025-08-19T08:29:44.024Z" }, + { url = "https://files.pythonhosted.org/packages/70/ab/9d3e22b1f1c128dd19f365f9c8a36cbf6e210cd45fe0a5b2dacc00962128/polyscope-2.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fe386475e8dff9072eb6a1ea191aa870236f2fb99b6bd77745b29092b6a539e0", size = 10010058, upload-time = "2025-08-19T08:29:50.24Z" }, + { url = "https://files.pythonhosted.org/packages/be/4e/82ea84c9e90125eba5c73e28c1caa01d03f304e06936759150a7a3565827/polyscope-2.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c093803adb7a74540e4f536812978d44acfdaf585238da8e118a7a5ecbad35e6", size = 7826546, upload-time = "2025-08-19T08:30:04.203Z" }, + { url = "https://files.pythonhosted.org/packages/90/ff/7bac1e8ce7e1d8bc7cacd70e62ad4361b3dcc10553dff313bc51ac82c0a8/polyscope-2.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a5c98845a7e938a6c08829daeeb733bee6c0ad9c95cbf461614dacdae2d31360", size = 10001021, upload-time = "2025-08-19T08:30:11.543Z" }, + { url = "https://files.pythonhosted.org/packages/aa/33/d9df9f22e65fcad83e7c340c2d06ffe34934f606d0c56ae04f9de962228d/polyscope-2.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccc1d04e3d0c6b071bc1d1acbad4209dbdfd7f9350e229c07e485d1f668947d0", size = 7827660, upload-time = "2025-08-19T08:30:26.425Z" }, + { url = "https://files.pythonhosted.org/packages/2c/02/8399e1ede1daea62e3ea3e25e39b615f5c0eb5ac233e534f34db18c9a70e/polyscope-2.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ea87f39c6c8809b9d92c743fdba00127811107d495f97365060422f04ed84d2", size = 10001404, upload-time = "2025-08-19T08:30:34.221Z" }, + { url = "https://files.pythonhosted.org/packages/c0/27/8304649d0ee809e2f0cb12dbdf749bf4e50ca9eabe5eeae688726840af8d/polyscope-2.5.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d65b41febd5c6b8df8e376937a853c79410ed4163edb26b83361042cc47b4f50", size = 7826880, upload-time = "2025-08-19T08:31:58.188Z" }, + { url = "https://files.pythonhosted.org/packages/66/af/c664d6233ba125073b49458837836e7c8c978ba417390b21c83623f1c8f1/polyscope-2.5.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d3921c03a2826b0655142991e2d3454385a19462f893ce032b8a0319d0d7329", size = 7828694, upload-time = "2025-08-19T08:32:10.995Z" }, +] + [[package]] name = "prettytable" version = "3.18.0" @@ -3455,6 +3495,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335, upload-time = "2022-10-25T20:38:27.636Z" }, ] +[[package]] +name = "pyarrow" +version = "25.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/e3/27f57f80141379d60defe6703eb50a707325706f07fedfd1312c7a751995/pyarrow-25.0.1.tar.gz", hash = "sha256:9150a83248bfed9813ea3c3af74c3856c1984d444aa28e58bf7733b9750ddf6a", size = 1201653, upload-time = "2026-08-10T12:40:53.904Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/5c/f8fc0eb2de03464a557d5a4d0c15e972d73362414696618833b771f7eddd/pyarrow-25.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a4d6d5e9a3d1879a97c08ded0c797579b7965eafd0f0c26c30b45ccc06db939b", size = 50066460, upload-time = "2026-08-10T12:36:53.702Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3c/f89d1bd76d5f3284c2a44d7d7ebbd8204535e5ae2b41f4077069b4ff2ec6/pyarrow-25.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cab40b1edfef0262e0e5251aa2c58d75630f24d06dd7794480243acc001a1d7d", size = 53107240, upload-time = "2026-08-10T12:37:07.205Z" }, + { url = "https://files.pythonhosted.org/packages/c8/6e/d3fafc41f378b2c65be43b827798c0fae42049a641c8526633ed3eb573e2/pyarrow-25.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:25f8720bf6387d5dc2ebd2622112de630760419e4b66134405dd24110d15f37e", size = 50065507, upload-time = "2026-08-10T12:37:40.565Z" }, + { url = "https://files.pythonhosted.org/packages/d3/0b/1ecb936ac6409e90a34d58eea1c7cec09a9ae6d2141b9e49ad01a2b1ea47/pyarrow-25.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aa0559502e1cd6254d6814614085dd9c5a3dd0419362978a936a3f68a9e5c3df", size = 53128198, upload-time = "2026-08-10T12:37:52.531Z" }, + { url = "https://files.pythonhosted.org/packages/60/c9/711ca85d79f1ec98f29a5eae2b051e25b4ecec5de3e3c0e2d5c5dcb15664/pyarrow-25.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:5389cdf79447ed1515c9e31620e6e1e2302249564d603f2ad727d4f6d313e4c3", size = 50102437, upload-time = "2026-08-10T12:38:22.487Z" }, + { url = "https://files.pythonhosted.org/packages/e8/83/4e5ae02a9341571b18a6fca380ac7a58ce6ddae7ab3c060208c0a1e79f02/pyarrow-25.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6109c94d8b9f3b17a041daca16cacb2f651ad8f1ef70a4232c2c0f37a23da2a8", size = 53144206, upload-time = "2026-08-10T12:38:34.862Z" }, + { url = "https://files.pythonhosted.org/packages/98/d6/33a411115b61dbfc16ad6ad73e71730f6fea654ee3667673bc53ab0e2fe7/pyarrow-25.0.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0befcf816e45a1af33ac775a9970b749e4868a230c7372f0ae5e932bee27039f", size = 50104452, upload-time = "2026-08-10T12:39:04.579Z" }, + { url = "https://files.pythonhosted.org/packages/98/9e/a112df5cfd5a68cb1d9fc31cfe38c28d5aec9f10865ce37ecef2e4450873/pyarrow-25.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6943e2fe7954d29d84de45d29d34c8dc36ce96570e67d89aa9976e650a4a9138", size = 53144784, upload-time = "2026-08-10T12:39:20.503Z" }, +] + [[package]] name = "pybind11" version = "3.0.4" @@ -3727,6 +3783,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, ] +[[package]] +name = "pyre-extensions" +version = "0.0.32" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, + { name = "typing-inspect" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/53/5bc2532536e921c48366ad1047c1344ccef6afa5e84053f0f6e20a453767/pyre_extensions-0.0.32.tar.gz", hash = "sha256:5396715f14ea56c4d5fd0a88c57ca7e44faa468f905909edd7de4ad90ed85e55", size = 10852, upload-time = "2024-11-22T19:26:44.152Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/7a/9812cb8be9828ab688203c5ac5f743c60652887f0c00995a6f6f19f912bd/pyre_extensions-0.0.32-py3-none-any.whl", hash = "sha256:a63ba6883ab02f4b1a9f372ed4eb4a2f4c6f3d74879aa2725186fdfcfe3e5c68", size = 12766, upload-time = "2024-11-22T19:26:42.465Z" }, +] + [[package]] name = "pyreadline3" version = "3.5.6" @@ -3943,6 +4012,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, ] +[[package]] +name = "rerun-sdk" +version = "0.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } }, + { name = "pillow" }, + { name = "psutil" }, + { name = "pyarrow" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/ba/d70997b43e6db4f58c4326c29c6a6a384ddc6c2fe125f231c885ad9b3b1f/rerun_sdk-0.33.0-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:53d95609f8b330026bcd041bf6d11b46ee1c18b6fbde155135f291fe86328eeb", size = 139552018, upload-time = "2026-05-29T09:43:06.275Z" }, +] + [[package]] name = "rich" version = "14.3.3" @@ -4478,6 +4563,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, ] +[[package]] +name = "superdex-physics-uni" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "imageio", extra = ["ffmpeg"] }, + { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } }, + { name = "pillow" }, + { name = "polyscope" }, + { name = "pycollada" }, + { name = "pyre-extensions" }, + { name = "rerun-sdk" }, + { name = "scikit-image", version = "0.26.0", source = { registry = "https://pypi.org/simple" } }, + { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" } }, + { name = "tabulate" }, + { name = "trimesh" }, + { name = "typing-extensions" }, + { name = "unrealcv" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/1f/deaaf137a3bd4e233c58702005d65a71abec953d22be00605e449859b094/superdex_physics_uni-1.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:29fc2d2a063244c0bb90a181c0dc418db25ded3db2b75262cb921c294da4d832", size = 11930457, upload-time = "2026-09-09T13:04:13.814Z" }, + { url = "https://files.pythonhosted.org/packages/66/53/e2fc09c2c3d45a853f811e3fc216cf52fdb6f4a82dbdda688994b7c54451/superdex_physics_uni-1.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e3832675306f5a34580d46a86618db44b9e45bb26b0a2ec178b2aa6c48e5e4d4", size = 11930880, upload-time = "2026-09-09T14:46:45.279Z" }, +] + +[[package]] +name = "superdex-robotics-uni" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "superdex-physics-uni" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/00/d670077fcbf7324bf0137e55dee51255084379aeb48494fe2b4350879138/superdex_robotics_uni-1.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb31135b39451862af8213feb2053c2482337e7f58ae36544093e723c9e5bfc", size = 1043255, upload-time = "2026-09-09T13:04:17.66Z" }, + { url = "https://files.pythonhosted.org/packages/77/3f/a854c6d94019279e68c4259348ac3ab46bd9f975bf30d718df6f4254af87/superdex_robotics_uni-1.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f61140e76c8809a22b58787dbbe5710ad074e44727b7dfa8b29009d335d7251c", size = 1043319, upload-time = "2026-09-09T14:46:47.57Z" }, +] + [[package]] name = "svg-path" version = "7.0" @@ -4499,6 +4620,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, ] +[[package]] +name = "tabulate" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, +] + [[package]] name = "tenacity" version = "9.1.4" @@ -5061,6 +5191,9 @@ newton = [ { name = "trimesh" }, { name = "warp-lang" }, ] +superdex = [ + { name = "unisim-core", extra = ["superdex"], marker = "python_full_version >= '3.12' and platform_machine == 'x86_64' and sys_platform == 'linux'" }, +] viser = [ { name = "trimesh" }, { name = "viser" }, @@ -5118,15 +5251,16 @@ requires-dist = [ { name = "trimesh", marker = "extra == 'newton'", specifier = ">=3.21.7" }, { name = "trimesh", marker = "extra == 'viser'", specifier = ">=3.21.7" }, { name = "typing-extensions" }, - { name = "unilab-rl", specifier = "==1.1.3" }, - { name = "unisim-core", specifier = ">=1.1.5" }, + { name = "unilab-rl", specifier = "==1.2.0" }, + { name = "unisim-core", specifier = ">=1.2.0" }, + { name = "unisim-core", extras = ["superdex"], marker = "python_full_version >= '3.12' and platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'superdex'" }, { name = "viser", marker = "extra == 'viser'", specifier = ">=1.0.26" }, { name = "wandb" }, { name = "warp-lang", marker = "extra == 'mjwarp'", specifier = "==1.16.0" }, { name = "warp-lang", marker = "extra == 'newton'", specifier = "==1.16.0" }, { name = "wheel", marker = "extra == 'mujoco'" }, ] -provides-extras = ["drake", "mujoco", "mjwarp", "newton", "motrix", "genesis", "viser"] +provides-extras = ["drake", "mujoco", "mjwarp", "newton", "motrix", "genesis", "viser", "superdex"] [package.metadata.requires-dev] dev = [ @@ -5139,7 +5273,7 @@ dev = [ [[package]] name = "unilab-rl" -version = "1.1.3" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "hydra-core" }, @@ -5156,20 +5290,43 @@ dependencies = [ { name = "torch", version = "2.9.0+cu130", source = { registry = "https://download-r2.pytorch.org/whl/cu130" }, marker = "platform_machine == 'aarch64' and sys_platform == 'linux'" }, { name = "wandb" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/04/7d9158f2e51662da3a694d8a23965918ba42ef40ea06406a1f222e51d37a/unilab_rl-1.1.3.tar.gz", hash = "sha256:2b39a884830f6740b1bdad59a283f47fdd9213149dc75997b11532b96a616a78", size = 148298, upload-time = "2026-09-09T13:52:35.765Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/9d/7a646bc044cadb48cbd1d0c58832faf59e037a45f22432cff2a7ad5a7b01/unilab_rl-1.2.0.tar.gz", hash = "sha256:bb8b1c713b961ea4b24ea72c39d443e057531e71882fa058502af947b98768da", size = 148289, upload-time = "2026-09-10T05:20:52.549Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/89/1c17773efa67e952bd93ccc34d2f1e78a745e6e290918305b84b1751c9e6/unilab_rl-1.1.3-py3-none-any.whl", hash = "sha256:7489db2042860bc2cc72c3184a9d2a8f9eaea0c79e06da702b87b4295eb3bdff", size = 183373, upload-time = "2026-09-09T13:52:34.639Z" }, + { url = "https://files.pythonhosted.org/packages/58/67/0ea1fb5f0c9a7e8604b0415b018deb3286024191a84d357f1b3221d2a41d/unilab_rl-1.2.0-py3-none-any.whl", hash = "sha256:617317dcca581d1af2daec36d50de7214067dd34f5d85a4f02d7cd38de1df611", size = 183372, upload-time = "2026-09-10T05:20:51.254Z" }, ] [[package]] name = "unisim-core" -version = "1.1.5" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/11/53/e69401c7363edfdc7e491e32a19074309ad5a6d025faf3c480fcc505a0f3/unisim_core-1.1.5.tar.gz", hash = "sha256:cdde0ffcdd222f2b9ceb40174bf8a7778c160748f2fff3b1c97b004b2f503a6a", size = 252926, upload-time = "2026-09-09T16:19:58.065Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/b7/2cf8626884236d9e14256fa4330b9e04a8a41598867ced1ac4030f827989/unisim_core-1.2.0.tar.gz", hash = "sha256:fccd67edbde98eeb16d2e6f9f5f8ce608dd2790266a673788897cbd9a42fa4ce", size = 253069, upload-time = "2026-09-10T05:19:05.388Z" } + +[package.optional-dependencies] +superdex = [ + { name = "mujoco" }, + { name = "superdex-physics-uni" }, + { name = "superdex-robotics-uni" }, +] + +[[package]] +name = "unrealcv" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docker" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } }, + { name = "opencv-python" }, + { name = "pillow" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/31/cb/f52971b2750e1df4e810a4980ce00ba81b3bd51516939cf52e4776f3e1eb/unrealcv-1.3.2.tar.gz", hash = "sha256:fb6eacfd0bd6a19a14c8695770960ce9ddc76a8dd7aa696b557601aeeb345ad2", size = 49617, upload-time = "2026-09-03T08:58:47.987Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/b4/6b0b4b77aeae30522c19bbabf1a9eda36cceec01fda4e749032ac88d4310/unrealcv-1.3.2-py3-none-any.whl", hash = "sha256:f41c8942d2ebfd6c2e619632792f267ff937ed823a6946fbb71f322d4a78d637", size = 52178, upload-time = "2026-09-03T08:58:46.518Z" }, +] [[package]] name = "urllib3" diff --git a/uv.rocm.lock b/uv.rocm.lock index 25d50b1ea..67c19d4c7 100644 --- a/uv.rocm.lock +++ b/uv.rocm.lock @@ -3,12 +3,12 @@ revision = 3 requires-python = ">=3.10, <3.14" resolution-markers = [ "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version >= '3.13' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine != 's390x' and sys_platform != 'linux')", - "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version >= '3.13' and platform_machine == 's390x'", + "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.12.*' and platform_machine == 's390x'", + "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version == '3.11.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.11.*' and platform_machine == 's390x'", "python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'linux'", @@ -307,12 +307,12 @@ version = "1.3.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version >= '3.13' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine != 's390x' and sys_platform != 'linux')", - "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version >= '3.13' and platform_machine == 's390x'", + "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.12.*' and platform_machine == 's390x'", + "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version == '3.11.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.11.*' and platform_machine == 's390x'", ] @@ -611,12 +611,12 @@ version = "1.14.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version >= '3.13' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine != 's390x' and sys_platform != 'linux')", - "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version >= '3.13' and platform_machine == 's390x'", + "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.12.*' and platform_machine == 's390x'", + "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version == '3.11.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.11.*' and platform_machine == 's390x'", ] @@ -1087,10 +1087,10 @@ version = "9.12.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version >= '3.13' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine != 's390x' and sys_platform != 'linux')", - "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version >= '3.13' and platform_machine == 's390x'", + "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.12.*' and platform_machine == 's390x'", ] dependencies = [ @@ -1928,12 +1928,12 @@ version = "3.6.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version >= '3.13' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine != 's390x' and sys_platform != 'linux')", - "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version >= '3.13' and platform_machine == 's390x'", + "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.12.*' and platform_machine == 's390x'", + "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version == '3.11.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.11.*' and platform_machine == 's390x'", ] @@ -2046,12 +2046,12 @@ version = "2.4.4" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version >= '3.13' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine != 's390x' and sys_platform != 'linux')", - "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version >= '3.13' and platform_machine == 's390x'", + "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.12.*' and platform_machine == 's390x'", + "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version == '3.11.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.11.*' and platform_machine == 's390x'", ] @@ -2366,12 +2366,12 @@ version = "1.24.4" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version >= '3.13' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine != 's390x' and sys_platform != 'linux')", - "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version >= '3.13' and platform_machine == 's390x'", + "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.12.*' and platform_machine == 's390x'", + "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version == '3.11.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.11.*' and platform_machine == 's390x'", ] @@ -3206,12 +3206,12 @@ version = "1.17.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", - "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version >= '3.13' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine != 's390x' and sys_platform != 'linux')", - "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version >= '3.13' and platform_machine == 's390x'", + "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.12.*' and platform_machine == 's390x'", + "python_full_version == '3.11.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", "(python_full_version == '3.11.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.11.*' and platform_machine == 's390x'", ] @@ -3509,8 +3509,8 @@ version = "2.11.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "(python_full_version >= '3.13' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine != 's390x' and sys_platform != 'linux')", - "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version >= '3.13' and platform_machine == 's390x'", + "(python_full_version == '3.12.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.12.*' and platform_machine == 's390x'", "(python_full_version == '3.11.*' and platform_machine != 's390x' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'linux')", "python_full_version == '3.11.*' and platform_machine == 's390x'", @@ -3801,8 +3801,8 @@ requires-dist = [ { name = "trimesh", marker = "extra == 'viser'", specifier = ">=3.21.7" }, { name = "triton-rocm", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'", specifier = "==3.6.0", index = "https://download.pytorch.org/whl/rocm7.2" }, { name = "typing-extensions" }, - { name = "unilab-rl", specifier = "==1.1.3" }, - { name = "unisim-core", specifier = ">=1.1.5" }, + { name = "unilab-rl", specifier = "==1.2.0" }, + { name = "unisim-core", specifier = ">=1.2.0" }, { name = "viser", marker = "extra == 'viser'", specifier = ">=1.0.26" }, { name = "wandb" }, { name = "wheel", marker = "extra == 'mujoco'" }, @@ -3820,7 +3820,7 @@ dev = [ [[package]] name = "unilab-rl" -version = "1.1.3" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "hydra-core" }, @@ -3836,20 +3836,20 @@ dependencies = [ { name = "torch", version = "2.11.0+rocm7.2", source = { registry = "https://download.pytorch.org/whl/rocm7.2" }, marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "wandb" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/04/7d9158f2e51662da3a694d8a23965918ba42ef40ea06406a1f222e51d37a/unilab_rl-1.1.3.tar.gz", hash = "sha256:2b39a884830f6740b1bdad59a283f47fdd9213149dc75997b11532b96a616a78", size = 148298, upload-time = "2026-09-09T13:52:35.765Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/9d/7a646bc044cadb48cbd1d0c58832faf59e037a45f22432cff2a7ad5a7b01/unilab_rl-1.2.0.tar.gz", hash = "sha256:bb8b1c713b961ea4b24ea72c39d443e057531e71882fa058502af947b98768da", size = 148289, upload-time = "2026-09-10T05:20:52.549Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/89/1c17773efa67e952bd93ccc34d2f1e78a745e6e290918305b84b1751c9e6/unilab_rl-1.1.3-py3-none-any.whl", hash = "sha256:7489db2042860bc2cc72c3184a9d2a8f9eaea0c79e06da702b87b4295eb3bdff", size = 183373, upload-time = "2026-09-09T13:52:34.639Z" }, + { url = "https://files.pythonhosted.org/packages/58/67/0ea1fb5f0c9a7e8604b0415b018deb3286024191a84d357f1b3221d2a41d/unilab_rl-1.2.0-py3-none-any.whl", hash = "sha256:617317dcca581d1af2daec36d50de7214067dd34f5d85a4f02d7cd38de1df611", size = 183372, upload-time = "2026-09-10T05:20:51.254Z" }, ] [[package]] name = "unisim-core" -version = "1.1.5" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/11/53/e69401c7363edfdc7e491e32a19074309ad5a6d025faf3c480fcc505a0f3/unisim_core-1.1.5.tar.gz", hash = "sha256:cdde0ffcdd222f2b9ceb40174bf8a7778c160748f2fff3b1c97b004b2f503a6a", size = 252926, upload-time = "2026-09-09T16:19:58.065Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/b7/2cf8626884236d9e14256fa4330b9e04a8a41598867ced1ac4030f827989/unisim_core-1.2.0.tar.gz", hash = "sha256:fccd67edbde98eeb16d2e6f9f5f8ce608dd2790266a673788897cbd9a42fa4ce", size = 253069, upload-time = "2026-09-10T05:19:05.388Z" } [[package]] name = "urllib3"