diff --git a/dimos/e2e_tests/test_control_coordinator.py b/dimos/e2e_tests/test_control_coordinator.py index 3b212a9060..f6e520831d 100644 --- a/dimos/e2e_tests/test_control_coordinator.py +++ b/dimos/e2e_tests/test_control_coordinator.py @@ -46,10 +46,7 @@ def test_coordinator_starts_and_responds_to_rpc(self, lcm_spy, start_blueprint) start_blueprint("coordinator-mock") # Wait for joint state to be published (proves tick loop is running) - lcm_spy.wait_for_saved_topic( - joint_state_topic, - timeout=10.0, - ) + lcm_spy.wait_for_saved_topic(joint_state_topic) # Create RPC client and query client = RPCClient(None, ControlCoordinator) @@ -81,9 +78,7 @@ def test_coordinator_executes_trajectory(self, lcm_spy, start_blueprint) -> None start_blueprint("coordinator-mock") # Wait for it to be ready - lcm_spy.wait_for_saved_topic( - "/coordinator/joint_state#sensor_msgs.JointState", timeout=10.0 - ) + lcm_spy.wait_for_saved_topic("/coordinator/joint_state#sensor_msgs.JointState") # Create RPC client client = RPCClient(None, ControlCoordinator) @@ -138,7 +133,7 @@ def test_coordinator_joint_state_published(self, lcm_spy, start_blueprint) -> No start_blueprint("coordinator-mock") # Wait for initial message - lcm_spy.wait_for_saved_topic(joint_state_topic, timeout=10.0) + lcm_spy.wait_for_saved_topic(joint_state_topic) # Collect messages for 1 second time.sleep(1.0) @@ -165,9 +160,7 @@ def test_coordinator_cancel_trajectory(self, lcm_spy, start_blueprint) -> None: # Start coordinator start_blueprint("coordinator-mock") - lcm_spy.wait_for_saved_topic( - "/coordinator/joint_state#sensor_msgs.JointState", timeout=10.0 - ) + lcm_spy.wait_for_saved_topic("/coordinator/joint_state#sensor_msgs.JointState") client = RPCClient(None, ControlCoordinator) try: @@ -210,9 +203,7 @@ def test_dual_arm_coordinator(self, lcm_spy, start_blueprint) -> None: # Start dual-arm mock coordinator start_blueprint("coordinator-dual-mock") - lcm_spy.wait_for_saved_topic( - "/coordinator/joint_state#sensor_msgs.JointState", timeout=10.0 - ) + lcm_spy.wait_for_saved_topic("/coordinator/joint_state#sensor_msgs.JointState") client = RPCClient(None, ControlCoordinator) try: diff --git a/dimos/manipulation/test_manipulation_module.py b/dimos/manipulation/test_manipulation_module.py index d2c2a347c9..c30ba9b55c 100644 --- a/dimos/manipulation/test_manipulation_module.py +++ b/dimos/manipulation/test_manipulation_module.py @@ -149,7 +149,7 @@ def test_plan_to_joints(self, module, joint_state_zeros): """Test planning to a joint configuration.""" module._on_joint_state(joint_state_zeros) - target = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] + target = JointState(position=[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]) success = module.plan_to_joints(target) assert success is True @@ -203,7 +203,7 @@ def test_trajectory_name_translation(self, module, joint_state_zeros): """Test that trajectory joint names are translated for coordinator.""" module._on_joint_state(joint_state_zeros) - success = module.plan_to_joints([0.05] * 7) + success = module.plan_to_joints(JointState(position=[0.05] * 7)) assert success is True traj = module._planned_trajectories["test_arm"] @@ -224,7 +224,7 @@ def test_execute_with_mock_coordinator(self, module, joint_state_zeros): """Test execute sends trajectory to coordinator.""" module._on_joint_state(joint_state_zeros) - success = module.plan_to_joints([0.05] * 7) + success = module.plan_to_joints(JointState(position=[0.05] * 7)) assert success is True # Mock the coordinator client @@ -253,7 +253,7 @@ def test_execute_rejected_by_coordinator(self, module, joint_state_zeros): """Test handling of coordinator rejection.""" module._on_joint_state(joint_state_zeros) - module.plan_to_joints([0.05] * 7) + module.plan_to_joints(JointState(position=[0.05] * 7)) # Mock coordinator to reject mock_client = MagicMock() @@ -273,7 +273,7 @@ def test_state_transitions_during_execution(self, module, joint_state_zeros): module._on_joint_state(joint_state_zeros) # Plan - should go through PLANNING -> COMPLETED - module.plan_to_joints([0.05] * 7) + module.plan_to_joints(JointState(position=[0.05] * 7)) assert module._state == ManipulationState.COMPLETED # Reset works from COMPLETED @@ -281,7 +281,7 @@ def test_state_transitions_during_execution(self, module, joint_state_zeros): assert module._state == ManipulationState.IDLE # Plan again - module.plan_to_joints([0.05] * 7) + module.plan_to_joints(JointState(position=[0.05] * 7)) # Mock coordinator mock_client = MagicMock() diff --git a/dimos/utils/cli/lcmspy/test_lcmspy.py b/dimos/utils/cli/lcmspy/test_lcmspy.py index 14877bbb9a..530f081f29 100644 --- a/dimos/utils/cli/lcmspy/test_lcmspy.py +++ b/dimos/utils/cli/lcmspy/test_lcmspy.py @@ -175,8 +175,9 @@ def test_lcmspy_global_totals() -> None: spy.msg("/odom", b"odometry data") spy.msg("/imu", b"imu data") - # The spy itself should have accumulated all messages - assert len(spy.message_history) == 3 + # Verify each test topic received exactly one message (ignore LCM discovery packets) + for t in ("/video", "/odom", "/imu"): + assert len(spy.topic[t].message_history) == 1 # Check global statistics global_freq = spy.freq(1.0) diff --git a/docker/python/Dockerfile b/docker/python/Dockerfile index 1572bbc3ba..30c9fda8eb 100644 --- a/docker/python/Dockerfile +++ b/docker/python/Dockerfile @@ -48,4 +48,7 @@ COPY . /app/ # Install dependencies with UV (10-100x faster than pip) RUN uv pip install --upgrade 'pip>=24' 'setuptools>=70' 'wheel' 'packaging>=24' && \ - uv pip install '.[misc,cpu,sim,drone,unitree,web,perception,visualization]' + uv pip install '.[misc,cpu,sim,drone,unitree,web,perception,visualization,manipulation]' + +# Remove pydrake .pyi stubs that use Python 3.12 syntax (breaks mypy on 3.10) +RUN find /usr/local/lib/python3.10/dist-packages/pydrake -name '*.pyi' -delete diff --git a/pyproject.toml b/pyproject.toml index 1b0c40acd3..52f18fe950 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -362,6 +362,8 @@ module = [ "open_clip", "piper_sdk.*", "plotext", + "pydrake", + "pydrake.*", "plum.*", "pycuda", "pycuda.*", @@ -384,6 +386,10 @@ ignore_missing_imports = true module = ["dimos.rxpy_backpressure", "dimos.rxpy_backpressure.*"] follow_imports = "skip" +[[tool.mypy.overrides]] +module = ["pydrake", "pydrake.*"] +follow_imports = "skip" + [tool.pytest.ini_options] testpaths = ["dimos"] markers = [