Compare commits

..

2 Commits

14 changed files with 251 additions and 475 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ permissions:
contents: read contents: read
env: env:
UV_VERSION: "0.8.0" UV_VERSION: "0.11.30"
PYTHON_VERSION: "3.12" PYTHON_VERSION: "3.12"
# Cancel in-flight runs for the same branch/PR. # Cancel in-flight runs for the same branch/PR.
+1 -1
View File
@@ -27,7 +27,7 @@ on:
# Sets up the environment variables # Sets up the environment variables
env: env:
UV_VERSION: "0.8.0" UV_VERSION: "0.11.30"
PYTHON_VERSION: "3.12" PYTHON_VERSION: "3.12"
DOCKER_IMAGE_NAME_CPU: huggingface/lerobot-cpu:latest DOCKER_IMAGE_NAME_CPU: huggingface/lerobot-cpu:latest
DOCKER_IMAGE_NAME_GPU: huggingface/lerobot-gpu:latest DOCKER_IMAGE_NAME_GPU: huggingface/lerobot-gpu:latest
+1 -1
View File
@@ -48,7 +48,7 @@ permissions:
# Sets up the environment variables # Sets up the environment variables
env: env:
UV_VERSION: "0.8.0" UV_VERSION: "0.11.30"
PYTHON_VERSION: "3.12" PYTHON_VERSION: "3.12"
# Ensures that only the latest commit for a PR or branch is built, canceling older runs. # Ensures that only the latest commit for a PR or branch is built, canceling older runs.
+1 -1
View File
@@ -37,7 +37,7 @@ permissions:
# Sets up the environment variables # Sets up the environment variables
env: env:
UV_VERSION: "0.8.0" UV_VERSION: "0.11.30"
PYTHON_VERSION: "3.12" PYTHON_VERSION: "3.12"
DOCKER_IMAGE_NAME: huggingface/lerobot-gpu DOCKER_IMAGE_NAME: huggingface/lerobot-gpu
+1 -1
View File
@@ -27,7 +27,7 @@ on:
# Sets up the environment variables # Sets up the environment variables
env: env:
UV_VERSION: "0.8.0" UV_VERSION: "0.11.30"
PYTHON_VERSION: "3.12" PYTHON_VERSION: "3.12"
DOCKER_IMAGE_NAME: huggingface/lerobot-gpu:latest-deps DOCKER_IMAGE_NAME: huggingface/lerobot-gpu:latest-deps
+1 -1
View File
@@ -21,7 +21,7 @@ on:
# Sets up the environment variables # Sets up the environment variables
env: env:
UV_VERSION: "0.8.0" UV_VERSION: "0.11.30"
PYTHON_VERSION: "3.12" PYTHON_VERSION: "3.12"
jobs: jobs:
-75
View File
@@ -1,75 +0,0 @@
# OpenArm — Episode Replay in Simulation
Replay a recorded bimanual-[OpenArm](https://openarm.dev) episode into an mp4 by driving the
official OpenArm MuJoCo model directly from a LeRobot dataset's recorded joint states. This is
a visual sanity check for recorded/commanded trajectories and for the end-effector kinematics
exposed by `OpenArmFollower.make_kinematics()` (see the [OpenArm docs](../../docs/source/openarm.mdx)).
## Model provenance
Everything is pulled from Enactic's official, Apache-2.0 OpenArm repositories — nothing is
vendored into LeRobot:
| Asset | Source | License |
| ------------------------------------ | ------------------------------------------------------------------------------- | ---------- |
| MuJoCo MJCF (used here) | [`enactic/openarm_mujoco`](https://github.com/enactic/openarm_mujoco) | Apache-2.0 |
| URDF / xacro (for `RobotKinematics`) | [`enactic/openarm_description`](https://github.com/enactic/openarm_description) | Apache-2.0 |
Use the **v1** MuJoCo revision (`v1/openarm_bimanual.xml`). v2 is a different wrist hardware
revision (DM3507) and will look sign-flipped when replaying v1 recordings.
## Setup
```bash
# LeRobot in your env (see https://huggingface.co/docs/lerobot/installation)
# Plus the sim/replay deps:
pip install mujoco av pandas
# Get the OpenArm MuJoCo model (either works):
pip install openarm-mujoco # installs models under <prefix>/share/openarm_mujoco/
# or
git clone https://github.com/enactic/openarm_mujoco.git # then pass --mjcf .../v1/openarm_bimanual.xml
```
The script auto-locates the model in this order: `--mjcf` arg → `$OPENARM_MJCF`
`<sys.prefix>/share/openarm_mujoco/v1/openarm_bimanual.xml`.
## Dataset layout
`observation.state` must be the 16-D bimanual vector (degrees):
```
right_joint_1..7, right_gripper, left_joint_1..7, left_gripper
```
Only the 14 arm joints affect the rendered pose; the two gripper scalars drive the fingers.
## Run
Headless rendering needs `MUJOCO_GL=egl`, and MuJoCo's GL libs on `LD_LIBRARY_PATH`
(in conda: `$CONDA_PREFIX/lib`).
```bash
# Replay episode 1 of a local LeRobot v3.0 dataset
LD_LIBRARY_PATH=$CONDA_PREFIX/lib MUJOCO_GL=egl \
python -m examples.openarm.render_episode \
--dataset data/folding_src_meta \
--episode 1 \
--out openarm_ep1.mp4
# No dataset handy? Smoke-test with a synthetic wave:
LD_LIBRARY_PATH=$CONDA_PREFIX/lib MUJOCO_GL=egl \
python -m examples.openarm.render_episode --demo --out openarm_demo.mp4
```
Useful flags: `--fps` (default 30), `--width` / `--height` (default 960×720), `--mjcf` to point
at an explicit model file.
## Troubleshooting
| Symptom | Fix |
| ------------------------------------- | ---------------------------------------------------------------------- |
| `Could not find the OpenArm v1 MJCF` | Pass `--mjcf`, set `$OPENARM_MJCF`, or install/clone `openarm_mujoco`. |
| `libEGL`/`GLEW` / blank window errors | Ensure `MUJOCO_GL=egl` and `LD_LIBRARY_PATH=$CONDA_PREFIX/lib`. |
| Wrists look mirrored / flipped | You are on the v2 model; switch to **v1**. |
| `KeyError: 'observation.state'` | Dataset isn't in the expected 16-D bimanual layout. |
-217
View File
@@ -1,217 +0,0 @@
#!/usr/bin/env python
# Copyright 2025 The HuggingFace Inc. team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Replay a recorded bimanual-OpenArm episode into an mp4, in simulation.
This drives the official OpenArm MuJoCo model (``enactic/openarm_mujoco``, v1) directly
from a LeRobot dataset's recorded ``observation.state`` and renders a headless video. It is
a visual sanity check that a recorded/commanded joint trajectory is what you think it is --
the same forward-kinematics path used to expose end-effector poses (see the OpenArm
end-effector kinematics helper ``OpenArmFollower.make_kinematics``).
The ``observation.state`` is expected in the 16-D bimanual layout (degrees):
right_joint_1..7, right_gripper, left_joint_1..7, left_gripper
Model (Apache-2.0): https://github.com/enactic/openarm_mujoco (use the **v1** revision;
v2 is a different wrist hardware revision and will look sign-flipped on v1 recordings).
Examples:
# replay episode 1 of a local LeRobot v3.0 dataset
LD_LIBRARY_PATH=$CONDA_PREFIX/lib MUJOCO_GL=egl python -m examples.openarm.render_episode \
--dataset data/folding_src_meta --episode 1 --out openarm_ep1.mp4
# smoke test with a synthetic wave (no dataset / model joints only)
LD_LIBRARY_PATH=$CONDA_PREFIX/lib MUJOCO_GL=egl python -m examples.openarm.render_episode \
--demo --out openarm_demo.mp4
"""
from __future__ import annotations
import argparse
import os
import sys
from pathlib import Path
os.environ.setdefault("MUJOCO_GL", "egl") # headless GPU rendering
import numpy as np
# Policy/dataset state layout: 16-D, degrees.
POLICY_ORDER = [
*(f"right_joint_{i}" for i in range(1, 8)),
"right_gripper",
*(f"left_joint_{i}" for i in range(1, 8)),
"left_gripper",
]
# MuJoCo joint name for each of the 14 arm entries (grippers handled separately).
ARM_MAP = {
**{f"right_joint_{i}": f"openarm_right_joint{i}" for i in range(1, 8)},
**{f"left_joint_{i}": f"openarm_left_joint{i}" for i in range(1, 8)},
}
RIGHT_GRIPPER_IDX, LEFT_GRIPPER_IDX = 7, 15
GRIP_FULL_DEG = 65.0 # follower gripper limit magnitude -> fully open
def locate_mjcf(explicit: str | None) -> str:
"""Resolve the OpenArm v1 bimanual MJCF path.
Priority: --mjcf arg, then $OPENARM_MJCF, then the file installed by the
``openarm_mujoco`` pip package under ``<prefix>/share/openarm_mujoco/v1``.
"""
if explicit:
return explicit
if os.environ.get("OPENARM_MJCF"):
return os.environ["OPENARM_MJCF"]
for prefix in (sys.prefix, os.environ.get("CONDA_PREFIX", "")):
if not prefix:
continue
cand = Path(prefix) / "share" / "openarm_mujoco" / "v1" / "openarm_bimanual.xml"
if cand.exists():
return str(cand)
raise SystemExit(
"Could not find the OpenArm v1 MJCF. Pass --mjcf /path/to/v1/openarm_bimanual.xml, "
"set $OPENARM_MJCF, or clone https://github.com/enactic/openarm_mujoco."
)
def load_state_from_dataset(root: str, ep: int) -> np.ndarray:
"""Read one episode's recorded observation.state (N, 16; degrees) from a LeRobot v3.0 root."""
import pandas as pd
root = Path(root)
ep_meta = pd.read_parquet(root / "meta" / "episodes" / "chunk-000" / "file-000.parquet")
row = ep_meta[ep_meta["episode_index"] == ep].iloc[0]
a, b = int(row["dataset_from_index"]), int(row["dataset_to_index"])
dchunk, dfile = int(row["data/chunk_index"]), int(row["data/file_index"])
df = pd.read_parquet(root / "data" / f"chunk-{dchunk:03d}" / f"file-{dfile:03d}.parquet")
df = df[(df["index"] >= a) & (df["index"] < b)].sort_values("frame_index")
return np.stack(df["observation.state"].to_numpy()).astype(np.float32)
def encode_mp4(frames: list[np.ndarray], path: str, fps: int) -> None:
import av
h, w = frames[0].shape[:2]
container = av.open(path, mode="w")
stream = container.add_stream("libx264", rate=fps)
stream.width, stream.height, stream.pix_fmt = w, h, "yuv420p"
for f in frames:
frame = av.VideoFrame.from_ndarray(np.ascontiguousarray(f), format="rgb24")
for pkt in stream.encode(frame):
container.mux(pkt)
for pkt in stream.encode():
container.mux(pkt)
container.close()
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawTextHelpFormatter)
ap.add_argument("--dataset", default=None, help="LeRobot v3.0 dataset root (meta/ + data/)")
ap.add_argument("--episode", type=int, default=0)
ap.add_argument("--demo", action="store_true", help="drive a synthetic wave (no dataset)")
ap.add_argument("--mjcf", default=None, help="path to v1/openarm_bimanual.xml (see locate_mjcf)")
ap.add_argument("--out", default="openarm_episode.mp4")
ap.add_argument("--fps", type=int, default=30)
ap.add_argument("--width", type=int, default=960)
ap.add_argument("--height", type=int, default=720)
args = ap.parse_args()
import mujoco
model = mujoco.MjModel.from_xml_path(locate_mjcf(args.mjcf))
model.vis.global_.offwidth = max(model.vis.global_.offwidth, args.width)
model.vis.global_.offheight = max(model.vis.global_.offheight, args.height)
data = mujoco.MjData(model)
qadr = {
pk: int(model.jnt_qposadr[mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, mj)])
for pk, mj in ARM_MAP.items()
}
def finger_adr(names):
out = []
for nm in names:
jid = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, nm)
out.append((int(model.jnt_qposadr[jid]), model.jnt_range[jid].copy(), int(model.jnt_type[jid])))
return out
right_fingers = finger_adr(["openarm_right_finger_joint1", "openarm_right_finger_joint2"])
left_fingers = finger_adr(["openarm_left_finger_joint1", "openarm_left_finger_joint2"])
hinge_type = int(mujoco.mjtJoint.mjJNT_HINGE)
def finger_target(gripper_deg, rng, jtype):
opening = min(1.0, abs(gripper_deg) / GRIP_FULL_DEG) # 0=closed .. 1=open
if jtype == hinge_type: # hinge in radians; sign encodes side via range direction
lo, hi = rng
mag = np.deg2rad(min(abs(gripper_deg), GRIP_FULL_DEG))
return np.clip(-mag if lo < 0 else mag, lo, hi)
return rng[0] + opening * (rng[1] - rng[0]) # slide (v1): lo=closed .. hi=open
if args.demo:
n_frames = 120
traj = np.zeros((n_frames, 16), np.float32)
wave = 40.0 * np.sin(np.linspace(0, 2 * np.pi, n_frames))
for i, pk in enumerate(POLICY_ORDER):
if pk in qadr:
traj[:, i] = wave * (0.5 + 0.5 * (i % 3))
elif args.dataset:
traj = load_state_from_dataset(args.dataset, args.episode)
else:
raise SystemExit("provide --dataset <root> (with --episode) or --demo")
n_frames = traj.shape[0]
print(f"driving {n_frames} frames")
# Auto-frame the arms (exclude pedestal/world) from body positions at the mid pose.
mid = n_frames // 2
for i, pk in enumerate(POLICY_ORDER):
if pk in qadr:
data.qpos[qadr[pk]] = np.deg2rad(traj[mid, i])
mujoco.mj_forward(model, data)
arm_pts = [
data.xpos[b].copy()
for b in range(model.nbody)
if (mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_BODY, b) or "").startswith("openarm")
and "base" not in (mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_BODY, b) or "")
]
arm_pts = np.array(arm_pts) if arm_pts else data.xpos[1:]
lo, hi = arm_pts.min(0), arm_pts.max(0)
cam = mujoco.MjvCamera()
mujoco.mjv_defaultCamera(cam)
cam.azimuth, cam.elevation = 150.0, -20.0
cam.distance = max(0.8, float(np.linalg.norm(hi - lo)) * 1.3)
cam.lookat[:] = (lo + hi) / 2.0
renderer = mujoco.Renderer(model, height=args.height, width=args.width)
frames = []
for t in range(n_frames):
for i, pk in enumerate(POLICY_ORDER):
if pk in qadr:
data.qpos[qadr[pk]] = np.deg2rad(traj[t, i])
for adr, rng, jt in right_fingers:
data.qpos[adr] = finger_target(float(traj[t, RIGHT_GRIPPER_IDX]), rng, jt)
for adr, rng, jt in left_fingers:
data.qpos[adr] = finger_target(float(traj[t, LEFT_GRIPPER_IDX]), rng, jt)
mujoco.mj_forward(model, data)
renderer.update_scene(data, camera=cam)
frames.append(renderer.render())
renderer.close()
encode_mp4(frames, args.out, args.fps)
print(f"wrote {args.out} ({n_frames} frames @ {args.fps} fps, {args.width}x{args.height})")
if __name__ == "__main__":
main()
+2 -2
View File
@@ -87,7 +87,7 @@ dependencies = [
# Build tools (required by opencv-python-headless on some platforms) # Build tools (required by opencv-python-headless on some platforms)
"cmake>=3.29.0.1,<4.2.0", "cmake>=3.29.0.1,<4.2.0",
"setuptools>=71.0.0,<81.0.0", "setuptools>=71.0.0,<82.0.0", # torch 2.11 requires setuptools<82; a higher cap makes the resolver downgrade torch
] ]
# Optional dependencies # Optional dependencies
@@ -261,7 +261,7 @@ annotations = [
# Development # Development
dev = ["pre-commit>=3.7.0,<5.0.0", "debugpy>=1.8.1,<1.9.0", "lerobot[grpcio-dep]", "grpcio-tools>=1.73.1,<2.0.0", "mypy>=1.19.1", "ruff>=0.14.1", "lerobot[notebook]"] dev = ["pre-commit>=3.7.0,<5.0.0", "debugpy>=1.8.1,<1.9.0", "lerobot[grpcio-dep]", "grpcio-tools>=1.73.1,<2.0.0", "mypy>=1.19.1", "ruff>=0.14.1", "lerobot[notebook]"]
notebook = ["jupyter>=1.0.0,<2.0.0", "ipykernel>=6.0.0,<7.0.0"] notebook = ["jupyter>=1.0.0,<2.0.0", "ipykernel>=6.0.0,<7.0.0"]
test = ["pytest>=8.1.0,<9.0.0", "pytest-timeout>=2.4.0,<3.0.0", "pytest-cov>=5.0.0,<8.0.0", "mock-serial>=0.0.1,<0.1.0 ; sys_platform != 'win32'"] test = ["pytest>=8.1.0,<10.0.0", "pytest-timeout>=2.4.0,<3.0.0", "pytest-cov>=5.0.0,<8.0.0", "mock-serial>=0.0.1,<0.1.0 ; sys_platform != 'win32'"]
video_benchmark = ["scikit-image>=0.23.2,<0.26.0", "pandas>=2.2.2,<2.4.0"] video_benchmark = ["scikit-image>=0.23.2,<0.26.0", "pandas>=2.2.2,<2.4.0"]
# Simulation # Simulation
+41
View File
@@ -22,6 +22,7 @@ from pathlib import Path
from typing import Any, NotRequired, TypedDict from typing import Any, NotRequired, TypedDict
import datasets import datasets
import numpy as np
import pandas as pd import pandas as pd
import tqdm import tqdm
@@ -303,6 +304,46 @@ def update_meta_data(
df["dataset_to_index"] = df["dataset_to_index"] + dst_meta.info.total_frames df["dataset_to_index"] = df["dataset_to_index"] + dst_meta.info.total_frames
df["episode_index"] = df["episode_index"] + dst_meta.info.total_episodes df["episode_index"] = df["episode_index"] + dst_meta.info.total_episodes
# Per-episode stats still describe the pre-merge values of the bookkeeping columns
# reindexed above. index/episode_index shift by a constant; task_index is relabeled,
# so recompute it from the episode's (stable) task strings via the unified tasks table.
shift_stat_keys = ("min", "max", "mean", "q01", "q10", "q50", "q90", "q99")
for name, offset in (
("episode_index", dst_meta.info.total_episodes),
("index", dst_meta.info.total_frames),
):
for stat in shift_stat_keys:
col = f"stats/{name}/{stat}"
if col in df.columns:
df[col] = df[col] + offset
if any(c.startswith("stats/task_index/") for c in df.columns):
quantiles = {"q01": 0.01, "q10": 0.10, "q50": 0.50, "q90": 0.90, "q99": 0.99}
ids_per_row = [
np.array([dst_meta.tasks.loc[t, "task_index"] for t in tasks], dtype=np.float64)
for tasks in df["tasks"]
]
def _task_stat(ids, stat):
if stat == "min":
return ids.min()
if stat == "max":
return ids.max()
if stat == "std":
return ids.std()
if stat in quantiles:
return np.quantile(ids, quantiles[stat])
return ids.mean()
for stat in ("min", "max", "mean", "std", *quantiles):
col = f"stats/task_index/{stat}"
if col in df.columns:
# np.full_like preserves each cell container and dtype so the parquet schema is unchanged.
df[col] = [
np.full_like(orig, _task_stat(ids, stat))
for orig, ids in zip(df[col], ids_per_row, strict=True)
]
return df return df
@@ -74,14 +74,6 @@ class OpenArmFollowerConfigBase:
# Set to a positive scalar for all motors, or a dict mapping motor names to limits # Set to a positive scalar for all motors, or a dict mapping motor names to limits
max_relative_target: float | dict[str, float] | None = None max_relative_target: float | dict[str, float] | None = None
# End-effector kinematics (optional). Point `urdf_path` at the OpenArm URDF and set
# `target_frame_name` to the end-effector link in that URDF to enable forward/inverse
# kinematics in Cartesian (EE) space -- via `lerobot.model.RobotKinematics` and the
# shared FK/IK processor steps. Left as None, the robot behaves exactly as before
# (joint space only). The URDF is user-supplied, so no large asset is vendored here.
urdf_path: str | None = None
target_frame_name: str | None = None
# Camera configurations # Camera configurations
cameras: dict[str, CameraConfig] = field(default_factory=dict) cameras: dict[str, CameraConfig] = field(default_factory=dict)
@@ -17,7 +17,7 @@
import logging import logging
import time import time
from functools import cached_property from functools import cached_property
from typing import TYPE_CHECKING, Any from typing import Any
from lerobot.cameras import make_cameras_from_configs from lerobot.cameras import make_cameras_from_configs
from lerobot.lerobot_types import RobotAction, RobotObservation from lerobot.lerobot_types import RobotAction, RobotObservation
@@ -25,9 +25,6 @@ from lerobot.motors import Motor, MotorCalibration, MotorNormMode
from lerobot.motors.damiao import DamiaoMotorsBus from lerobot.motors.damiao import DamiaoMotorsBus
from lerobot.utils.decorators import check_if_already_connected, check_if_not_connected from lerobot.utils.decorators import check_if_already_connected, check_if_not_connected
if TYPE_CHECKING:
from lerobot.model import RobotKinematics
from ..robot import Robot from ..robot import Robot
from ..utils import ensure_safe_goal_position from ..utils import ensure_safe_goal_position
from .config_openarm_follower import ( from .config_openarm_follower import (
@@ -123,33 +120,6 @@ class OpenArmFollower(Robot):
"""Action features.""" """Action features."""
return self._motors_ft return self._motors_ft
@property
def arm_motor_names(self) -> list[str]:
"""Arm joints forming the kinematic chain to the end-effector (excludes the gripper)."""
return [motor for motor in self.bus.motors if motor != "gripper"]
def make_kinematics(self) -> "RobotKinematics":
"""Build a solver for end-effector forward/inverse kinematics.
Requires ``config.urdf_path`` (path to the OpenArm URDF) and
``config.target_frame_name`` (the end-effector link in that URDF). Pair the returned
solver with the shared FK/IK processor steps in
``lerobot.robots.so_follower.robot_kinematic_processor`` to record or command the arm
in end-effector (Cartesian) space instead of raw joint angles.
"""
from lerobot.model import RobotKinematics
if self.config.urdf_path is None or self.config.target_frame_name is None:
raise ValueError(
"OpenArm end-effector kinematics require config.urdf_path and "
"config.target_frame_name (the OpenArm URDF and its end-effector link)."
)
return RobotKinematics(
urdf_path=self.config.urdf_path,
target_frame_name=self.config.target_frame_name,
joint_names=self.arm_motor_names,
)
@property @property
def is_connected(self) -> bool: def is_connected(self) -> bool:
"""Check if robot is connected.""" """Check if robot is connected."""
+65
View File
@@ -23,12 +23,15 @@ import pytest
pytest.importorskip("datasets", reason="datasets is required (install lerobot[dataset])") pytest.importorskip("datasets", reason="datasets is required (install lerobot[dataset])")
import datasets # noqa: E402 import datasets # noqa: E402
import numpy as np
import pandas as pd
import torch import torch
from lerobot.configs import VIDEO_ENCODER_INFO_KEYS from lerobot.configs import VIDEO_ENCODER_INFO_KEYS
from lerobot.datasets.aggregate import aggregate_datasets from lerobot.datasets.aggregate import aggregate_datasets
from lerobot.datasets.feature_utils import features_equal_for_merge from lerobot.datasets.feature_utils import features_equal_for_merge
from lerobot.datasets.lerobot_dataset import LeRobotDataset from lerobot.datasets.lerobot_dataset import LeRobotDataset
from lerobot.datasets.utils import EPISODES_DIR
from tests.fixtures.constants import ( from tests.fixtures.constants import (
DUMMY_CAMERA_FEATURES_WITH_DEPTH, DUMMY_CAMERA_FEATURES_WITH_DEPTH,
DUMMY_REPO_ID, DUMMY_REPO_ID,
@@ -857,3 +860,65 @@ def test_aggregate_already_merged_dataset(tmp_path, lerobot_dataset_factory):
# This would raise FileNotFoundError before the fix # This would raise FileNotFoundError before the fix
assert_dataset_iteration_works(ds_abc) assert_dataset_iteration_works(ds_abc)
def test_aggregate_updates_per_episode_stats(tmp_path):
"""episode_index/index/task_index per-episode stats follow the merge; all other stats are copied verbatim."""
features = {"observation.state": {"dtype": "float32", "shape": (2,), "names": None}}
def _make_dataset(suffix, tasks):
ds = LeRobotDataset.create(
f"{DUMMY_REPO_ID}_{suffix}", fps=10, features=features, root=tmp_path / suffix
)
for task in tasks:
for _ in range(4):
ds.add_frame({"observation.state": torch.randn(2), "task": task})
ds.save_episode()
ds.finalize()
return ds
# Overlapping tasks so relabeling collapses shared "b" and introduces new "c".
sources = [_make_dataset("s0", ["a", "b"]), _make_dataset("s1", ["b", "c"])]
aggr_root = tmp_path / "aggr"
aggregate_datasets(
repo_ids=[d.repo_id for d in sources],
roots=[d.root for d in sources],
aggr_repo_id=f"{DUMMY_REPO_ID}_aggr",
aggr_root=aggr_root,
)
with (
patch("lerobot.datasets.dataset_metadata.get_safe_version", return_value="v3.0"),
patch("lerobot.datasets.dataset_metadata.snapshot_download", return_value=str(aggr_root)),
):
aggr = LeRobotDataset(f"{DUMMY_REPO_ID}_aggr", root=aggr_root)
assert aggr.meta.total_tasks == 3 # "b" deduped, "c" added
def _load_stats(root):
# load_episodes drops stats/* columns, so read the episodes parquet shards directly.
shards = sorted((root / EPISODES_DIR).rglob("*.parquet"))
return pd.concat([pd.read_parquet(s) for s in shards]).set_index("episode_index")
merged = _load_stats(aggr_root)
src_rows, ep_off, fr_off = [], 0, 0
for d in sources:
src = _load_stats(d.root)
src_rows += [(src.loc[ep], ep_off, fr_off) for ep in range(d.num_episodes)]
ep_off, fr_off = ep_off + d.num_episodes, fr_off + d.num_frames
shift = {"min", "max", "mean", "q01", "q10", "q50", "q90", "q99"}
for ep, (src_row, e_off, f_off) in enumerate(src_rows):
row = merged.loc[ep]
new_id = float(aggr.meta.tasks.loc[row["tasks"][0], "task_index"])
for col in (c for c in merged.columns if c.startswith("stats/")):
feat, key = col[len("stats/") :].rsplit("/", 1)
got = np.asarray(row[col], dtype=np.float64).reshape(-1)
base = np.asarray(src_row[col], dtype=np.float64).reshape(-1)
if feat == "episode_index":
expected = base + e_off if key in shift else base
elif feat == "index":
expected = base + f_off if key in shift else base
elif feat == "task_index":
expected = base if key == "count" else np.full_like(base, 0.0 if key == "std" else new_id)
else:
expected = base
assert np.allclose(got, expected), f"ep{ep} {col}: {got} != {expected}"
Generated
+136 -136
View File
@@ -1,5 +1,5 @@
version = 1 version = 1
revision = 2 revision = 3
requires-python = ">=3.12" requires-python = ">=3.12"
resolution-markers = [ resolution-markers = [
"(python_full_version >= '3.15' and platform_machine == 'AMD64' and sys_platform == 'linux') or (python_full_version >= '3.15' and platform_machine == 'x86_64' and sys_platform == 'linux')", "(python_full_version >= '3.15' and platform_machine == 'AMD64' and sys_platform == 'linux') or (python_full_version >= '3.15' and platform_machine == 'x86_64' and sys_platform == 'linux')",
@@ -402,10 +402,10 @@ name = "bddl"
version = "1.0.1" version = "1.0.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "jupytext", marker = "sys_platform == 'linux'" }, { name = "jupytext" },
{ name = "networkx", marker = "sys_platform == 'linux'" }, { name = "networkx" },
{ name = "numpy", marker = "sys_platform == 'linux'" }, { name = "numpy" },
{ name = "pytest", marker = "sys_platform == 'linux'" }, { name = "pytest" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/5c/37/0211f82891a9f14efcfd2b2096f8d9e4351398ad637fdd1ee59cfc580b0e/bddl-1.0.1.tar.gz", hash = "sha256:1fa4e6e5050b93888ff6fd8455c39bfb29d3864ce06b4c37c0f781f513a2ae26", size = 164809, upload-time = "2022-03-08T01:48:23.564Z" } sdist = { url = "https://files.pythonhosted.org/packages/5c/37/0211f82891a9f14efcfd2b2096f8d9e4351398ad637fdd1ee59cfc580b0e/bddl-1.0.1.tar.gz", hash = "sha256:1fa4e6e5050b93888ff6fd8455c39bfb29d3864ce06b4c37c0f781f513a2ae26", size = 164809, upload-time = "2022-03-08T01:48:23.564Z" }
@@ -1010,7 +1010,7 @@ name = "cuda-bindings"
version = "12.9.7" version = "12.9.7"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "cuda-pathfinder", marker = "sys_platform == 'linux'" }, { name = "cuda-pathfinder" },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/32/45/557d4ed1fa54f0c7db8aee083229f624990d69f7d00f55477eed5c7e169a/cuda_bindings-12.9.7-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0666d3c082ef8f4b2d670950589373550e9f3bf564d635dd883f24a0b40402ff", size = 7071026, upload-time = "2026-05-27T18:44:13.356Z" }, { url = "https://files.pythonhosted.org/packages/32/45/557d4ed1fa54f0c7db8aee083229f624990d69f7d00f55477eed5c7e169a/cuda_bindings-12.9.7-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0666d3c082ef8f4b2d670950589373550e9f3bf564d635dd883f24a0b40402ff", size = 7071026, upload-time = "2026-05-27T18:44:13.356Z" },
@@ -1043,37 +1043,37 @@ wheels = [
[package.optional-dependencies] [package.optional-dependencies]
cublas = [ cublas = [
{ name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cublas-cu12" },
] ]
cudart = [ cudart = [
{ name = "nvidia-cuda-runtime-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cuda-runtime-cu12" },
] ]
cufft = [ cufft = [
{ name = "nvidia-cufft-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cufft-cu12" },
] ]
cufile = [ cufile = [
{ name = "nvidia-cufile-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cufile-cu12" },
] ]
cupti = [ cupti = [
{ name = "nvidia-cuda-cupti-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cuda-cupti-cu12" },
] ]
curand = [ curand = [
{ name = "nvidia-curand-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-curand-cu12" },
] ]
cusolver = [ cusolver = [
{ name = "nvidia-cusolver-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cusolver-cu12" },
] ]
cusparse = [ cusparse = [
{ name = "nvidia-cusparse-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cusparse-cu12" },
] ]
nvjitlink = [ nvjitlink = [
{ name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-nvjitlink-cu12" },
] ]
nvrtc = [ nvrtc = [
{ name = "nvidia-cuda-nvrtc-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cuda-nvrtc-cu12" },
] ]
nvtx = [ nvtx = [
{ name = "nvidia-nvtx-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-nvtx-cu12" },
] ]
[[package]] [[package]]
@@ -1145,7 +1145,7 @@ name = "decord"
version = "0.6.0" version = "0.6.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "numpy", marker = "(platform_machine != 'arm64' and sys_platform == 'darwin') or (platform_machine == 'AMD64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "numpy" },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/11/79/936af42edf90a7bd4e41a6cac89c913d4b47fa48a26b042d5129a9242ee3/decord-0.6.0-py3-none-manylinux2010_x86_64.whl", hash = "sha256:51997f20be8958e23b7c4061ba45d0efcd86bffd5fe81c695d0befee0d442976", size = 13602299, upload-time = "2021-06-14T21:30:55.486Z" }, { url = "https://files.pythonhosted.org/packages/11/79/936af42edf90a7bd4e41a6cac89c913d4b47fa48a26b042d5129a9242ee3/decord-0.6.0-py3-none-manylinux2010_x86_64.whl", hash = "sha256:51997f20be8958e23b7c4061ba45d0efcd86bffd5fe81c695d0befee0d442976", size = 13602299, upload-time = "2021-06-14T21:30:55.486Z" },
@@ -1283,10 +1283,10 @@ resolution-markers = [
"python_full_version == '3.14.*' and sys_platform == 'win32'", "python_full_version == '3.14.*' and sys_platform == 'win32'",
] ]
dependencies = [ dependencies = [
{ name = "absl-py", marker = "python_full_version >= '3.14'" }, { name = "absl-py" },
{ name = "attrs", marker = "python_full_version >= '3.14'" }, { name = "attrs" },
{ name = "numpy", marker = "python_full_version >= '3.14'" }, { name = "numpy" },
{ name = "wrapt", marker = "python_full_version >= '3.14'" }, { name = "wrapt" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/a6/83/ce29720ccf934c6cfa9b9c95ebbe96558386e66886626066632b5e44afed/dm_tree-0.1.9.tar.gz", hash = "sha256:a4c7db3d3935a5a2d5e4b383fc26c6b0cd6f78c6d4605d3e7b518800ecd5342b", size = 35623, upload-time = "2025-01-30T20:45:37.13Z" } sdist = { url = "https://files.pythonhosted.org/packages/a6/83/ce29720ccf934c6cfa9b9c95ebbe96558386e66886626066632b5e44afed/dm_tree-0.1.9.tar.gz", hash = "sha256:a4c7db3d3935a5a2d5e4b383fc26c6b0cd6f78c6d4605d3e7b518800ecd5342b", size = 35623, upload-time = "2025-01-30T20:45:37.13Z" }
wheels = [ wheels = [
@@ -1324,10 +1324,10 @@ resolution-markers = [
"python_full_version < '3.13' and sys_platform == 'win32'", "python_full_version < '3.13' and sys_platform == 'win32'",
] ]
dependencies = [ dependencies = [
{ name = "absl-py", marker = "python_full_version < '3.14'" }, { name = "absl-py" },
{ name = "attrs", marker = "python_full_version < '3.14'" }, { name = "attrs" },
{ name = "numpy", marker = "python_full_version < '3.14'" }, { name = "numpy" },
{ name = "wrapt", marker = "python_full_version < '3.14'" }, { name = "wrapt" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/5a/66/a3ec619d22b6baffa5ab853e8dc6ec9d0c837127948af59bb15b988d7312/dm_tree-0.1.10.tar.gz", hash = "sha256:22f37b599e01cc3402a17f79c257a802aebd8d326de05b54657650845956208a", size = 35748, upload-time = "2026-03-31T17:35:39.03Z" } sdist = { url = "https://files.pythonhosted.org/packages/5a/66/a3ec619d22b6baffa5ab853e8dc6ec9d0c837127948af59bb15b988d7312/dm_tree-0.1.10.tar.gz", hash = "sha256:22f37b599e01cc3402a17f79c257a802aebd8d326de05b54657650845956208a", size = 35748, upload-time = "2026-03-31T17:35:39.03Z" }
wheels = [ wheels = [
@@ -1911,7 +1911,7 @@ name = "h5py"
version = "3.16.0" version = "3.16.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "numpy", marker = "sys_platform == 'linux'" }, { name = "numpy" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/db/33/acd0ce6863b6c0d7735007df01815403f5589a21ff8c2e1ee2587a38f548/h5py-3.16.0.tar.gz", hash = "sha256:a0dbaad796840ccaa67a4c144a0d0c8080073c34c76d5a6941d6818678ef2738", size = 446526, upload-time = "2026-03-06T13:49:08.07Z" } sdist = { url = "https://files.pythonhosted.org/packages/db/33/acd0ce6863b6c0d7735007df01815403f5589a21ff8c2e1ee2587a38f548/h5py-3.16.0.tar.gz", hash = "sha256:a0dbaad796840ccaa67a4c144a0d0c8080073c34c76d5a6941d6818678ef2738", size = 446526, upload-time = "2026-03-06T13:49:08.07Z" }
wheels = [ wheels = [
@@ -1955,23 +1955,23 @@ name = "hf-libero"
version = "0.1.4" version = "0.1.4"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "bddl", marker = "sys_platform == 'linux'" }, { name = "bddl" },
{ name = "cloudpickle", marker = "sys_platform == 'linux'" }, { name = "cloudpickle" },
{ name = "easydict", marker = "sys_platform == 'linux'" }, { name = "easydict" },
{ name = "einops", marker = "sys_platform == 'linux'" }, { name = "einops" },
{ name = "future", marker = "sys_platform == 'linux'" }, { name = "future" },
{ name = "gymnasium", marker = "sys_platform == 'linux'" }, { name = "gymnasium" },
{ name = "hf-egl-probe", marker = "sys_platform == 'linux'" }, { name = "hf-egl-probe" },
{ name = "hydra-core", marker = "sys_platform == 'linux'" }, { name = "hydra-core" },
{ name = "matplotlib", marker = "sys_platform == 'linux'" }, { name = "matplotlib" },
{ name = "mujoco", marker = "sys_platform == 'linux'" }, { name = "mujoco" },
{ name = "numpy", marker = "sys_platform == 'linux'" }, { name = "numpy" },
{ name = "opencv-python", marker = "sys_platform == 'linux'" }, { name = "opencv-python" },
{ name = "robomimic", marker = "sys_platform == 'linux'" }, { name = "robomimic" },
{ name = "robosuite", marker = "sys_platform == 'linux'" }, { name = "robosuite" },
{ name = "thop", marker = "sys_platform == 'linux'" }, { name = "thop" },
{ name = "transformers", marker = "sys_platform == 'linux'" }, { name = "transformers" },
{ name = "wandb", marker = "sys_platform == 'linux'" }, { name = "wandb" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/af/aa/4e9eb8715e0bff9cb6553db563a35d253393097d446f82bd53575e8b253d/hf_libero-0.1.4.tar.gz", hash = "sha256:c058d67ad5a2b589529c14d614282ef4cca3a7763dafa134f58a6c9039657e34", size = 2961319, upload-time = "2026-06-10T09:56:13.994Z" } sdist = { url = "https://files.pythonhosted.org/packages/af/aa/4e9eb8715e0bff9cb6553db563a35d253393097d446f82bd53575e8b253d/hf_libero-0.1.4.tar.gz", hash = "sha256:c058d67ad5a2b589529c14d614282ef4cca3a7763dafa134f58a6c9039657e34", size = 2961319, upload-time = "2026-06-10T09:56:13.994Z" }
wheels = [ wheels = [
@@ -2122,9 +2122,9 @@ name = "hydra-core"
version = "1.3.4" version = "1.3.4"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "antlr4-python3-runtime", marker = "sys_platform == 'linux'" }, { name = "antlr4-python3-runtime" },
{ name = "omegaconf", marker = "sys_platform == 'linux'" }, { name = "omegaconf" },
{ name = "packaging", marker = "sys_platform == 'linux'" }, { name = "packaging" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/10/dd/220f0e91743136725352497e98540772a01fc7c3ab96ff16c3c74424e984/hydra_core-1.3.4.tar.gz", hash = "sha256:ad0f7b05a0242255a8984d5a4ed2f6847f7b783ed727368a2c0155ec52d6c34c", size = 3263348, upload-time = "2026-07-04T16:25:38.891Z" } sdist = { url = "https://files.pythonhosted.org/packages/10/dd/220f0e91743136725352497e98540772a01fc7c3ab96ff16c3c74424e984/hydra_core-1.3.4.tar.gz", hash = "sha256:ad0f7b05a0242255a8984d5a4ed2f6847f7b783ed727368a2c0155ec52d6c34c", size = 3263348, upload-time = "2026-07-04T16:25:38.891Z" }
wheels = [ wheels = [
@@ -2677,11 +2677,11 @@ name = "jupytext"
version = "1.19.5" version = "1.19.5"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "markdown-it-py", marker = "sys_platform == 'linux'" }, { name = "markdown-it-py" },
{ name = "mdit-py-plugins", marker = "sys_platform == 'linux'" }, { name = "mdit-py-plugins" },
{ name = "nbformat", marker = "sys_platform == 'linux'" }, { name = "nbformat" },
{ name = "packaging", marker = "sys_platform == 'linux'" }, { name = "packaging" },
{ name = "pyyaml", marker = "sys_platform == 'linux'" }, { name = "pyyaml" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/473f8ebb101553fb2ea6ab1d34324d6677844c968947ac050c759d539f2c/jupytext-1.19.5.tar.gz", hash = "sha256:605026446d605aa54fd7f7fc69df6ae51c7a46053d4cebf05afdc64d66de3df0", size = 4600916, upload-time = "2026-07-21T22:00:29.198Z" } sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/473f8ebb101553fb2ea6ab1d34324d6677844c968947ac050c759d539f2c/jupytext-1.19.5.tar.gz", hash = "sha256:605026446d605aa54fd7f7fc69df6ae51c7a46053d4cebf05afdc64d66de3df0", size = 4600916, upload-time = "2026-07-21T22:00:29.198Z" }
wheels = [ wheels = [
@@ -3471,7 +3471,7 @@ requires-dist = [
{ name = "pyrealsense2", marker = "sys_platform != 'darwin' and extra == 'intelrealsense'", specifier = ">=2.55.1.6486,<2.57.0" }, { name = "pyrealsense2", marker = "sys_platform != 'darwin' and extra == 'intelrealsense'", specifier = ">=2.55.1.6486,<2.57.0" },
{ name = "pyrealsense2-macosx", marker = "sys_platform == 'darwin' and extra == 'intelrealsense'", specifier = ">=2.54,<2.57.0" }, { name = "pyrealsense2-macosx", marker = "sys_platform == 'darwin' and extra == 'intelrealsense'", specifier = ">=2.54,<2.57.0" },
{ name = "pyserial", marker = "extra == 'pyserial-dep'", specifier = ">=3.5,<4.0" }, { name = "pyserial", marker = "extra == 'pyserial-dep'", specifier = ">=3.5,<4.0" },
{ name = "pytest", marker = "extra == 'test'", specifier = ">=8.1.0,<9.0.0" }, { name = "pytest", marker = "extra == 'test'", specifier = ">=8.1.0,<10.0.0" },
{ name = "pytest-cov", marker = "extra == 'test'", specifier = ">=5.0.0,<8.0.0" }, { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=5.0.0,<8.0.0" },
{ name = "pytest-timeout", marker = "extra == 'test'", specifier = ">=2.4.0,<3.0.0" }, { name = "pytest-timeout", marker = "extra == 'test'", specifier = ">=2.4.0,<3.0.0" },
{ name = "python-can", marker = "extra == 'can-dep'", specifier = ">=4.2.0,<5.0.0" }, { name = "python-can", marker = "extra == 'can-dep'", specifier = ">=4.2.0,<5.0.0" },
@@ -3485,7 +3485,7 @@ requires-dist = [
{ name = "scikit-image", marker = "extra == 'video-benchmark'", specifier = ">=0.23.2,<0.26.0" }, { name = "scikit-image", marker = "extra == 'video-benchmark'", specifier = ">=0.23.2,<0.26.0" },
{ name = "scipy", marker = "extra == 'all'", specifier = ">=1.14.0,<2.0.0" }, { name = "scipy", marker = "extra == 'all'", specifier = ">=1.14.0,<2.0.0" },
{ name = "scipy", marker = "extra == 'scipy-dep'", specifier = ">=1.14.0,<2.0.0" }, { name = "scipy", marker = "extra == 'scipy-dep'", specifier = ">=1.14.0,<2.0.0" },
{ name = "setuptools", specifier = ">=71.0.0,<81.0.0" }, { name = "setuptools", specifier = ">=71.0.0,<82.0.0" },
{ name = "teleop", marker = "extra == 'phone'", specifier = ">=0.1.0,<0.2.0" }, { name = "teleop", marker = "extra == 'phone'", specifier = ">=0.1.0,<0.2.0" },
{ name = "termcolor", specifier = ">=2.4.0,<4.0.0" }, { name = "termcolor", specifier = ">=2.4.0,<4.0.0" },
{ name = "timm", marker = "extra == 'timm-dep'", specifier = ">=1.0.0,<1.1.0" }, { name = "timm", marker = "extra == 'timm-dep'", specifier = ">=1.0.0,<1.1.0" },
@@ -3816,7 +3816,7 @@ name = "mdit-py-plugins"
version = "0.6.1" version = "0.6.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "markdown-it-py", marker = "sys_platform == 'linux'" }, { name = "markdown-it-py" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" } sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" }
wheels = [ wheels = [
@@ -4295,8 +4295,8 @@ name = "numba"
version = "0.66.0" version = "0.66.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "llvmlite", marker = "sys_platform == 'linux'" }, { name = "llvmlite" },
{ name = "numpy", marker = "sys_platform == 'linux'" }, { name = "numpy" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/ae/a0/570e3dc53e5602b49108f62a13e529f1eec8bfc7ef37d49c825924dcf546/numba-0.66.0.tar.gz", hash = "sha256:b900e63a0e26c05ea9a6d5a3a5a0a177cb64c5011887bf43edb8c3ed2c38d363", size = 2806181, upload-time = "2026-07-01T23:12:46.36Z" } sdist = { url = "https://files.pythonhosted.org/packages/ae/a0/570e3dc53e5602b49108f62a13e529f1eec8bfc7ef37d49c825924dcf546/numba-0.66.0.tar.gz", hash = "sha256:b900e63a0e26c05ea9a6d5a3a5a0a177cb64c5011887bf43edb8c3ed2c38d363", size = 2806181, upload-time = "2026-07-01T23:12:46.36Z" }
wheels = [ wheels = [
@@ -4389,7 +4389,7 @@ name = "nvidia-cudnn-cu12"
version = "9.19.0.56" version = "9.19.0.56"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cublas-cu12" },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/09/b8/277c51962ee46fa3e5b203ac5f76107c650f781d6891e681e28e6f3e9fe6/nvidia_cudnn_cu12-9.19.0.56-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:08caaf27fe556aca82a3ee3b5aa49a77e7de0cfcb7ff4e5c29da426387a8267e", size = 656910700, upload-time = "2026-02-03T20:40:25.508Z" }, { url = "https://files.pythonhosted.org/packages/09/b8/277c51962ee46fa3e5b203ac5f76107c650f781d6891e681e28e6f3e9fe6/nvidia_cudnn_cu12-9.19.0.56-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:08caaf27fe556aca82a3ee3b5aa49a77e7de0cfcb7ff4e5c29da426387a8267e", size = 656910700, upload-time = "2026-02-03T20:40:25.508Z" },
@@ -4401,7 +4401,7 @@ name = "nvidia-cufft-cu12"
version = "11.3.3.83" version = "11.3.3.83"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-nvjitlink-cu12" },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211, upload-time = "2025-03-07T01:44:56.873Z" }, { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211, upload-time = "2025-03-07T01:44:56.873Z" },
@@ -4431,9 +4431,9 @@ name = "nvidia-cusolver-cu12"
version = "11.7.3.90" version = "11.7.3.90"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cublas-cu12" },
{ name = "nvidia-cusparse-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cusparse-cu12" },
{ name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-nvjitlink-cu12" },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841, upload-time = "2025-03-07T01:46:54.356Z" }, { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841, upload-time = "2025-03-07T01:46:54.356Z" },
@@ -4445,7 +4445,7 @@ name = "nvidia-cusparse-cu12"
version = "12.5.8.93" version = "12.5.8.93"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-nvjitlink-cu12" },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129, upload-time = "2025-03-07T01:47:40.407Z" }, { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129, upload-time = "2025-03-07T01:47:40.407Z" },
@@ -4502,8 +4502,8 @@ name = "omegaconf"
version = "2.3.1" version = "2.3.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "antlr4-python3-runtime", marker = "sys_platform == 'linux'" }, { name = "antlr4-python3-runtime" },
{ name = "pyyaml", marker = "sys_platform == 'linux'" }, { name = "pyyaml" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/ce/3d/e4b57b8d9008c6ebe0d5eff901f91d5700cf7bdb8c8863df817463a7fd5e/omegaconf-2.3.1.tar.gz", hash = "sha256:e5e7de64aeebeddaf8e6d3f7a783b32ac2a01c0fbd9c878012caecb891a1f42a", size = 3298472, upload-time = "2026-06-11T05:05:12.885Z" } sdist = { url = "https://files.pythonhosted.org/packages/ce/3d/e4b57b8d9008c6ebe0d5eff901f91d5700cf7bdb8c8863df817463a7fd5e/omegaconf-2.3.1.tar.gz", hash = "sha256:e5e7de64aeebeddaf8e6d3f7a783b32ac2a01c0fbd9c878012caecb891a1f42a", size = 3298472, upload-time = "2026-06-11T05:05:12.885Z" }
wheels = [ wheels = [
@@ -4743,7 +4743,7 @@ name = "pexpect"
version = "4.9.0" version = "4.9.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "ptyprocess", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, { name = "ptyprocess" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" }
wheels = [ wheels = [
@@ -5317,10 +5317,10 @@ name = "pyobjc-framework-applicationservices"
version = "12.2.1" version = "12.2.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-core" },
{ name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-framework-cocoa" },
{ name = "pyobjc-framework-coretext", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-framework-coretext" },
{ name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-framework-quartz" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/5e/4d/0ebdd8144aba94b8fe9828ccee5616a4bf53d1f8bc51cff55f3cce86d695/pyobjc_framework_applicationservices-12.2.1.tar.gz", hash = "sha256:048ea663c9ac75c44a15dc7d5b8d78cbb4c97bf1c76e83835e8d5498e184001f", size = 109342, upload-time = "2026-06-19T16:19:46.149Z" } sdist = { url = "https://files.pythonhosted.org/packages/5e/4d/0ebdd8144aba94b8fe9828ccee5616a4bf53d1f8bc51cff55f3cce86d695/pyobjc_framework_applicationservices-12.2.1.tar.gz", hash = "sha256:048ea663c9ac75c44a15dc7d5b8d78cbb4c97bf1c76e83835e8d5498e184001f", size = 109342, upload-time = "2026-06-19T16:19:46.149Z" }
wheels = [ wheels = [
@@ -5338,7 +5338,7 @@ name = "pyobjc-framework-cocoa"
version = "12.2.1" version = "12.2.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-core" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/51/34/fbe38a204643aa4e1b91391cdce07a34da565a69171ebcad08de7438a556/pyobjc_framework_cocoa-12.2.1.tar.gz", hash = "sha256:b94b37fe5730e5ae1fb0052912cd174e6ec329b0bfba4a012ae5db1014b5864b", size = 3125751, upload-time = "2026-06-19T16:20:05.159Z" } sdist = { url = "https://files.pythonhosted.org/packages/51/34/fbe38a204643aa4e1b91391cdce07a34da565a69171ebcad08de7438a556/pyobjc_framework_cocoa-12.2.1.tar.gz", hash = "sha256:b94b37fe5730e5ae1fb0052912cd174e6ec329b0bfba4a012ae5db1014b5864b", size = 3125751, upload-time = "2026-06-19T16:20:05.159Z" }
wheels = [ wheels = [
@@ -5356,9 +5356,9 @@ name = "pyobjc-framework-coretext"
version = "12.2.1" version = "12.2.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-core" },
{ name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-framework-cocoa" },
{ name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-framework-quartz" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/5a/9c/4c7f452059dc1d3845b8e627b9113c247a997b9b07518e848c2ab7ff3149/pyobjc_framework_coretext-12.2.1.tar.gz", hash = "sha256:af740e784d7c592c34025ec7165f4f6c1a69b5a2d9075f06e41e4f77c212aed2", size = 97349, upload-time = "2026-06-19T16:20:22.508Z" } sdist = { url = "https://files.pythonhosted.org/packages/5a/9c/4c7f452059dc1d3845b8e627b9113c247a997b9b07518e848c2ab7ff3149/pyobjc_framework_coretext-12.2.1.tar.gz", hash = "sha256:af740e784d7c592c34025ec7165f4f6c1a69b5a2d9075f06e41e4f77c212aed2", size = 97349, upload-time = "2026-06-19T16:20:22.508Z" }
wheels = [ wheels = [
@@ -5376,8 +5376,8 @@ name = "pyobjc-framework-quartz"
version = "12.2.1" version = "12.2.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-core" },
{ name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "pyobjc-framework-cocoa" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/3b/f6/2a8b84dbf1fe7c04dd96ea73d991678d4e09a909f51971ecc51629bb2ab4/pyobjc_framework_quartz-12.2.1.tar.gz", hash = "sha256:b3b8b6f71e66147f8ff9e6213864cc8527e3a0b1ee90835b93ce221f4802d9b0", size = 3215521, upload-time = "2026-06-19T16:21:30.199Z" } sdist = { url = "https://files.pythonhosted.org/packages/3b/f6/2a8b84dbf1fe7c04dd96ea73d991678d4e09a909f51971ecc51629bb2ab4/pyobjc_framework_quartz-12.2.1.tar.gz", hash = "sha256:b3b8b6f71e66147f8ff9e6213864cc8527e3a0b1ee90835b93ce221f4802d9b0", size = 3215521, upload-time = "2026-06-19T16:21:30.199Z" }
wheels = [ wheels = [
@@ -5940,18 +5940,18 @@ name = "robomimic"
version = "0.2.0" version = "0.2.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "egl-probe", marker = "sys_platform == 'linux'" }, { name = "egl-probe" },
{ name = "h5py", marker = "sys_platform == 'linux'" }, { name = "h5py" },
{ name = "imageio", marker = "sys_platform == 'linux'" }, { name = "imageio" },
{ name = "imageio-ffmpeg", marker = "sys_platform == 'linux'" }, { name = "imageio-ffmpeg" },
{ name = "numpy", marker = "sys_platform == 'linux'" }, { name = "numpy" },
{ name = "psutil", marker = "sys_platform == 'linux'" }, { name = "psutil" },
{ name = "tensorboard", marker = "sys_platform == 'linux'" }, { name = "tensorboard" },
{ name = "tensorboardx", marker = "sys_platform == 'linux'" }, { name = "tensorboardx" },
{ name = "termcolor", marker = "sys_platform == 'linux'" }, { name = "termcolor" },
{ name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform == 'linux'" }, { name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } },
{ name = "torchvision", version = "0.26.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform == 'linux'" }, { name = "torchvision", version = "0.26.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } },
{ name = "tqdm", marker = "sys_platform == 'linux'" }, { name = "tqdm" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/3d/c3/44b1d1ea4bcb4bbed43d19e09505f4142714451ded74020d4f679cdc89fb/robomimic-0.2.0.tar.gz", hash = "sha256:ee3bb5cf9c3e1feead6b57b43c5db738fd0a8e0c015fdf6419808af8fffdc463", size = 192919, upload-time = "2021-12-17T19:00:33.279Z" } sdist = { url = "https://files.pythonhosted.org/packages/3d/c3/44b1d1ea4bcb4bbed43d19e09505f4142714451ded74020d4f679cdc89fb/robomimic-0.2.0.tar.gz", hash = "sha256:ee3bb5cf9c3e1feead6b57b43c5db738fd0a8e0c015fdf6419808af8fffdc463", size = 192919, upload-time = "2021-12-17T19:00:33.279Z" }
@@ -5960,12 +5960,12 @@ name = "robosuite"
version = "1.4.0" version = "1.4.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "mujoco", marker = "sys_platform == 'linux'" }, { name = "mujoco" },
{ name = "numba", marker = "sys_platform == 'linux'" }, { name = "numba" },
{ name = "numpy", marker = "sys_platform == 'linux'" }, { name = "numpy" },
{ name = "opencv-python", marker = "sys_platform == 'linux'" }, { name = "opencv-python" },
{ name = "pillow", marker = "sys_platform == 'linux'" }, { name = "pillow" },
{ name = "scipy", marker = "sys_platform == 'linux'" }, { name = "scipy" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/25/a1/9dd07a9a5e09c6aa032faf531da985808b34437cbf6c8f358fe8f7c47118/robosuite-1.4.0.tar.gz", hash = "sha256:a8a6233d7458dbd91bf00a86cab15aa1c178bd9d1b28d515db2cf3d152cb48e6", size = 192182147, upload-time = "2022-12-01T07:31:55.791Z" } sdist = { url = "https://files.pythonhosted.org/packages/25/a1/9dd07a9a5e09c6aa032faf531da985808b34437cbf6c8f358fe8f7c47118/robosuite-1.4.0.tar.gz", hash = "sha256:a8a6233d7458dbd91bf00a86cab15aa1c178bd9d1b28d515db2cf3d152cb48e6", size = 192182147, upload-time = "2022-12-01T07:31:55.791Z" }
wheels = [ wheels = [
@@ -6386,16 +6386,16 @@ name = "tensorboard"
version = "2.20.0" version = "2.20.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "absl-py", marker = "sys_platform == 'linux'" }, { name = "absl-py" },
{ name = "grpcio", marker = "sys_platform == 'linux'" }, { name = "grpcio" },
{ name = "markdown", marker = "sys_platform == 'linux'" }, { name = "markdown" },
{ name = "numpy", marker = "sys_platform == 'linux'" }, { name = "numpy" },
{ name = "packaging", marker = "sys_platform == 'linux'" }, { name = "packaging" },
{ name = "pillow", marker = "sys_platform == 'linux'" }, { name = "pillow" },
{ name = "protobuf", marker = "sys_platform == 'linux'" }, { name = "protobuf" },
{ name = "setuptools", marker = "sys_platform == 'linux'" }, { name = "setuptools" },
{ name = "tensorboard-data-server", marker = "sys_platform == 'linux'" }, { name = "tensorboard-data-server" },
{ name = "werkzeug", marker = "sys_platform == 'linux'" }, { name = "werkzeug" },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/9c/d9/a5db55f88f258ac669a92858b70a714bbbd5acd993820b41ec4a96a4d77f/tensorboard-2.20.0-py3-none-any.whl", hash = "sha256:9dc9f978cb84c0723acf9a345d96c184f0293d18f166bb8d59ee098e6cfaaba6", size = 5525680, upload-time = "2025-07-17T19:20:49.638Z" }, { url = "https://files.pythonhosted.org/packages/9c/d9/a5db55f88f258ac669a92858b70a714bbbd5acd993820b41ec4a96a4d77f/tensorboard-2.20.0-py3-none-any.whl", hash = "sha256:9dc9f978cb84c0723acf9a345d96c184f0293d18f166bb8d59ee098e6cfaaba6", size = 5525680, upload-time = "2025-07-17T19:20:49.638Z" },
@@ -6415,9 +6415,9 @@ name = "tensorboardx"
version = "2.6.5" version = "2.6.5"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "numpy", marker = "sys_platform == 'linux'" }, { name = "numpy" },
{ name = "packaging", marker = "sys_platform == 'linux'" }, { name = "packaging" },
{ name = "protobuf", marker = "sys_platform == 'linux'" }, { name = "protobuf" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/48/a9/fc520ea91ab1f3ba51cbf3fe24f2b6364ed3b49046969e0868d46d6da372/tensorboardx-2.6.5.tar.gz", hash = "sha256:ca176db3997ee8c07d2eb77381225956a3fd1c10c91beafab1f17069adc47017", size = 4770195, upload-time = "2026-04-03T15:40:23.803Z" } sdist = { url = "https://files.pythonhosted.org/packages/48/a9/fc520ea91ab1f3ba51cbf3fe24f2b6364ed3b49046969e0868d46d6da372/tensorboardx-2.6.5.tar.gz", hash = "sha256:ca176db3997ee8c07d2eb77381225956a3fd1c10c91beafab1f17069adc47017", size = 4770195, upload-time = "2026-04-03T15:40:23.803Z" }
wheels = [ wheels = [
@@ -6452,7 +6452,7 @@ name = "thop"
version = "0.1.1.post2209072238" version = "0.1.1.post2209072238"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform == 'linux'" }, { name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/bb/0f/72beeab4ff5221dc47127c80f8834b4bcd0cb36f6ba91c0b1d04a1233403/thop-0.1.1.post2209072238-py3-none-any.whl", hash = "sha256:01473c225231927d2ad718351f78ebf7cffe6af3bed464c4f1ba1ef0f7cdda27", size = 15443, upload-time = "2022-09-07T14:38:37.211Z" }, { url = "https://files.pythonhosted.org/packages/bb/0f/72beeab4ff5221dc47127c80f8834b4bcd0cb36f6ba91c0b1d04a1233403/thop-0.1.1.post2209072238-py3-none-any.whl", hash = "sha256:01473c225231927d2ad718351f78ebf7cffe6af3bed464c4f1ba1ef0f7cdda27", size = 15443, upload-time = "2022-09-07T14:38:37.211Z" },
@@ -6558,13 +6558,13 @@ resolution-markers = [
"python_full_version < '3.13' and sys_platform == 'win32'", "python_full_version < '3.13' and sys_platform == 'win32'",
] ]
dependencies = [ dependencies = [
{ name = "filelock", marker = "sys_platform != 'linux'" }, { name = "filelock" },
{ name = "fsspec", marker = "sys_platform != 'linux'" }, { name = "fsspec" },
{ name = "jinja2", marker = "sys_platform != 'linux'" }, { name = "jinja2" },
{ name = "networkx", marker = "sys_platform != 'linux'" }, { name = "networkx" },
{ name = "setuptools", marker = "sys_platform != 'linux'" }, { name = "setuptools" },
{ name = "sympy", marker = "sys_platform != 'linux'" }, { name = "sympy" },
{ name = "typing-extensions", marker = "sys_platform != 'linux'" }, { name = "typing-extensions" },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/6f/8b/69e3008d78e5cee2b30183340cc425081b78afc5eff3d080daab0adda9aa/torch-2.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b5866312ee6e52ea625cd211dcb97d6a2cdc1131a5f15cc0d87eec948f6dd34", size = 80606338, upload-time = "2026-03-23T18:11:34.781Z" }, { url = "https://files.pythonhosted.org/packages/6f/8b/69e3008d78e5cee2b30183340cc425081b78afc5eff3d080daab0adda9aa/torch-2.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b5866312ee6e52ea625cd211dcb97d6a2cdc1131a5f15cc0d87eec948f6dd34", size = 80606338, upload-time = "2026-03-23T18:11:34.781Z" },
@@ -6598,20 +6598,20 @@ resolution-markers = [
"python_full_version < '3.13' and platform_machine != 'AMD64' and platform_machine != 'aarch64' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'linux'", "python_full_version < '3.13' and platform_machine != 'AMD64' and platform_machine != 'aarch64' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'linux'",
] ]
dependencies = [ dependencies = [
{ name = "cuda-bindings", marker = "sys_platform == 'linux'" }, { name = "cuda-bindings" },
{ name = "cuda-toolkit", extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "sys_platform == 'linux'" }, { name = "cuda-toolkit", extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"] },
{ name = "filelock", marker = "sys_platform == 'linux'" }, { name = "filelock" },
{ name = "fsspec", marker = "sys_platform == 'linux'" }, { name = "fsspec" },
{ name = "jinja2", marker = "sys_platform == 'linux'" }, { name = "jinja2" },
{ name = "networkx", marker = "sys_platform == 'linux'" }, { name = "networkx" },
{ name = "nvidia-cudnn-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cudnn-cu12" },
{ name = "nvidia-cusparselt-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cusparselt-cu12" },
{ name = "nvidia-nccl-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-nccl-cu12" },
{ name = "nvidia-nvshmem-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-nvshmem-cu12" },
{ name = "setuptools", marker = "sys_platform == 'linux'" }, { name = "setuptools" },
{ name = "sympy", marker = "sys_platform == 'linux'" }, { name = "sympy" },
{ name = "triton", marker = "sys_platform == 'linux'" }, { name = "triton" },
{ name = "typing-extensions", marker = "sys_platform == 'linux'" }, { name = "typing-extensions" },
] ]
wheels = [ wheels = [
{ url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9c8f38efee365cb9d334de8a83ce52fc7e5fc9e5a7b0853285efa1b69e00b0f2", upload-time = "2026-04-27T17:41:30Z" }, { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9c8f38efee365cb9d334de8a83ce52fc7e5fc9e5a7b0853285efa1b69e00b0f2", upload-time = "2026-04-27T17:41:30Z" },
@@ -6682,9 +6682,9 @@ resolution-markers = [
"python_full_version < '3.13' and sys_platform == 'win32'", "python_full_version < '3.13' and sys_platform == 'win32'",
] ]
dependencies = [ dependencies = [
{ name = "numpy", marker = "sys_platform != 'linux'" }, { name = "numpy" },
{ name = "pillow", marker = "sys_platform != 'linux'" }, { name = "pillow" },
{ name = "torch", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'linux'" }, { name = "torch", version = "2.11.0", source = { registry = "https://pypi.org/simple" } },
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/ae/e7/56b47cc3b132aea90ccce22bcb8975dec688b002150012acc842846039d0/torchvision-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c409e1c3fdebec7a3834465086dbda8bf7680eff79abf7fd2f10c6b59520a7a4", size = 1863502, upload-time = "2026-03-23T18:12:57.326Z" }, { url = "https://files.pythonhosted.org/packages/ae/e7/56b47cc3b132aea90ccce22bcb8975dec688b002150012acc842846039d0/torchvision-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c409e1c3fdebec7a3834465086dbda8bf7680eff79abf7fd2f10c6b59520a7a4", size = 1863502, upload-time = "2026-03-23T18:12:57.326Z" },
@@ -6718,9 +6718,9 @@ resolution-markers = [
"python_full_version < '3.13' and platform_machine != 'AMD64' and platform_machine != 'aarch64' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'linux'", "python_full_version < '3.13' and platform_machine != 'AMD64' and platform_machine != 'aarch64' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'linux'",
] ]
dependencies = [ dependencies = [
{ name = "numpy", marker = "sys_platform == 'linux'" }, { name = "numpy" },
{ name = "pillow", marker = "sys_platform == 'linux'" }, { name = "pillow" },
{ name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform == 'linux'" }, { name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } },
] ]
wheels = [ wheels = [
{ url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:63e35234aed13b6edda37056f417b5c281249669db631e706811917af36b21d7", upload-time = "2026-04-09T23:21:35Z" }, { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:63e35234aed13b6edda37056f417b5c281249669db631e706811917af36b21d7", upload-time = "2026-04-09T23:21:35Z" },
@@ -7222,7 +7222,7 @@ name = "werkzeug"
version = "3.1.8" version = "3.1.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "markupsafe", marker = "sys_platform == 'linux'" }, { name = "markupsafe" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/dd/b2/381be8cfdee792dd117872481b6e378f85c957dd7c5bca38897b08f765fd/werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44", size = 875852, upload-time = "2026-04-02T18:49:14.268Z" } sdist = { url = "https://files.pythonhosted.org/packages/dd/b2/381be8cfdee792dd117872481b6e378f85c957dd7c5bca38897b08f765fd/werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44", size = 875852, upload-time = "2026-04-02T18:49:14.268Z" }
wheels = [ wheels = [