diff --git a/.github/workflows/pypi_publish.yml b/.github/workflows/pypi_publish.yml index 9b6d7927..a933e1d6 100644 --- a/.github/workflows/pypi_publish.yml +++ b/.github/workflows/pypi_publish.yml @@ -164,7 +164,7 @@ jobs: run: | source /tmp/test-venv/bin/activate python -c " - from mujoco_extensions.policy_rollout import create_systems_vector, threaded_rollout + from judo.mujoco_extensions.policy_rollout import create_systems_vector, threaded_rollout print('mujoco_extensions OK') from judo.tasks.spot.spot_base import SpotBase, XML_PATH from judo.tasks.spot.spot_constants import SPOT_LOCOMOTION_POLICY_PATH diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 96b263ef..f7d934cf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,9 +42,9 @@ jobs: uses: actions/cache@v5 with: path: | - mujoco_extensions/build - mujoco_extensions/policy_rollout/*.so - key: mujoco-ext-${{ matrix.os }}-${{ matrix.pixi-env }}-${{ hashFiles('pixi.lock', 'mujoco_extensions/**/*.cpp', 'mujoco_extensions/**/*.h', 'mujoco_extensions/**/CMakeLists.txt') }} + judo/mujoco_extensions/build + judo/mujoco_extensions/policy_rollout/*.so + key: mujoco-ext-${{ matrix.os }}-${{ matrix.pixi-env }}-${{ hashFiles('pixi.lock', 'judo/mujoco_extensions/**/*.cpp', 'judo/mujoco_extensions/**/*.h', 'judo/mujoco_extensions/**/CMakeLists.txt') }} - name: Build mujoco_extensions (cache miss) if: steps.ext-cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/test_gpu.yml b/.github/workflows/test_gpu.yml index 280a7b3f..c1dda336 100644 --- a/.github/workflows/test_gpu.yml +++ b/.github/workflows/test_gpu.yml @@ -29,9 +29,9 @@ jobs: uses: actions/cache@v5 with: path: | - mujoco_extensions/build - mujoco_extensions/policy_rollout/*.so - key: mujoco-ext-gpu-${{ hashFiles('pixi.lock', 'mujoco_extensions/**/*.cpp', 'mujoco_extensions/**/*.h', 'mujoco_extensions/**/CMakeLists.txt') }} + judo/mujoco_extensions/build + judo/mujoco_extensions/policy_rollout/*.so + key: mujoco-ext-gpu-${{ hashFiles('pixi.lock', 'judo/mujoco_extensions/**/*.cpp', 'judo/mujoco_extensions/**/*.h', 'judo/mujoco_extensions/**/CMakeLists.txt') }} - name: Build mujoco_extensions (cache miss) if: steps.ext-cache.outputs.cache-hit != 'true' diff --git a/.gitignore b/.gitignore index 9de1e035..a71c30f0 100644 --- a/.gitignore +++ b/.gitignore @@ -188,7 +188,7 @@ outputs/ MUJOCO_LOG.TXT # bundled shared libraries (auditwheel handles bundling into wheel) -mujoco_extensions/policy_rollout/libonnxruntime* +judo/mujoco_extensions/policy_rollout/libonnxruntime* wheelhouse/ # assets diff --git a/README.md b/README.md index d5e80997..6df299f6 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,18 @@ pixi run clean pixi run build ``` +If you change the `policy_rollout_pybind` C++ API (signatures in +`judo/mujoco_extensions/policy_rollout/pybind/`), regenerate its type stubs so +type checkers stay in sync (this builds the module first): +```bash +pixi run stubgen-extension +``` +The generated `.pyi` files live next to the compiled module in +`judo/mujoco_extensions/policy_rollout/policy_rollout_pybind/` and are committed +to the repo. `pybind11-stubgen` occasionally emits raw C++ types (e.g. +`SystemClass::System`, `Ort::Session`) as invalid `...` annotations — review the +diff and replace those with the proper Python types before committing. + ## 2. Run the `judo` app! To start the simulator, from within the pixi shell, you can simply run: ```bash diff --git a/judo/app/__init__.py b/judo/app/__init__.py index 4d3e2daf..95856600 100644 --- a/judo/app/__init__.py +++ b/judo/app/__init__.py @@ -1 +1,81 @@ # Copyright (c) 2025 Robotics and AI Institute LLC. All rights reserved. + +"""Judo application defaults. + +This package is judo's *batteries-included* task set. It is intentionally kept out of the +individual libraries (tasks, optimizers, controllers, simulation) so those libraries can be reused +by third-party packages that want to register their own tasks. Its sole job is to declare judo's +default tasks and how each one is wired (rollout backend, simulation backend, and low-level +locomotion policy). + +Importing ``judo.app`` registers judo's built-in tasks via :func:`register_default_tasks`. +Third-party applications that only want the *mechanism* (not judo's default tasks) should avoid +importing this module and instead call :func:`judo.tasks.register_task` themselves. Applications +that want judo's defaults *and* their own can import this module (or call +:func:`register_default_tasks`) and then register/override additional tasks by name. +""" + +from judo.tasks import register_task +from judo.tasks.caltech_leap_cube import CaltechLeapCube, CaltechLeapCubeConfig +from judo.tasks.cartpole import Cartpole, CartpoleConfig +from judo.tasks.cylinder_push import CylinderPush, CylinderPushConfig +from judo.tasks.fr3_pick import FR3Pick, FR3PickConfig +from judo.tasks.leap_cube import LeapCube, LeapCubeConfig +from judo.tasks.leap_cube_down import LeapCubeDown, LeapCubeDownConfig +from judo.tasks.spot import ( + SpotBase, + SpotBaseConfig, + SpotBoxPush, + SpotBoxPushConfig, + SpotNavigate, + SpotNavigateConfig, + SpotTireRoll, + SpotTireRollConfig, + SpotTireUpright, + SpotTireUprightConfig, +) +from judo.tasks.spot.spot_constants import SPOT_LOCOMOTION_POLICY_PATH + + +def register_default_tasks() -> None: + """Register judo's built-in tasks with their default backends and locomotion policies. + + This is the application-level source of truth for which tasks are available and how each one + is wired (rollout backend, simulation backend, and low-level locomotion policy). Third-party + applications can call :func:`judo.tasks.register_task` (or + :func:`judo.registration.register_tasks_from_cfg`) to register their own tasks instead of, or + in addition to, these defaults. Re-registering a name overrides the previous entry, so callers + may register these defaults and then override individual tasks by name. + """ + register_task(CylinderPush.name, CylinderPush, CylinderPushConfig) + register_task(Cartpole.name, Cartpole, CartpoleConfig) + register_task(FR3Pick.name, FR3Pick, FR3PickConfig) + register_task(LeapCube.name, LeapCube, LeapCubeConfig) + register_task(LeapCubeDown.name, LeapCubeDown, LeapCubeDownConfig) + register_task(CaltechLeapCube.name, CaltechLeapCube, CaltechLeapCubeConfig) + + spot_policy_path = str(SPOT_LOCOMOTION_POLICY_PATH) + for spot_task, spot_config in ( + (SpotBase, SpotBaseConfig), + (SpotBoxPush, SpotBoxPushConfig), + (SpotNavigate, SpotNavigateConfig), + (SpotTireRoll, SpotTireRollConfig), + (SpotTireUpright, SpotTireUprightConfig), + ): + register_task( + spot_task.name, + spot_task, + spot_config, + rollout_backend="mujoco_hierarchical", + simulation_backend="mujoco_hierarchical", + locomotion_policy_path=spot_policy_path, + ) + + +# Register judo's built-in tasks when the application defaults are imported. +register_default_tasks() + + +__all__ = [ + "register_default_tasks", +] diff --git a/judo/app/dora/controller_node.py b/judo/app/dora/controller_node.py index 872b066e..5cb4ae8d 100644 --- a/judo/app/dora/controller_node.py +++ b/judo/app/dora/controller_node.py @@ -9,8 +9,10 @@ from dora_utils.node import DoraNode, on_event from omegaconf import DictConfig -from judo.app.structs import MujocoState from judo.controller import Controller, make_controller +from judo.optimizers import get_registered_optimizers +from judo.structs import MujocoState +from judo.tasks import get_registered_tasks class ControllerNode(DoraNode): @@ -44,6 +46,7 @@ def __init__( self._optimizer_registration_cfg = optimizer_registration_cfg self.controller = self._build_controller(init_task, init_optimizer) self._paused = False + self._running = True self.write_controls() self.lock = Lock() @@ -61,7 +64,7 @@ def _current_optimizer_name(self) -> str: Returns "cem" as a safe default if no registry entry matches the active optimizer instance. """ - for name, (cls, _) in self.controller.available_optimizers.items(): + for name, (cls, _) in get_registered_optimizers().items(): if isinstance(self.controller.optimizer, cls): return name return "cem" @@ -70,7 +73,7 @@ def _current_optimizer_name(self) -> str: def update_task(self, event: dict) -> None: """Updates the task type.""" new_task = event["value"].to_numpy(zero_copy_only=False)[0] - task_entry = self.controller.available_tasks.get(new_task) + task_entry = get_registered_tasks().get(new_task) if task_entry is None: raise ValueError(f"Task {new_task} not found in task registry.") @@ -94,7 +97,7 @@ def set_paused_status(self, event: dict) -> None: def update_optimizer(self, event: dict) -> None: """Updates the optimizer type.""" new_optimizer = event["value"].to_numpy(zero_copy_only=False)[0] - optimizer_entry = self.controller.available_optimizers.get(new_optimizer) + optimizer_entry = get_registered_optimizers().get(new_optimizer) if optimizer_entry is not None: optimizer_cls, optimizer_config_cls = optimizer_entry optimizer_config = optimizer_config_cls() @@ -120,11 +123,25 @@ def update_task_config(self, event: dict) -> None: """Callback to update optimizer task config on receiving a new config message.""" self.controller.task_config = from_event(event, type(self.controller.task_config)) + def _send_output(self, output_id: str, data: pa.Array, metadata: dict | None = None) -> None: + """Publish an output, tolerating event-stream closure during shutdown. + + During Ctrl-C / dataflow teardown the dora event stream can close while a step is in + progress, which makes ``send_output`` raise ``RuntimeError``. Treat that as a stop signal + so shutdown stays quiet instead of surfacing a traceback. + """ + if not self._running: + return + try: + self.node.send_output(output_id, data, metadata or {}) + except RuntimeError: + self._running = False + def write_controls(self) -> None: """Util that publishes the current controller spline.""" # send control action arr, metadata = to_arrow(self.controller.spline_data) - self.node.send_output("controls", arr, metadata) + self._send_output("controls", arr, metadata) # send traces if self.controller.traces is not None and len(self.controller.traces) > 0: @@ -132,7 +149,7 @@ def write_controls(self) -> None: "all_traces_rollout_size": str(self.controller.all_traces_rollout_size), "shape": self.controller.traces.shape, } - self.node.send_output("traces", pa.array(self.controller.traces.flatten()), metadata=metadata) + self._send_output("traces", pa.array(self.controller.traces.flatten()), metadata=metadata) @on_event("INPUT", "states") def update_states(self, event: dict) -> None: @@ -163,16 +180,18 @@ def step(self) -> None: self.controller.update_action() end = time.perf_counter() - self.node.send_output("plan_time", pa.array([end - start])) + self._send_output("plan_time", pa.array([end - start])) self.write_controls() def spin(self) -> None: """Spin logic for the controller node.""" try: - while True: + while self._running: start_time = time.time() self.parse_messages() self.step() + if not self._running: + break # Force controller to run at fixed rate specified by control_freq. sleep_dt = 1 / self.controller.controller_cfg.control_freq - (time.time() - start_time) diff --git a/judo/app/dora/simulation_node.py b/judo/app/dora/simulation_node.py index d3925847..c9473146 100644 --- a/judo/app/dora/simulation_node.py +++ b/judo/app/dora/simulation_node.py @@ -8,9 +8,9 @@ from dora_utils.node import DoraNode, on_event from omegaconf import DictConfig -from judo.app.structs import SplineData from judo.simulation import DEFAULT_SIMULATION_BACKEND_REGISTRY from judo.simulation.base import Simulation +from judo.structs import SplineData from judo.tasks import get_registered_tasks @@ -56,7 +56,12 @@ def _init_sim(self, task_name: str) -> None: raise ValueError(f"Task {task_name} not found in task registry.") sim_backend_cls = self._resolve_backend(task_entry.simulation_backend) - self.sim = sim_backend_cls(init_task=task_name, task_registration_cfg=self._task_registration_cfg) + sim_kwargs: dict = {"init_task": task_name, "task_registration_cfg": self._task_registration_cfg} + # The hierarchical backend needs the low-level policy path passed explicitly (the + # Simulation classes are decoupled from the task registry). + if task_entry.simulation_backend == "mujoco_hierarchical": + sim_kwargs["locomotion_policy_path"] = task_entry.locomotion_policy_path + self.sim = sim_backend_cls(**sim_kwargs) @on_event("INPUT", "task") def update_task(self, event: dict) -> None: diff --git a/judo/app/dora/visualization_node.py b/judo/app/dora/visualization_node.py index 462155ae..ad6db89b 100644 --- a/judo/app/dora/visualization_node.py +++ b/judo/app/dora/visualization_node.py @@ -8,7 +8,7 @@ from omegaconf import DictConfig from viser import GuiFolderHandle, GuiImageHandle, GuiInputHandle, IcosphereHandle, MeshHandle -from judo.app.structs import RenderPose +from judo.structs import RenderPose from judo.tasks import TaskRegistration from judo.visualizers.visualizer import Visualizer diff --git a/judo/cli.py b/judo/cli.py index 7a9a29d4..8fdeec58 100644 --- a/judo/cli.py +++ b/judo/cli.py @@ -119,7 +119,11 @@ def main_app(cfg: DictConfig) -> None: """Main function to run judo via a hydra configuration yaml file.""" try: run(cfg) - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit, subprocess.CalledProcessError): + # On shutdown (e.g. Ctrl+C), dora_utils' cleanup (run.py) calls `dora destroy` with + # check=True; if the dataflow is already being torn down it exits non-zero and raises + # CalledProcessError. Our own _force_cleanup() already handles teardown, so all of these + # are expected shutdown paths rather than real failures. _force_cleanup() @@ -144,7 +148,7 @@ def _warm_caches() -> None: def _require_mujoco_extensions() -> None: """Fail fast if mujoco_extensions is unavailable in the current environment.""" try: - import mujoco_extensions # noqa: F401, PLC0415 + import judo.mujoco_extensions # noqa: F401, PLC0415 except Exception as e: # pragma: no cover - environment dependent raise RuntimeError( "mujoco_extensions is required but could not be imported. Build it with: pixi run build" diff --git a/judo/controller/__init__.py b/judo/controller/__init__.py index 53aaa439..08de86f6 100644 --- a/judo/controller/__init__.py +++ b/judo/controller/__init__.py @@ -4,8 +4,8 @@ BatchedControllers, Controller, ControllerConfig, - make_controller, ) +from judo.controller.factory import make_controller from judo.controller.overrides import ( set_default_caltech_leap_cube_overrides, set_default_cartpole_overrides, diff --git a/judo/controller/controller.py b/judo/controller/controller.py index 6f2a5a6c..327d3aa5 100644 --- a/judo/controller/controller.py +++ b/judo/controller/controller.py @@ -7,15 +7,13 @@ import numpy as np from mujoco import MjData -from omegaconf import DictConfig from scipy.interpolate import interp1d -from judo.app.structs import MujocoState, SplineData -from judo.app.utils import register_optimizers_from_cfg, register_tasks_from_cfg from judo.config import OverridableConfig from judo.gui import slider -from judo.optimizers import Optimizer, OptimizerConfig, get_registered_optimizers -from judo.tasks import Task, TaskConfig, get_registered_tasks, get_task_registration +from judo.optimizers import Optimizer, OptimizerConfig +from judo.structs import MujocoState, SplineData +from judo.tasks import Task, TaskConfig from judo.tasks.spot.spot_constants import POLICY_OUTPUT_DIM from judo.utils.hierarchical_mj_rollout_backend import HierarchicalMJRolloutBackend from judo.utils.mj_rollout_backend import MJRolloutBackend @@ -75,10 +73,10 @@ def __init__( rollout_backend_registry: Optional mapping of backend names to backend classes. Overrides entries in DEFAULT_ROLLOUT_BACKEND_REGISTRY. rollout_backend_kwargs: Optional extra kwargs for rollout backend constructor. - For "mujoco_hierarchical" backend, 'physics_substeps' and 'policy_path' cannot be - specified here—they are sourced from the task and task registry respectively. - Raises ValueError if either is provided. To use different values, create or - update a task registry entry. + For "mujoco_hierarchical" backend, 'physics_substeps' cannot be specified here—it + is sourced from the task (raises ValueError if provided). 'policy_path' is required + and must be supplied here by the caller (e.g., the app resolves it from the task + registry's locomotion_policy_path). """ self._controller_cfg = controller_config self.task = task @@ -87,9 +85,6 @@ def __init__( self._rollout_backend_registry.update(rollout_backend_registry or {}) self._rollout_backend_kwargs = rollout_backend_kwargs or {} - self.available_optimizers = get_registered_optimizers() - self.available_tasks = get_registered_tasks() - self.model = self.task.model self.rollout_backend: RolloutBackend = self._make_rollout_backend( @@ -470,23 +465,14 @@ def _make_rollout_backend( ) final_kwargs["physics_substeps"] = self.task.physics_substeps - # policy_path is currently registry-owned for hierarchical backend wiring. - # This keeps policy/model assumptions centralized until hierarchical ONNX - # integration is generalized on the C++ side. - if "policy_path" in final_kwargs: - raise ValueError( - f"Cannot specify 'policy_path' in rollout_backend_kwargs. " - f"It must be defined in the task registry entry for '{self.task.name}'. " - f"To use a different policy path, create or update a task registry entry with the desired path." - ) - - task_policy_path = get_task_registration(self.task.name).locomotion_policy_path - if task_policy_path is None: + # policy_path must be supplied explicitly by the caller (e.g., the app resolves it + # from the task registry's locomotion_policy_path and passes it via rollout_backend_kwargs). + if final_kwargs.get("policy_path") is None: raise ValueError( f"Backend '{backend_name}' requires 'policy_path'. " - f"Task '{self.task.name}' must have a locomotion_policy_path registered in the task registry." + f"Provide it via rollout_backend_kwargs for task '{self.task.name}' " + f"(the app resolves it from the task registry's locomotion_policy_path)." ) - final_kwargs["policy_path"] = task_policy_path backend = backend_factory(**final_kwargs) if not isinstance(backend, RolloutBackend): @@ -728,65 +714,3 @@ def make_spline(times: np.ndarray, controls: np.ndarray, spline_order: str) -> i fill_value=fill_value, # interp1d is incorrectly typed # type: ignore bounds_error=False, ) - - -def make_controller( - init_task: str, - init_optimizer: str, - task_registration_cfg: DictConfig | None = None, - optimizer_registration_cfg: DictConfig | None = None, - controller_cls: type[Controller] | None = None, - **controller_kwargs: Any, -) -> Controller: - """Make a controller. - - Args: - init_task: The task name to use. - init_optimizer: The optimizer name to use. - task_registration_cfg: Optional task registration overrides keyed by task name. - Each entry must contain `task` and `config` import paths, and may also define - `rollout_backend`, `simulation_backend`, and `locomotion_policy_path`. - See register_tasks_from_cfg for the exact supported schema. - optimizer_registration_cfg: Optional optimizer registration overrides keyed by - optimizer name. Each entry must contain `optimizer` and `config` import paths. - See register_optimizers_from_cfg for the exact supported schema. - controller_cls: Optional controller class to instantiate instead of Controller. - **controller_kwargs: Additional keyword arguments forwarded to the controller - constructor. - - Returns: - The created Controller instance. - """ - available_optimizers = get_registered_optimizers() - available_tasks = get_registered_tasks() - if task_registration_cfg is not None: - register_tasks_from_cfg(task_registration_cfg) - if optimizer_registration_cfg is not None: - register_optimizers_from_cfg(optimizer_registration_cfg) - - task_entry = available_tasks.get(init_task) - optimizer_entry = available_optimizers.get(init_optimizer) - - assert task_entry is not None, f"Task {init_task} not found in task registry." - assert optimizer_entry is not None, f"Optimizer {init_optimizer} not found in optimizer registry." - task_registration = get_task_registration(init_task) - - # instantiate the task/optimizer/controller - task = task_entry.task_type() - - optimizer_cls, optimizer_config_cls = optimizer_entry - optimizer_cfg = optimizer_config_cls() - optimizer_cfg.set_override(init_task) - optimizer = optimizer_cls(optimizer_cfg, task.nu) - - controller_cfg = ControllerConfig() - controller_cfg.set_override(init_task) - - cls = controller_cls or Controller - return cls( - controller_config=controller_cfg, - task=task, - optimizer=optimizer, - rollout_backend=task_registration.rollout_backend, - **controller_kwargs, - ) diff --git a/judo/controller/factory.py b/judo/controller/factory.py new file mode 100644 index 00000000..ca755329 --- /dev/null +++ b/judo/controller/factory.py @@ -0,0 +1,95 @@ +# Copyright (c) 2025 Robotics and AI Institute LLC. All rights reserved. + +"""Registry-aware controller factory. + +The :class:`~judo.controller.controller.Controller` class itself is intentionally decoupled from +the task/optimizer registries (it receives its backend and locomotion policy explicitly). This +module provides :func:`make_controller`, a convenience factory that *reads* the registries to +resolve those values and then constructs a controller. It depends only on the registry +*mechanism* (``judo.tasks`` / ``judo.optimizers``), not on any particular set of registered tasks, +so it can be used equally by judo's own app and by third-party applications that register their +own tasks. +""" + +from typing import Any + +from omegaconf import DictConfig + +from judo.controller.controller import Controller, ControllerConfig +from judo.optimizers import get_registered_optimizers +from judo.registration import register_optimizers_from_cfg, register_tasks_from_cfg +from judo.tasks import get_registered_tasks, get_task_registration + + +def make_controller( + init_task: str, + init_optimizer: str, + task_registration_cfg: DictConfig | None = None, + optimizer_registration_cfg: DictConfig | None = None, + controller_cls: type[Controller] | None = None, + **controller_kwargs: Any, +) -> Controller: + """Make a controller. + + This factory reads the task/optimizer registries to resolve backends and the locomotion policy + path, then passes those to the (registry-agnostic) :class:`~judo.controller.Controller` + constructor explicitly. + + Args: + init_task: The task name to use. + init_optimizer: The optimizer name to use. + task_registration_cfg: Optional task registration overrides keyed by task name. + Each entry must contain `task` and `config` import paths, and may also define + `rollout_backend`, `simulation_backend`, and `locomotion_policy_path`. + See register_tasks_from_cfg for the exact supported schema. + optimizer_registration_cfg: Optional optimizer registration overrides keyed by + optimizer name. Each entry must contain `optimizer` and `config` import paths. + See register_optimizers_from_cfg for the exact supported schema. + controller_cls: Optional controller class to instantiate instead of Controller. + **controller_kwargs: Additional keyword arguments forwarded to the controller + constructor. + + Returns: + The created Controller instance. + """ + if task_registration_cfg is not None: + register_tasks_from_cfg(task_registration_cfg) + if optimizer_registration_cfg is not None: + register_optimizers_from_cfg(optimizer_registration_cfg) + + available_optimizers = get_registered_optimizers() + available_tasks = get_registered_tasks() + + task_entry = available_tasks.get(init_task) + optimizer_entry = available_optimizers.get(init_optimizer) + + assert task_entry is not None, f"Task {init_task} not found in task registry." + assert optimizer_entry is not None, f"Optimizer {init_optimizer} not found in optimizer registry." + task_registration = get_task_registration(init_task) + + # instantiate the task/optimizer/controller + task = task_entry.task_type() + + optimizer_cls, optimizer_config_cls = optimizer_entry + optimizer_cfg = optimizer_config_cls() + optimizer_cfg.set_override(init_task) + optimizer = optimizer_cls(optimizer_cfg, task.nu) + + controller_cfg = ControllerConfig() + controller_cfg.set_override(init_task) + + # Resolve the locomotion policy path from the registry and pass it explicitly to the + # controller so the Controller class itself stays decoupled from the task registry. + rollout_backend_kwargs = dict(controller_kwargs.pop("rollout_backend_kwargs", None) or {}) + if task_registration.locomotion_policy_path is not None: + rollout_backend_kwargs.setdefault("policy_path", task_registration.locomotion_policy_path) + + cls = controller_cls or Controller + return cls( + controller_config=controller_cfg, + task=task, + optimizer=optimizer, + rollout_backend=task_registration.rollout_backend, + rollout_backend_kwargs=rollout_backend_kwargs, + **controller_kwargs, + ) diff --git a/judo/examples/example_task.py b/judo/examples/example_task.py index 30a77a22..c55f6948 100644 --- a/judo/examples/example_task.py +++ b/judo/examples/example_task.py @@ -2,7 +2,7 @@ from dataclasses import dataclass -from judo.tasks import CylinderPush, CylinderPushConfig +from judo.tasks.cylinder_push import CylinderPush, CylinderPushConfig @dataclass diff --git a/mujoco_extensions/CMakeLists.txt b/judo/mujoco_extensions/CMakeLists.txt similarity index 97% rename from mujoco_extensions/CMakeLists.txt rename to judo/mujoco_extensions/CMakeLists.txt index d8e3a5e7..12cd6e9d 100644 --- a/mujoco_extensions/CMakeLists.txt +++ b/judo/mujoco_extensions/CMakeLists.txt @@ -121,8 +121,8 @@ target_link_libraries(policy_rollout_pybind PRIVATE ${MUJOCO_LIB} ) set_target_properties(policy_rollout_pybind PROPERTIES - BUILD_RPATH "$ORIGIN/../../mujoco" - INSTALL_RPATH "$ORIGIN/../../mujoco" + BUILD_RPATH "$ORIGIN/../../../mujoco" + INSTALL_RPATH "$ORIGIN/../../../mujoco" BUILD_RPATH_USE_ORIGIN TRUE LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/policy_rollout" ) diff --git a/mujoco_extensions/__init__.py b/judo/mujoco_extensions/__init__.py similarity index 68% rename from mujoco_extensions/__init__.py rename to judo/mujoco_extensions/__init__.py index 8c3458ba..aa6e78f2 100644 --- a/mujoco_extensions/__init__.py +++ b/judo/mujoco_extensions/__init__.py @@ -1,6 +1,6 @@ # Copyright (c) 2025 Robotics and AI Institute LLC. All rights reserved. -from mujoco_extensions import policy_rollout +from judo.mujoco_extensions import policy_rollout __all__ = [ "policy_rollout", diff --git a/mujoco_extensions/onnx_interface/onnx_interface.cpp b/judo/mujoco_extensions/onnx_interface/onnx_interface.cpp similarity index 100% rename from mujoco_extensions/onnx_interface/onnx_interface.cpp rename to judo/mujoco_extensions/onnx_interface/onnx_interface.cpp diff --git a/mujoco_extensions/onnx_interface/onnx_interface.h b/judo/mujoco_extensions/onnx_interface/onnx_interface.h similarity index 100% rename from mujoco_extensions/onnx_interface/onnx_interface.h rename to judo/mujoco_extensions/onnx_interface/onnx_interface.h diff --git a/mujoco_extensions/policy_rollout/__init__.py b/judo/mujoco_extensions/policy_rollout/__init__.py similarity index 73% rename from mujoco_extensions/policy_rollout/__init__.py rename to judo/mujoco_extensions/policy_rollout/__init__.py index fe70d7f8..1ad3c966 100644 --- a/mujoco_extensions/policy_rollout/__init__.py +++ b/judo/mujoco_extensions/policy_rollout/__init__.py @@ -1,6 +1,6 @@ # Copyright (c) 2025 Robotics and AI Institute LLC. All rights reserved. -from mujoco_extensions.policy_rollout.policy_rollout_pybind.policy_rollout import ( +from judo.mujoco_extensions.policy_rollout.policy_rollout_pybind.policy_rollout import ( System, create_systems_vector, set_state, diff --git a/judo/mujoco_extensions/policy_rollout/policy_rollout_pybind/__init__.pyi b/judo/mujoco_extensions/policy_rollout/policy_rollout_pybind/__init__.pyi new file mode 100644 index 00000000..40393b33 --- /dev/null +++ b/judo/mujoco_extensions/policy_rollout/policy_rollout_pybind/__init__.pyi @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Robotics and AI Institute LLC. All rights reserved. + +"""Type stubs for the compiled ``policy_rollout_pybind`` extension module. + +These stubs let type checkers resolve the C++ pybind11 module without requiring +the ``.so`` to be built (e.g. in lint-only CI jobs). Regenerate with:: + + pixi run stubgen-extension +""" + +from __future__ import annotations + +from . import policy_rollout + +__all__: list[str] = ["policy_rollout"] diff --git a/judo/mujoco_extensions/policy_rollout/policy_rollout_pybind/policy_rollout.pyi b/judo/mujoco_extensions/policy_rollout/policy_rollout_pybind/policy_rollout.pyi new file mode 100644 index 00000000..a88a1340 --- /dev/null +++ b/judo/mujoco_extensions/policy_rollout/policy_rollout_pybind/policy_rollout.pyi @@ -0,0 +1,68 @@ +# Copyright (c) 2025 Robotics and AI Institute LLC. All rights reserved. + +from __future__ import annotations + +import collections.abc +import typing + +import numpy +import numpy.typing + +__all__: list[str] = ["System", "create_systems_vector", "set_state", "threaded_rollout"] + +class System: + def __init__(self, model_filepath: str, policy_filepath: str) -> None: ... + def get_control(self) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: ... + def get_state(self) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: ... + def load_policy(self, arg0: str, arg1: typing.Any) -> None: ... + def policy_inference(self) -> None: ... + def reset(self, arg0: bool) -> None: ... + def rollout( + self, + state: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"], + command: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, n]"], + physics_substeps: typing.SupportsInt | typing.SupportsIndex = 2, + reset_last_output: bool = True, + cutoff_time: typing.SupportsFloat | typing.SupportsIndex = ..., + ) -> tuple[ + typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, n]"], + typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, n]"], + ]: ... + def set_observation( + self, command: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] + ) -> None: ... + @property + def observation(self) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: ... + @observation.setter + def observation( + self, arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] + ) -> None: ... + @property + def policy_output(self) -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]: ... + @policy_output.setter + def policy_output( + self, arg1: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] + ) -> None: ... + +def create_systems_vector( + model: typing.Any, policy_filepath: str, num_systems: typing.SupportsInt | typing.SupportsIndex +) -> list[System]: ... +def set_state( + system: System, state: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[m, 1]"] +) -> None: + """Sets the state of a system object""" + +def threaded_rollout( + systems: collections.abc.Sequence[System], + states: numpy.typing.ArrayLike, + command: numpy.typing.ArrayLike, + last_policy_output: numpy.typing.ArrayLike, + num_threads: typing.SupportsInt | typing.SupportsIndex, + physics_substeps: typing.SupportsInt | typing.SupportsIndex, + cutoff_time: typing.SupportsFloat | typing.SupportsIndex = ..., +) -> tuple[ + list[typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, n]"]], + list[typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, n]"]], + list[typing.Annotated[numpy.typing.NDArray[numpy.float64], "[m, 1]"]], +]: + """Threaded policy rollout with shared pointers to System objects.""" diff --git a/mujoco_extensions/policy_rollout/pybind/policy_rollout.cpp b/judo/mujoco_extensions/policy_rollout/pybind/policy_rollout.cpp similarity index 100% rename from mujoco_extensions/policy_rollout/pybind/policy_rollout.cpp rename to judo/mujoco_extensions/policy_rollout/pybind/policy_rollout.cpp diff --git a/mujoco_extensions/policy_rollout/pybind/pybind.cpp b/judo/mujoco_extensions/policy_rollout/pybind/pybind.cpp similarity index 100% rename from mujoco_extensions/policy_rollout/pybind/pybind.cpp rename to judo/mujoco_extensions/policy_rollout/pybind/pybind.cpp diff --git a/mujoco_extensions/system/eigen_types.h b/judo/mujoco_extensions/system/eigen_types.h similarity index 100% rename from mujoco_extensions/system/eigen_types.h rename to judo/mujoco_extensions/system/eigen_types.h diff --git a/mujoco_extensions/system/system_class.cpp b/judo/mujoco_extensions/system/system_class.cpp similarity index 100% rename from mujoco_extensions/system/system_class.cpp rename to judo/mujoco_extensions/system/system_class.cpp diff --git a/mujoco_extensions/system/system_class.h b/judo/mujoco_extensions/system/system_class.h similarity index 100% rename from mujoco_extensions/system/system_class.h rename to judo/mujoco_extensions/system/system_class.h diff --git a/mujoco_extensions/system/system_utils.cpp b/judo/mujoco_extensions/system/system_utils.cpp similarity index 100% rename from mujoco_extensions/system/system_utils.cpp rename to judo/mujoco_extensions/system/system_utils.cpp diff --git a/mujoco_extensions/system/system_utils.h b/judo/mujoco_extensions/system/system_utils.h similarity index 100% rename from mujoco_extensions/system/system_utils.h rename to judo/mujoco_extensions/system/system_utils.h diff --git a/judo/app/utils.py b/judo/registration.py similarity index 100% rename from judo/app/utils.py rename to judo/registration.py diff --git a/judo/simulation/__init__.py b/judo/simulation/__init__.py index cb16104d..a6b8cd2f 100644 --- a/judo/simulation/__init__.py +++ b/judo/simulation/__init__.py @@ -1,12 +1,25 @@ # Copyright (c) 2025 Robotics and AI Institute LLC. All rights reserved. from judo.simulation.base import Simulation -from judo.simulation.hierarchical_mj_simulation import HierarchicalMJSimulation from judo.simulation.mj_simulation import MJSimulation +# ``hierarchical_mj_simulation`` imports the ``judo.mujoco_extensions`` C++ pybind extension, which +# is only available once it has been built (``pixi run build``). Make the import optional so that +# third-party consumers using only the plain MuJoCo backend can ``import judo.simulation`` without +# building the extension. The hierarchical backend is registered only when it imports successfully; +# requesting it otherwise fails at registry lookup with a clear ``KeyError``. +try: + from judo.simulation.hierarchical_mj_simulation import HierarchicalMJSimulation + + _HIERARCHICAL_BACKEND: dict[str, type[Simulation]] = {"mujoco_hierarchical": HierarchicalMJSimulation} + _HIERARCHICAL_AVAILABLE = True +except ImportError: + _HIERARCHICAL_BACKEND = {} + _HIERARCHICAL_AVAILABLE = False + DEFAULT_SIMULATION_BACKEND_REGISTRY: dict[str, type[Simulation]] = { "mujoco": MJSimulation, - "mujoco_hierarchical": HierarchicalMJSimulation, + **_HIERARCHICAL_BACKEND, } @@ -27,7 +40,9 @@ def get_simulation_backend(simulation_backend: str) -> type: __all__ = [ "Simulation", "MJSimulation", - "HierarchicalMJSimulation", "DEFAULT_SIMULATION_BACKEND_REGISTRY", "get_simulation_backend", ] + +if _HIERARCHICAL_AVAILABLE: + __all__.append("HierarchicalMJSimulation") diff --git a/judo/simulation/base.py b/judo/simulation/base.py index bf9cbc77..beca7748 100644 --- a/judo/simulation/base.py +++ b/judo/simulation/base.py @@ -5,8 +5,8 @@ import numpy as np from omegaconf import DictConfig -from judo.app.structs import MujocoState, RenderPose -from judo.app.utils import register_tasks_from_cfg +from judo.registration import register_tasks_from_cfg +from judo.structs import MujocoState, RenderPose from judo.tasks import get_registered_tasks from judo.tasks.base import Task diff --git a/judo/simulation/hierarchical_mj_simulation.py b/judo/simulation/hierarchical_mj_simulation.py index 483e8f1f..e411a6a2 100644 --- a/judo/simulation/hierarchical_mj_simulation.py +++ b/judo/simulation/hierarchical_mj_simulation.py @@ -9,11 +9,10 @@ from omegaconf import DictConfig from judo.simulation.mj_simulation import MJSimulation -from judo.tasks import get_task_registration from judo.tasks.spot.spot_constants import DEFAULT_SPOT_ROLLOUT_CUTOFF_TIME, POLICY_OUTPUT_DIM try: - from mujoco_extensions.policy_rollout import create_systems_vector, threaded_rollout # type: ignore + from judo.mujoco_extensions.policy_rollout import create_systems_vector, threaded_rollout except ImportError as e: raise ImportError( "mujoco_extensions is not built. Spot locomotion tasks require the C++ extension.\n" @@ -37,26 +36,22 @@ def __init__( self, init_task: str = "spot_base", task_registration_cfg: DictConfig | None = None, + locomotion_policy_path: str | Path | None = None, ) -> None: """Initialize the hierarchical simulation. Args: init_task: Name of the task to initialize. task_registration_cfg: Optional task registration configuration. + locomotion_policy_path: Path to the ONNX low-level policy used by hierarchical tasks. + Must be provided for tasks that use a locomotion policy; it is supplied by the + caller (e.g., the app resolves it from the task registry) rather than looked up + here, keeping the simulation decoupled from the task registry. """ - super().__init__(init_task=init_task, task_registration_cfg=task_registration_cfg) - + self._locomotion_policy_path = locomotion_policy_path self._systems = None self._last_policy_output = np.zeros(POLICY_OUTPUT_DIM) - - # Initialize C++ systems if the task uses a hierarchical policy layer. - if self.task.uses_locomotion_policy: - policy_path = get_task_registration(self.task.name).locomotion_policy_path - if policy_path is None: - raise ValueError( - f"Task '{self.task.name}' uses locomotion policy but no locomotion_policy_path is registered." - ) - self._init_cpp_systems(policy_path) + super().__init__(init_task=init_task, task_registration_cfg=task_registration_cfg) def _init_cpp_systems(self, policy_path: str | Path) -> None: """Initialize the C++ systems vector for threaded rollout. @@ -105,6 +100,7 @@ def _step_with_hierarchical_policy(self, command: np.ndarray) -> None: # states: (num_threads, nq+nv) # commands: (num_threads, num_timesteps, cmd_dim) # last_outputs: (num_threads, POLICY_OUTPUT_DIM) + assert self._systems is not None # guaranteed by the caller's `_systems is not None` check states = np.array([state], dtype=np.float64) commands = np.array([[command]], dtype=np.float64) last_outputs = np.array([self._last_policy_output], dtype=np.float64) @@ -149,12 +145,11 @@ def set_task(self, task_name: str) -> None: # Reinitialize systems based on the new task's policy layer. if self.task.uses_locomotion_policy: - policy_path = get_task_registration(self.task.name).locomotion_policy_path - if policy_path is None: + if self._locomotion_policy_path is None: raise ValueError( - f"Task '{self.task.name}' uses locomotion policy but no locomotion_policy_path is registered." + f"Task '{self.task.name}' uses locomotion policy but no locomotion_policy_path was provided." ) - self._init_cpp_systems(policy_path) + self._init_cpp_systems(self._locomotion_policy_path) self._last_policy_output = np.zeros(POLICY_OUTPUT_DIM) else: raise ValueError( diff --git a/judo/app/structs.py b/judo/structs.py similarity index 100% rename from judo/app/structs.py rename to judo/structs.py diff --git a/judo/tasks/__init__.py b/judo/tasks/__init__.py index 30be02ad..9a8c233f 100644 --- a/judo/tasks/__init__.py +++ b/judo/tasks/__init__.py @@ -4,25 +4,6 @@ from typing import Dict, Type from judo.tasks.base import Task, TaskConfig -from judo.tasks.caltech_leap_cube import CaltechLeapCube, CaltechLeapCubeConfig -from judo.tasks.cartpole import Cartpole, CartpoleConfig -from judo.tasks.cylinder_push import CylinderPush, CylinderPushConfig -from judo.tasks.fr3_pick import FR3Pick, FR3PickConfig -from judo.tasks.leap_cube import LeapCube, LeapCubeConfig -from judo.tasks.leap_cube_down import LeapCubeDown, LeapCubeDownConfig -from judo.tasks.spot import ( - SpotBase, - SpotBaseConfig, - SpotBoxPush, - SpotBoxPushConfig, - SpotNavigate, - SpotNavigateConfig, - SpotTireRoll, - SpotTireRollConfig, - SpotTireUpright, - SpotTireUprightConfig, -) -from judo.tasks.spot.spot_constants import SPOT_LOCOMOTION_POLICY_PATH @dataclass(frozen=True) @@ -36,49 +17,11 @@ class TaskRegistration: locomotion_policy_path: str | None = None -_registered_tasks: Dict[str, TaskRegistration] = { - CylinderPush.name: TaskRegistration(CylinderPush, CylinderPushConfig), - Cartpole.name: TaskRegistration(Cartpole, CartpoleConfig), - FR3Pick.name: TaskRegistration(FR3Pick, FR3PickConfig), - LeapCube.name: TaskRegistration(LeapCube, LeapCubeConfig), - LeapCubeDown.name: TaskRegistration(LeapCubeDown, LeapCubeDownConfig), - CaltechLeapCube.name: TaskRegistration(CaltechLeapCube, CaltechLeapCubeConfig), - SpotBase.name: TaskRegistration( - SpotBase, - SpotBaseConfig, - rollout_backend="mujoco_hierarchical", - simulation_backend="mujoco_hierarchical", - locomotion_policy_path=str(SPOT_LOCOMOTION_POLICY_PATH), - ), - SpotBoxPush.name: TaskRegistration( - SpotBoxPush, - SpotBoxPushConfig, - rollout_backend="mujoco_hierarchical", - simulation_backend="mujoco_hierarchical", - locomotion_policy_path=str(SPOT_LOCOMOTION_POLICY_PATH), - ), - SpotNavigate.name: TaskRegistration( - SpotNavigate, - SpotNavigateConfig, - rollout_backend="mujoco_hierarchical", - simulation_backend="mujoco_hierarchical", - locomotion_policy_path=str(SPOT_LOCOMOTION_POLICY_PATH), - ), - SpotTireRoll.name: TaskRegistration( - SpotTireRoll, - SpotTireRollConfig, - rollout_backend="mujoco_hierarchical", - simulation_backend="mujoco_hierarchical", - locomotion_policy_path=str(SPOT_LOCOMOTION_POLICY_PATH), - ), - SpotTireUpright.name: TaskRegistration( - SpotTireUpright, - SpotTireUprightConfig, - rollout_backend="mujoco_hierarchical", - simulation_backend="mujoco_hierarchical", - locomotion_policy_path=str(SPOT_LOCOMOTION_POLICY_PATH), - ), -} +# The registry is intentionally empty by default. Concrete tasks (and their backends / +# locomotion policies) are registered at the application level so that this library can be +# consumed by third-party packages without pulling in judo's built-in task set. Judo's own +# default tasks are registered in ``judo.app`` (see ``judo.app.register_default_tasks``). +_registered_tasks: Dict[str, TaskRegistration] = {} def get_registered_tasks() -> Dict[str, TaskRegistration]: @@ -119,26 +62,4 @@ def register_task( "TaskRegistration", "Task", "TaskConfig", - "CaltechLeapCube", - "CaltechLeapCubeConfig", - "Cartpole", - "CartpoleConfig", - "CylinderPush", - "CylinderPushConfig", - "FR3Pick", - "FR3PickConfig", - "LeapCube", - "LeapCubeConfig", - "LeapCubeDown", - "LeapCubeDownConfig", - "SpotBase", - "SpotBaseConfig", - "SpotBoxPush", - "SpotBoxPushConfig", - "SpotNavigate", - "SpotNavigateConfig", - "SpotTireRoll", - "SpotTireRollConfig", - "SpotTireUpright", - "SpotTireUprightConfig", ] diff --git a/judo/utils/assets.py b/judo/utils/assets.py index f9fcb3c9..d38bc618 100644 --- a/judo/utils/assets.py +++ b/judo/utils/assets.py @@ -7,6 +7,20 @@ import requests +_TRUTHY_ENV_VALUES = {"1", "true", "yes", "on"} + + +def mesh_downloads_disabled() -> bool: + """Return whether judo should skip downloading mesh assets from GitHub releases. + + Network downloads are enabled by default. Third-party or offline deployments (e.g. air-gapped + robots, hermetic build systems that vendor meshes themselves) can opt out by setting the + ``JUDO_OFFLINE`` environment variable to a truthy value (``1``, ``true``, ``yes``, ``on``). + When disabled, :func:`download_and_extract_meshes` becomes a no-op and callers are expected to + provide the meshes through other means (e.g. a copy already present on disk). + """ + return os.environ.get("JUDO_OFFLINE", "").strip().lower() in _TRUTHY_ENV_VALUES + def acquire_lock(lock_path: Path, timeout: int = 60, poll_interval: float = 0.1) -> None: """Acquire a lock by creating a lock file atomically. @@ -39,7 +53,15 @@ def download_and_extract_meshes( asset_name: str = "meshes.zip", tag: str | None = None, ) -> None: - """Downloads meshes.zip from the latest public GitHub release and extracts it.""" + """Downloads meshes.zip from the latest public GitHub release and extracts it. + + This is a no-op when mesh downloads are disabled via the ``JUDO_OFFLINE`` environment variable + (see :func:`mesh_downloads_disabled`), allowing offline/third-party deployments to supply their + own meshes without any network access. + """ + if mesh_downloads_disabled(): + return + extract_path = Path(extract_root).expanduser() meshes_path = extract_path / "meshes" lock_path = extract_path / ".meshes_download.lock" diff --git a/judo/utils/hierarchical_mj_rollout_backend.py b/judo/utils/hierarchical_mj_rollout_backend.py index fc216d72..2f198d8d 100644 --- a/judo/utils/hierarchical_mj_rollout_backend.py +++ b/judo/utils/hierarchical_mj_rollout_backend.py @@ -43,7 +43,7 @@ def __init__( def _setup_mujoco_extensions(self, model: MjModel, policy_path: str | Path, num_threads: int) -> None: """Setup the mujoco_extensions C++ rollout backend with ONNX low-level policy.""" try: - from mujoco_extensions.policy_rollout import create_systems_vector, threaded_rollout # type: ignore # noqa: PLC0415, I001 + from judo.mujoco_extensions.policy_rollout import create_systems_vector, threaded_rollout # noqa: PLC0415, I001 except ImportError as e: raise ImportError("mujoco_extensions is required. Build with: pixi run build") from e diff --git a/judo/visualizers/visualizer.py b/judo/visualizers/visualizer.py index d69e1c3a..f5c65b19 100644 --- a/judo/visualizers/visualizer.py +++ b/judo/visualizers/visualizer.py @@ -10,11 +10,11 @@ from viser import GuiFolderHandle, GuiImageHandle, GuiInputHandle, IcosphereHandle, MeshHandle from judo import PACKAGE_ROOT -from judo.app.utils import register_optimizers_from_cfg, register_tasks_from_cfg from judo.config import set_config_overrides from judo.controller import ControllerConfig from judo.gui import create_gui_elements from judo.optimizers import get_registered_optimizers +from judo.registration import register_optimizers_from_cfg, register_tasks_from_cfg from judo.tasks import TaskRegistration, get_registered_tasks from judo.visualizers.model import ViserMjModel @@ -332,17 +332,30 @@ def _(_: viser.GuiEvent) -> None: with self.task_lock: self.set_task(self.task_name, self.optimizer_name) + @staticmethod + def _is_removed(handle: object) -> bool: + """Return True if a viser handle has already been removed. + + Different viser handle types track removal differently: GUI/scene handles expose + ``_impl.removed`` while tab handles expose ``_removed``. This guards against + double-removal warnings (e.g. removing a tab group already removes its child tabs). + """ + if getattr(handle, "_removed", False): + return True + impl = getattr(handle, "_impl", None) + return bool(getattr(impl, "removed", False)) + def remove_handles(self, handles: list[ElementType] | ElementType) -> None: """Remove GUI handles from the visualization node.""" if isinstance(handles, ElementType): - if not handles._impl.removed: + if not self._is_removed(handles): handles.remove() else: assert isinstance(handles, list), "handles must be a list or a single handle." for handle in handles: if isinstance(handle, list): self.remove_handles(handle) - elif not handle._impl.removed: + elif not self._is_removed(handle): handle.remove() def _remove_gui_elements(self) -> None: @@ -351,7 +364,7 @@ def _remove_gui_elements(self) -> None: if isinstance(v, list): for handle in v: self.remove_handles(handle) - else: + elif not self._is_removed(v): v.remove() self.viser_model.remove() diff --git a/pixi.lock b/pixi.lock index 3b92f5fe..6cc9a1de 100644 --- a/pixi.lock +++ b/pixi.lock @@ -5,13 +5,15 @@ environments: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.3.2-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-hc65338a_0.conda @@ -37,13 +39,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.4.0-h2a15e64_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.4.0-h6963c3b_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onnxruntime-cpp-1.19.2-h641f3bf_0_cpu.conda @@ -133,10 +135,11 @@ environments: - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.3.2-h8cb302d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-5.0.1-h44d0d2d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.4-h55c6f16_0.conda @@ -147,9 +150,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/onnxruntime-cpp-1.19.2-hda9e549_0_cpu.conda @@ -339,13 +342,15 @@ environments: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.3.2-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-hc65338a_0.conda @@ -358,6 +363,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-h018ffa1_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -371,15 +380,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.4.0-h2a15e64_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.4.0-h6963c3b_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-26.6.0-hc039f44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onnxruntime-cpp-1.19.2-h641f3bf_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda @@ -533,11 +543,16 @@ environments: - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.3.2-h8cb302d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-5.0.1-h44d0d2d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260526.0-cxx17_h4c27e2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.2.0-h1dcdb26_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.2.0-h5295a6a_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.2.0-h2ddc9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.4-h55c6f16_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda @@ -547,11 +562,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-26.6.0-h00e74ec_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/onnxruntime-cpp-1.19.2-hda9e549_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -711,6 +727,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/nodejs-26.6.0-h80d1838_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/onnxruntime-cpp-1.19.2-h50ebc8d_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.2-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -864,13 +881,15 @@ environments: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.3.2-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-hc65338a_0.conda @@ -883,6 +902,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-h018ffa1_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -896,15 +919,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.4.0-h2a15e64_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.4.0-h6963c3b_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-26.6.0-hc039f44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onnxruntime-cpp-1.19.2-h641f3bf_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda @@ -1065,11 +1089,16 @@ environments: - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.3.2-h8cb302d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-5.0.1-h44d0d2d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260526.0-cxx17_h4c27e2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.2.0-h1dcdb26_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.2.0-h5295a6a_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.2.0-h2ddc9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.4-h55c6f16_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda @@ -1079,11 +1108,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-26.6.0-h00e74ec_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/onnxruntime-cpp-1.19.2-hda9e549_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -1243,6 +1273,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/nodejs-26.6.0-h80d1838_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/onnxruntime-cpp-1.19.2-h50ebc8d_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.2-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -1396,13 +1427,15 @@ environments: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.3.2-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-hc65338a_0.conda @@ -1428,13 +1461,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.4.0-h2a15e64_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.4.0-h6963c3b_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onnxruntime-cpp-1.19.2-h641f3bf_0_cpu.conda @@ -1550,10 +1583,11 @@ environments: - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.3.2-h8cb302d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-5.0.1-h44d0d2d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.4-h55c6f16_0.conda @@ -1564,9 +1598,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/onnxruntime-cpp-1.19.2-hda9e549_0_cpu.conda @@ -1808,13 +1842,15 @@ environments: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.3.2-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-hc65338a_0.conda @@ -1840,13 +1876,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.4.0-h2a15e64_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.4.0-h6963c3b_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onnxruntime-cpp-1.19.2-h641f3bf_0_cpu.conda @@ -1943,10 +1979,11 @@ environments: - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.3.2-h8cb302d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-5.0.1-h44d0d2d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.4-h55c6f16_0.conda @@ -1957,9 +1994,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/onnxruntime-cpp-1.19.2-hda9e549_0_cpu.conda @@ -2149,13 +2186,15 @@ environments: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.3.2-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-hc65338a_0.conda @@ -2168,6 +2207,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-h018ffa1_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -2181,16 +2224,17 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.4.0-h2a15e64_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.4.0-h6963c3b_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-26.6.0-hc039f44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onnxruntime-cpp-1.19.2-h641f3bf_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda @@ -2347,11 +2391,16 @@ environments: - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.3.2-h8cb302d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-5.0.1-h44d0d2d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260526.0-cxx17_h4c27e2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.2.0-h1dcdb26_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.2.0-h5295a6a_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.2.0-h2ddc9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.4-h55c6f16_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda @@ -2360,11 +2409,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-26.6.0-h00e74ec_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/onnxruntime-cpp-1.19.2-hda9e549_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -2526,6 +2576,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/nodejs-26.6.0-h80d1838_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/onnxruntime-cpp-1.19.2-h50ebc8d_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.2-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -2682,13 +2733,15 @@ environments: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.3.2-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-hc65338a_0.conda @@ -2701,6 +2754,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-h018ffa1_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -2714,16 +2771,17 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.4.0-h2a15e64_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.4.0-h6963c3b_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-26.6.0-hc039f44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onnxruntime-cpp-1.19.2-h641f3bf_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda @@ -2878,11 +2936,16 @@ environments: - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.3.2-h8cb302d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-5.0.1-h44d0d2d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260526.0-cxx17_h4c27e2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.2.0-h1dcdb26_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.2.0-h5295a6a_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.2.0-h2ddc9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.4-h55c6f16_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda @@ -2891,11 +2954,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-26.6.0-h00e74ec_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/onnxruntime-cpp-1.19.2-hda9e549_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -3055,6 +3119,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/nodejs-26.6.0-h80d1838_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/onnxruntime-cpp-1.19.2-h50ebc8d_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.2-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -3209,13 +3274,15 @@ environments: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.3.2-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-hc65338a_0.conda @@ -3228,6 +3295,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-h018ffa1_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -3241,16 +3312,17 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.4.0-h2a15e64_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.4.0-h6963c3b_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-26.6.0-hc039f44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onnxruntime-cpp-1.19.2-h641f3bf_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda @@ -3403,11 +3475,16 @@ environments: - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.3.2-h8cb302d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-5.0.1-h44d0d2d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260526.0-cxx17_h4c27e2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.2.0-h1dcdb26_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.2.0-h5295a6a_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.2.0-h2ddc9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.4-h55c6f16_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda @@ -3416,11 +3493,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-26.6.0-h00e74ec_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/onnxruntime-cpp-1.19.2-hda9e549_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -3578,6 +3656,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/nodejs-26.6.0-h80d1838_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/onnxruntime-cpp-1.19.2-h50ebc8d_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.2-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -3730,13 +3809,15 @@ environments: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.3.2-hc85cc9f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-hc65338a_0.conda @@ -3749,6 +3830,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-h018ffa1_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda @@ -3762,15 +3847,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.4.0-h2a15e64_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.4.0-h6963c3b_118.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-26.6.0-hc039f44_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onnxruntime-cpp-1.19.2-h641f3bf_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda @@ -3924,11 +4010,16 @@ environments: - pypi: ./ osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.3.2-h8cb302d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/eigen-5.0.1-h44d0d2d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260526.0-cxx17_h4c27e2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.2.0-h1dcdb26_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.2.0-h5295a6a_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.2.0-h2ddc9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.4-h55c6f16_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda @@ -3938,11 +4029,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-26.6.0-h00e74ec_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/onnxruntime-cpp-1.19.2-hda9e549_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -4102,6 +4194,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/nodejs-26.6.0-h80d1838_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/onnxruntime-cpp-1.19.2-h50ebc8d_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.2-hf411b9b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda @@ -4442,27 +4535,27 @@ packages: purls: [] size: 56115 timestamp: 1771350256444 -- conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda - sha256: cc9accf72fa028d31c2a038460787751127317dcfa991f8d1f1babf216bb454e - md5: 920bb03579f15389b9e512095ad995b7 +- conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda + sha256: 9c37cc233238adf366ea75b0e845662a5be07ceadf62e458183516369340274b + md5: 3ad2b403be8fc5612b9159e2ce621f69 depends: + - libgcc >=15 - __glibc >=2.17,<3.0.a0 - - libgcc >=14 license: MIT license_family: MIT purls: [] - size: 207882 - timestamp: 1765214722852 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda - sha256: 2995f2aed4e53725e5efbc28199b46bf311c3cab2648fc4f10c2227d6d5fa196 - md5: bcb3cba70cf1eec964a03b4ba7775f01 + size: 228700 + timestamp: 1787169971173 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda + sha256: 82bdd5a3fcada6afef6255a9bf41172f07b362f36e04a354dc2abc0a29bfb756 + md5: 4cc01a374215de38387d45e19c8c5c9c depends: - __osx >=11.0 license: MIT license_family: MIT purls: [] - size: 180327 - timestamp: 1765215064054 + size: 197819 + timestamp: 1787169996553 - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-h4c7d964_0.conda sha256: 6f4ff81534c19e76acf52fcabf4a258088a932b8f1ac56e9a59e98f6051f8e46 md5: 56fb2c6c73efc627b40c77d14caecfba @@ -5484,6 +5577,16 @@ packages: purls: [] size: 12723451 timestamp: 1773822285671 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda + sha256: 6cdb5dee54c72e56ab189fb3ad33cb28533553d42590e7e831160248f4416a43 + md5: a5efc0b42bb8b42e97d0a29ae3e3c187 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 14070242 + timestamp: 1786545847761 - pypi: https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl name: id version: 1.6.1 @@ -5753,7 +5856,7 @@ packages: - pypi: ./ name: judo-rai version: 0.1.0 - sha256: 757fc34870fd4ae6ce9811e5a5f578d10323e408cf86342e87bcf789f1ddd5c5 + sha256: 1c59c1edde8ca14aa4b327c3186888d80567d0d621f5229b23b0e25d95b3c78f requires_dist: - dora-utils - h5py @@ -5787,7 +5890,6 @@ packages: - twine ; extra == 'dev' - wheel ; extra == 'dev' requires_python: '>=3.10' - editable: true - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda sha256: 41557eeadf641de6aeae49486cef30d02a6912d8da98585d687894afd65b356a md5: 86d9cba083cd041bfbf242a01a7a1999 @@ -5894,6 +5996,102 @@ packages: purls: [] size: 728002 timestamp: 1774197446916 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + sha256: 7bb3d495411b7059e85225aae500d84e7846a4bb02ebd77e4450200b20c180f0 + md5: 6983bfe8e09992014b9cf393769c7a84 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + constrains: + - abseil-cpp =20260526.0 + - libabseil-static =20260526.0=cxx17* + license: Apache-2.0 + license_family: Apache + purls: [] + size: 1436888 + timestamp: 1787217011773 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260526.0-cxx17_h4c27e2a_2.conda + sha256: d9c62dae9d8f5bebadf72fcf369c00cc353183cb2521f9fffbf4c2f70b58bef9 + md5: 2aa5e7dc7b5d218908effd2a8c70a8a8 + depends: + - __osx >=11.0 + - libcxx >=19 + constrains: + - abseil-cpp =20260526.0 + - libabseil-static =20260526.0=cxx17* + license: Apache-2.0 + license_family: Apache + purls: [] + size: 1277537 + timestamp: 1787217005681 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_3.conda + sha256: e5864f257f839ffc27d681659bac95901f524f602b9121e5dcc5e2df18437f2d + md5: 7a2499a177753582fb7ae7e9dc4a908a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + license: MIT + license_family: MIT + purls: [] + size: 80265 + timestamp: 1786622773969 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.2.0-h1dcdb26_3.conda + sha256: 5e62b856b2e77ce98db44133bacab1281b42c1040dcbd69dbacfb80890cff5b0 + md5: b457450ba3f27c4749783c0204bd17b0 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 80027 + timestamp: 1786622846050 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_3.conda + sha256: dad31b6d104973deb89710929a35651033aad692d4e7793cdb5b786a9bd54678 + md5: 6ab3315dc56618d652c1da42a648a129 + depends: + - __glibc >=2.17,<3.0.a0 + - libbrotlicommon 1.2.0 h39a168f_3 + - libgcc >=15 + license: MIT + license_family: MIT + purls: [] + size: 34828 + timestamp: 1786622783405 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.2.0-h5295a6a_3.conda + sha256: 510c9fce0d9ffcf41741dd96fc05db381672109d5665ef002c2e58f0d4ca0118 + md5: e07a99c6fdd984f4d588060f2f936bf4 + depends: + - __osx >=11.0 + - libbrotlicommon 1.2.0 h1dcdb26_3 + license: MIT + license_family: MIT + purls: [] + size: 29935 + timestamp: 1786622857695 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-h018ffa1_3.conda + sha256: d37124d0f51816e7d5e3a94bfc9ed3d6174d077f9b4f832d20c5a08b52bebf1f + md5: 2ac965638d4c6b2b38383bb1aebaf543 + depends: + - __glibc >=2.17,<3.0.a0 + - libbrotlicommon 1.2.0 h39a168f_3 + - libgcc >=15 + license: MIT + license_family: MIT + purls: [] + size: 298639 + timestamp: 1786622792145 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.2.0-h2ddc9cb_3.conda + sha256: eac412417eee2e93c62e9d53559f1f9c14f40b6c41e2c432af8b517596898dd1 + md5: 954c78a9f591bfb12c79beaff7338ec8 + depends: + - __osx >=11.0 + - libbrotlicommon 1.2.0 h1dcdb26_3 + license: MIT + license_family: MIT + purls: [] + size: 295650 + timestamp: 1786622868044 - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda sha256: a0390fd0536ebcd2244e243f5f00ab8e76ab62ed9aa214cd54470fe7496620f4 md5: d50608c443a30c341c24277d28290f76 @@ -6236,28 +6434,29 @@ packages: purls: [] size: 6591860 timestamp: 1771377400521 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.0-hf4e2dac_0.conda - sha256: ec37c79f737933bbac965f5dc0f08ef2790247129a84bb3114fad4900adce401 - md5: 810d83373448da85c3f673fbcb7ad3a3 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda + sha256: f20d70da54e5b31dd4a51fb1efeaafafd5ab6dd8d7ac9d1438eaa2526ac4ed3d + md5: e72bbec309c2b0f37823ee7d4fabfcd3 depends: - __glibc >=2.17,<3.0.a0 - icu >=78.3,<79.0a0 - - libgcc >=14 + - libgcc >=15 - libzlib >=1.3.2,<2.0a0 license: blessing purls: [] - size: 958864 - timestamp: 1775753750179 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.0-h1b79a29_0.conda - sha256: 1a9d1e3e18dbb0b87cff3b40c3e42703730d7ac7ee9b9322c2682196a81ba0c3 - md5: 8423c008105df35485e184066cad4566 + size: 974348 + timestamp: 1787051145557 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-hca69786_1.conda + sha256: 839b31d4830e896b4d315b551d27f2bb08026bc946df04bcc360d8627c3ba2cd + md5: fde96d40ebe9a9cb34e4122380189ddb depends: - __osx >=11.0 + - icu >=78.3,<79.0a0 - libzlib >=1.3.2,<2.0a0 license: blessing purls: [] - size: 920039 - timestamp: 1775754485962 + size: 942754 + timestamp: 1787051243846 - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.53.0-hf5d6505_0.conda sha256: 7a6256ea136936df4c4f3b227ba1e273b7d61152f9811b52157af497f07640b0 md5: 4152b5a8d2513fd7ae9fb9f221a5595d @@ -6351,27 +6550,27 @@ packages: purls: [] size: 40297 timestamp: 1775052476770 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda - sha256: c180f4124a889ac343fc59d15558e93667d894a966ec6fdb61da1604481be26b - md5: 0f03292cc56bf91a077a134ea8747118 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda + sha256: 67761d0206f84140047a367eaf9befe03a7e157a29ee25aee0047b40801cc6b6 + md5: 01c4ed87826af55996768af6dbc936b4 depends: - - __glibc >=2.17,<3.0.a0 - libgcc >=14 + - __glibc >=2.17,<3.0.a0 license: MIT license_family: MIT purls: [] - size: 895108 - timestamp: 1753948278280 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda - sha256: 042c7488ad97a5629ec0a991a8b2a3345599401ecc75ad6a5af73b60e6db9689 - md5: c0d87c3c8e075daf1daf6c31b53e8083 + size: 420040 + timestamp: 1785914567661 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.52.1-h1a92334_1.conda + sha256: 4f47de9de1990efd998edbbd6793f89c8f02ffde987ae8120b1c006acefd2a04 + md5: de09bd0f175611e94f21b28f8c708e80 depends: - __osx >=11.0 license: MIT license_family: MIT purls: [] - size: 421195 - timestamp: 1753948426421 + size: 122729 + timestamp: 1785914645797 - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda sha256: f03dc82e6fb1725788e73ae97f0cd3d820d5af0d351a274104a0767035444c59 md5: 31e1545994c48efc3e6ea32ca02a8724 @@ -7408,6 +7607,63 @@ packages: version: 1.10.0 sha256: 5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827 requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*' +- conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-26.6.0-hc039f44_0.conda + sha256: 049788cee5e10fe13846f806d8ae854642414aeb06018ad268ce9959b529be77 + md5: c99a655b4c729eef64e63140962b8cc9 + depends: + - __glibc >=2.28,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + - libuv >=1.52.1,<2.0a0 + - libabseil >=20260526.0,<20260527.0a0 + - libabseil * cxx17* + - zstd >=1.5.7,<1.6.0a0 + - libsqlite >=3.53.4,<4.0a0 + - icu >=78.3,<79.0a0 + - openssl >=3.5.7,<4.0a0 + - libnghttp2 >=1.68.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - libbrotlicommon >=1.2.0,<1.3.0a0 + - libbrotlienc >=1.2.0,<1.3.0a0 + - libbrotlidec >=1.2.0,<1.3.0a0 + - c-ares >=1.34.8,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 20013853 + timestamp: 1785852655297 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-26.6.0-h00e74ec_0.conda + sha256: 379ba26eb11cccb4d9a10989d9afef3f8bc4c9039cbe371dec3e3ee24594597b + md5: f0ba635c2293dff6fb86fc2150c8c110 + depends: + - libcxx >=19 + - __osx >=12.0 + - libnghttp2 >=1.68.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - libbrotlicommon >=1.2.0,<1.3.0a0 + - libbrotlienc >=1.2.0,<1.3.0a0 + - libbrotlidec >=1.2.0,<1.3.0a0 + - libuv >=1.52.1,<2.0a0 + - icu >=78.3,<79.0a0 + - openssl >=3.5.7,<4.0a0 + - libabseil >=20260526.0,<20260527.0a0 + - libabseil * cxx17* + - zstd >=1.5.7,<1.6.0a0 + - c-ares >=1.34.8,<2.0a0 + - libsqlite >=3.53.4,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 18228083 + timestamp: 1785852758781 +- conda: https://conda.anaconda.org/conda-forge/win-64/nodejs-26.6.0-h80d1838_0.conda + sha256: 8209fff36e34d2dc47ab37f879cb596059b3e6d58307fccefe7b9d79935492f3 + md5: a375968cb2cf4a5b745c875b26d40b05 + license: MIT + license_family: MIT + purls: [] + size: 34057372 + timestamp: 1785852767251 - pypi: https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl name: numpy version: 2.2.6 diff --git a/pyproject.toml b/pyproject.toml index 8307723f..a24af558 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,18 +56,18 @@ run_mpc = "run_mpc.cli:main" allow-direct-references = true [tool.hatch.build.targets.wheel] -packages = ["judo", "mujoco_extensions", "run_mpc"] -artifacts = ["mujoco_extensions/**/policy_rollout_pybind*.so", "judo/app/asset/*"] +packages = ["judo", "run_mpc"] +artifacts = ["judo/mujoco_extensions/**/policy_rollout_pybind*.so", "judo/app/asset/*"] exclude = [ "judo/models/meshes", - "mujoco_extensions/build", - "mujoco_extensions/system", - "mujoco_extensions/onnx_interface", - "mujoco_extensions/example", - "mujoco_extensions/test", - "mujoco_extensions/CMakeLists.txt", - "mujoco_extensions/policy_rollout/pybind", - "mujoco_extensions/policy_rollout/test", + "judo/mujoco_extensions/build", + "judo/mujoco_extensions/system", + "judo/mujoco_extensions/onnx_interface", + "judo/mujoco_extensions/example", + "judo/mujoco_extensions/test", + "judo/mujoco_extensions/CMakeLists.txt", + "judo/mujoco_extensions/policy_rollout/pybind", + "judo/mujoco_extensions/policy_rollout/test", ] [project.optional-dependencies] @@ -114,6 +114,9 @@ stubPath = "typings" reportMissingTypeStubs = false reportPrivateImportUsage = false +# The mujoco_extensions C++ module is type-checked via committed .pyi stubs; its compiled +# .so is built separately (pixi run build) and is absent in lint-only environments. +reportMissingModuleSource = false pythonVersion = "3.13" @@ -150,7 +153,7 @@ exclude=[ "site-packages", "venv", "docs", - "mujoco_extensions", + "judo/mujoco_extensions", ] [tool.ruff.lint] @@ -214,9 +217,10 @@ judo-rai = { path = ".", editable = true } [tool.pixi.tasks] # Build mujoco_extensions C++ module -configure = { cmd = "cmake -B mujoco_extensions/build -S mujoco_extensions", description = "Configure mujoco_extensions cmake build" } -build = { cmd = "cmake --build mujoco_extensions/build -j8", depends-on = ["configure"], description = "Build mujoco_extensions pybind modules" } -clean = { cmd = "rm -rf mujoco_extensions/build mujoco_extensions/policy_rollout/*.so", description = "Clean mujoco_extensions build artifacts" } +configure = { cmd = "cmake -B judo/mujoco_extensions/build -S judo/mujoco_extensions", description = "Configure mujoco_extensions cmake build" } +build = { cmd = "cmake --build judo/mujoco_extensions/build -j8", depends-on = ["configure"], description = "Build mujoco_extensions pybind modules" } +clean = { cmd = "rm -rf judo/mujoco_extensions/build judo/mujoco_extensions/policy_rollout/*.so", description = "Clean mujoco_extensions build artifacts" } +stubgen-extension = { cmd = "python -m pybind11_stubgen policy_rollout_pybind -o .", cwd = "judo/mujoco_extensions/policy_rollout", depends-on = ["build"], description = "Regenerate .pyi type stubs for the policy_rollout_pybind C++ module (review output for C++ leaks afterwards)" } upload-meshes = { cmd = "bash scripts/upload_meshes.sh", description = "Zip and upload meshes to latest GitHub release" } build-wheel = { cmd = "rm -rf dist && python -m build --wheel --outdir dist && bash scripts/repair_wheel.sh dist/*.whl wheelhouse \"\" $(python -c \"import sys; print(f'cp{sys.version_info[0]}{sys.version_info[1]}')\")", depends-on = ["clean", "build"], description = "Build manylinux wheel with auditwheel" } run_mpc = { cmd = "run_mpc", description = "Run batched MPC (pass args after --)" } @@ -225,6 +229,9 @@ run_mpc = { cmd = "run_mpc", description = "Run batched MPC (pass args after --) LD_LIBRARY_PATH = "$CONDA_PREFIX/lib:$LD_LIBRARY_PATH" PYTHONNOUSERSITE = "1" +[tool.pixi.feature.dev.dependencies] +nodejs = ">=18" # pyright needs a modern Node.js (system node may be too old to parse its bundled JS) + [tool.pixi.feature.py310.dependencies] python = "3.10.*" [tool.pixi.feature.py311.dependencies] diff --git a/run_mpc/__init__.py b/run_mpc/__init__.py index 4d3e2daf..1a3f0754 100644 --- a/run_mpc/__init__.py +++ b/run_mpc/__init__.py @@ -1 +1,5 @@ # Copyright (c) 2025 Robotics and AI Institute LLC. All rights reserved. + +# Importing the judo application layer registers judo's built-in tasks (and their backends / +# locomotion policies) in the task registry, which run_mpc relies on when loading configs. +import judo.app # noqa: F401 diff --git a/run_mpc/mpc_batch.py b/run_mpc/mpc_batch.py index 5cca2856..5743673b 100644 --- a/run_mpc/mpc_batch.py +++ b/run_mpc/mpc_batch.py @@ -9,11 +9,11 @@ import numpy as np from tqdm import tqdm -from judo.app.structs import RenderPose from judo.controller import BatchedControllers as JudoBatchedController from judo.controller import Controller as JudoController from judo.simulation.hierarchical_mj_simulation import HierarchicalMJSimulation from judo.simulation.mj_simulation import MJSimulation +from judo.structs import RenderPose from judo.visualizers.visualizer import Visualizer from run_mpc.mpc_config import MPCTimers, PublicMPCConfig, SizeData diff --git a/run_mpc/mpc_setup.py b/run_mpc/mpc_setup.py index f3b5b856..651d2aab 100644 --- a/run_mpc/mpc_setup.py +++ b/run_mpc/mpc_setup.py @@ -58,7 +58,7 @@ def setup_mpc( for _ in range(num_parallel): if use_spot: - sim = HierarchicalMJSimulation(init_task=json_configs["task"]) + sim = HierarchicalMJSimulation(init_task=json_configs["task"], locomotion_policy_path=policy_path) else: sim = MJSimulation(init_task=json_configs["task"]) sim.task.config = copy.deepcopy(task.config) diff --git a/tests/conftest.py b/tests/conftest.py index a7cfd6d7..fcb4b1bc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,6 +8,8 @@ import numpy as np import pytest +import judo.app # noqa: F401 # registers judo's built-in tasks in the task registry + @pytest.fixture(scope="session") def temp_np_seed() -> Callable[[int], contextlib._GeneratorContextManager[None]]: diff --git a/tests/test_controller/test_controller.py b/tests/test_controller/test_controller.py index b43765e6..d8290bcf 100644 --- a/tests/test_controller/test_controller.py +++ b/tests/test_controller/test_controller.py @@ -6,7 +6,7 @@ from judo.controller import Controller, ControllerConfig, make_controller from judo.optimizers import Optimizer, OptimizerConfig, get_registered_optimizers -from judo.tasks import CylinderPush +from judo.tasks.cylinder_push import CylinderPush # ##### # # MOCKS # diff --git a/tests/test_simulation/test_simulation.py b/tests/test_simulation/test_simulation.py index 5254de27..1729ded6 100644 --- a/tests/test_simulation/test_simulation.py +++ b/tests/test_simulation/test_simulation.py @@ -43,7 +43,8 @@ def test_simulation_data_step(temp_np_seed: Callable) -> None: def test_spot_simulation_init() -> None: """Test HierarchicalMJSimulation initializes with a Spot task and C++ systems.""" - sim = HierarchicalMJSimulation(init_task="spot_base") + policy_path = get_task_registration("spot_base").locomotion_policy_path + sim = HierarchicalMJSimulation(init_task="spot_base", locomotion_policy_path=policy_path) assert sim._systems is not None assert sim.task.uses_locomotion_policy assert get_task_registration(sim.task.name).locomotion_policy_path is not None @@ -51,7 +52,8 @@ def test_spot_simulation_init() -> None: def test_spot_simulation_step() -> None: """Test HierarchicalMJSimulation steps correctly with Spot locomotion policy.""" - sim = HierarchicalMJSimulation(init_task="spot_base") + policy_path = get_task_registration("spot_base").locomotion_policy_path + sim = HierarchicalMJSimulation(init_task="spot_base", locomotion_policy_path=policy_path) qpos_before = sim.task.data.qpos.copy() command = np.zeros(sim.task.nu) sim.step(command)