Skip to content

Commit 577b00f

Browse files
strands-agentcagataycali
authored andcommitted
refactor: address 10 review threads from @awsarron on PR strands-labs#86
1. Rename factory.py → robot.py, robot.py → hardware_robot.py Eliminates two 'Robot' classes in different files. The factory function now lives where users expect: strands_robots.robot.Robot 2. Default mode='sim' instead of mode='auto' Using real hardware should be an explicit decision since it affects the physical world. Robot('so100') now always returns simulation. Use mode='real' to explicitly opt into hardware control. 3. Fix ThreadPoolExecutor leak in _async_utils.py Register atexit.shutdown(wait=False) to clean up the module-level executor on interpreter exit. 4. Remove redundant list_robots() wrapper Was a 1-line passthrough to registry.list_robots(). Now __init__.py points directly to strands_robots.registry.list_robots. 5. Use module names in dataset_recorder docstring 'robot.py' → 'strands_robots.hardware_robot', 'simulation.py' → 'strands_robots.simulation' 6. Make camera shape configurable in dataset_recorder Added camera_shapes parameter to _build_features() instead of hardcoding (3, 480, 640). Default preserved for backward compat. 7. Add mode validation — invalid mode raises ValueError 8. Update __init__.py lazy imports for renamed modules Tests: 230 passed, 10 skipped, 0 failures Lint: ruff check + ruff format clean
1 parent 9af0a55 commit 577b00f

7 files changed

Lines changed: 971 additions & 955 deletions

File tree

strands_robots/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
# Maps public name -> (module_path, attribute_name)
3838
_LAZY_IMPORTS: dict[str, tuple[str, str]] = {
3939
# Hardware robot
40-
"Robot": ("strands_robots.factory", "Robot"),
41-
"list_robots": ("strands_robots.factory", "list_robots"),
40+
"Robot": ("strands_robots.robot", "Robot"),
41+
"list_robots": ("strands_robots.registry", "list_robots"),
4242
# Policies
4343
"Gr00tPolicy": ("strands_robots.policies.groot", "Gr00tPolicy"),
4444
# Simulation (MuJoCo)

strands_robots/_async_utils.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
"""Async-to-sync helper for resolving coroutines in sync contexts."""
22

33
import asyncio
4-
import concurrent.futures
4+
import atexit
5+
from concurrent.futures import ThreadPoolExecutor
56

67
# Module-level executor reused across calls to avoid creating threads at high frequency.
78
# A single worker is sufficient — we only need to offload one asyncio.run() at a time.
8-
_EXECUTOR = concurrent.futures.ThreadPoolExecutor(max_workers=1, thread_name_prefix="strands_async")
9+
_EXECUTOR = ThreadPoolExecutor(max_workers=1, thread_name_prefix="strands_async")
10+
11+
# Ensure the executor is shut down cleanly on interpreter exit to avoid
12+
# ResourceWarning and orphaned threads.
13+
atexit.register(_EXECUTOR.shutdown, wait=False)
914

1015

1116
def _resolve_coroutine(coro_or_result): # type: ignore[no-untyped-def]

strands_robots/dataset_recorder.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""LeRobotDataset recorder bridge for strands-robots.
22
3-
Wraps LeRobotDataset so that both robot.py (real hardware) and
4-
simulation.py (MuJoCo) can produce training-ready datasets with
3+
Wraps LeRobotDataset so that both strands_robots.hardware_robot and
4+
strands_robots.simulation (MuJoCo) can produce training-ready datasets with
55
a single add_frame() call per control step.
66
77
Usage:
@@ -180,6 +180,7 @@ def _build_features(
180180
camera_keys: list[str] | None = None,
181181
joint_names: list[str] | None = None,
182182
use_videos: bool = True,
183+
camera_shapes: dict[str, tuple[int, int, int]] | None = None,
183184
) -> dict[str, Any]:
184185
"""Build LeRobot v3-compatible features dict.
185186
@@ -199,13 +200,13 @@ def _build_features(
199200
for cam_name in camera_keys:
200201
key = f"observation.images.{cam_name}"
201202
dtype = "video" if use_videos else "image"
203+
# Per-camera shape override, default (3, 480, 640) CHW
204+
shape = (3, 480, 640)
205+
if camera_shapes and cam_name in camera_shapes:
206+
shape = camera_shapes[cam_name]
202207
features[key] = {
203208
"dtype": dtype,
204-
"shape": (
205-
3,
206-
480,
207-
640,
208-
), # CHW default, actual shape set on first frame
209+
"shape": shape,
209210
"names": ["channels", "height", "width"],
210211
}
211212

strands_robots/factory.py

Lines changed: 0 additions & 202 deletions
This file was deleted.

0 commit comments

Comments
 (0)