From fb22f9f8d8c82559d52470881b29a2246e80aea5 Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Tue, 2 Dec 2025 05:08:50 +0200 Subject: [PATCH 01/10] run mypy in CI --- .github/workflows/docker.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 34c7627549..f5a22e541c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -205,6 +205,22 @@ jobs: cmd: "pytest -m lcm" dev-image: dev:${{ (needs.check-changes.outputs.python == 'true' || needs.check-changes.outputs.dev == 'true') && needs.dev.result == 'success' && needs.check-changes.outputs.branch-tag || 'dev' }} + # Run mypy type checking with ROS types + run-mypy: + needs: [check-changes, ros-dev] + if: always() + uses: ./.github/workflows/tests.yml + secrets: inherit + with: + should-run: ${{ + needs.check-changes.result == 'success' && + ((needs.ros-dev.result == 'success') || + (needs.ros-dev.result == 'skipped' && + needs.check-changes.outputs.tests == 'true')) + }} + cmd: "MYPYPATH=/opt/ros/humble/lib/python3.10/site-packages mypy dimos" + dev-image: ros-dev:${{ (needs.check-changes.outputs.python == 'true' || needs.check-changes.outputs.dev == 'true' || needs.check-changes.outputs.ros == 'true') && needs.ros-dev.result == 'success' && needs.check-changes.outputs.branch-tag || 'dev' }} + # Run module tests directly to avoid pytest forking issues # run-module-tests: # needs: [check-changes, dev] From 875267689eba5b17631193fd2f6a21807619cbad Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Tue, 2 Dec 2025 06:34:32 +0200 Subject: [PATCH 02/10] use jazzy for mypy --- .github/workflows/docker.yml | 58 ++++++++++++++++++++--- docker/ros-jazzy/Dockerfile | 89 ++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 docker/ros-jazzy/Dockerfile diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f5a22e541c..18a8e3e29d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -20,6 +20,7 @@ jobs: runs-on: [self-hosted, Linux] outputs: ros: ${{ steps.filter.outputs.ros }} + ros-jazzy: ${{ steps.filter.outputs.ros-jazzy }} python: ${{ steps.filter.outputs.python }} dev: ${{ steps.filter.outputs.dev }} tests: ${{ steps.filter.outputs.tests }} @@ -43,6 +44,11 @@ jobs: - .github/workflows/docker.yml - docker/ros/** + ros-jazzy: + - .github/workflows/_docker-build-template.yml + - .github/workflows/docker.yml + - docker/ros-jazzy/** + python: - .github/workflows/_docker-build-template.yml - .github/workflows/docker.yml @@ -144,6 +150,46 @@ jobs: to-image: ghcr.io/dimensionalos/ros-dev:${{ needs.check-changes.outputs.branch-tag }} dockerfile: dev + # ROS Jazzy chain (Ubuntu 24.04 / Python 3.12) + ros-jazzy: + needs: [check-changes] + if: needs.check-changes.outputs.ros-jazzy == 'true' + uses: ./.github/workflows/_docker-build-template.yml + with: + should-run: true + from-image: ubuntu:24.04 + to-image: ghcr.io/dimensionalos/ros-jazzy:${{ needs.check-changes.outputs.branch-tag }} + dockerfile: ros-jazzy + + ros-python-jazzy: + needs: [check-changes, ros-jazzy] + if: always() + uses: ./.github/workflows/_docker-build-template.yml + with: + should-run: ${{ + needs.check-changes.outputs.python == 'true' && + needs.check-changes.result != 'error' && + needs.ros-jazzy.result != 'error' + }} + + from-image: ghcr.io/dimensionalos/ros-jazzy:${{ needs.ros-jazzy.result == 'success' && needs.check-changes.outputs.branch-tag || 'dev' }} + to-image: ghcr.io/dimensionalos/ros-python-jazzy:${{ needs.check-changes.outputs.branch-tag }} + dockerfile: python + + ros-dev-jazzy: + needs: [check-changes, ros-python-jazzy] + if: always() + uses: ./.github/workflows/_docker-build-template.yml + with: + should-run: ${{ + needs.check-changes.result == 'success' && + (needs.check-changes.outputs.dev == 'true' || + (needs.ros-python-jazzy.result == 'success' && (needs.check-changes.outputs.python == 'true' || needs.check-changes.outputs.ros-jazzy == 'true'))) + }} + from-image: ghcr.io/dimensionalos/ros-python-jazzy:${{ needs.ros-python-jazzy.result == 'success' && needs.check-changes.outputs.branch-tag || 'dev' }} + to-image: ghcr.io/dimensionalos/ros-dev-jazzy:${{ needs.check-changes.outputs.branch-tag }} + dockerfile: dev + run-ros-tests: needs: [check-changes, ros-dev] if: always() @@ -205,21 +251,21 @@ jobs: cmd: "pytest -m lcm" dev-image: dev:${{ (needs.check-changes.outputs.python == 'true' || needs.check-changes.outputs.dev == 'true') && needs.dev.result == 'success' && needs.check-changes.outputs.branch-tag || 'dev' }} - # Run mypy type checking with ROS types + # Run mypy type checking with ROS types (uses Jazzy for Python 3.12) run-mypy: - needs: [check-changes, ros-dev] + needs: [check-changes, ros-dev-jazzy] if: always() uses: ./.github/workflows/tests.yml secrets: inherit with: should-run: ${{ needs.check-changes.result == 'success' && - ((needs.ros-dev.result == 'success') || - (needs.ros-dev.result == 'skipped' && + ((needs.ros-dev-jazzy.result == 'success') || + (needs.ros-dev-jazzy.result == 'skipped' && needs.check-changes.outputs.tests == 'true')) }} - cmd: "MYPYPATH=/opt/ros/humble/lib/python3.10/site-packages mypy dimos" - dev-image: ros-dev:${{ (needs.check-changes.outputs.python == 'true' || needs.check-changes.outputs.dev == 'true' || needs.check-changes.outputs.ros == 'true') && needs.ros-dev.result == 'success' && needs.check-changes.outputs.branch-tag || 'dev' }} + cmd: "MYPYPATH=/opt/ros/jazzy/lib/python3.12/site-packages mypy dimos" + dev-image: ros-dev-jazzy:${{ (needs.check-changes.outputs.python == 'true' || needs.check-changes.outputs.dev == 'true' || needs.check-changes.outputs.ros-jazzy == 'true') && needs.ros-dev-jazzy.result == 'success' && needs.check-changes.outputs.branch-tag || 'dev' }} # Run module tests directly to avoid pytest forking issues # run-module-tests: diff --git a/docker/ros-jazzy/Dockerfile b/docker/ros-jazzy/Dockerfile new file mode 100644 index 0000000000..b7b64fc9f5 --- /dev/null +++ b/docker/ros-jazzy/Dockerfile @@ -0,0 +1,89 @@ +ARG FROM_IMAGE=ubuntu:24.04 +FROM ${FROM_IMAGE} + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Set locale +RUN apt-get update && apt-get install -y locales && \ + locale-gen en_US en_US.UTF-8 && \ + update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 +ENV LANG=en_US.UTF-8 + +# Set ROS distro +ENV ROS_DISTRO=jazzy + +# Install basic requirements +RUN apt-get update +RUN apt-get install -y \ + curl \ + gnupg2 \ + lsb-release \ + python3-pip \ + clang \ + portaudio19-dev \ + git \ + mesa-utils \ + libgl1-mesa-glx \ + libgl1-mesa-dri \ + software-properties-common \ + libxcb1-dev \ + libxcb-keysyms1-dev \ + libxcb-util0-dev \ + libxcb-icccm4-dev \ + libxcb-image0-dev \ + libxcb-randr0-dev \ + libxcb-shape0-dev \ + libxcb-xinerama0-dev \ + libxcb-xkb-dev \ + libxkbcommon-x11-dev \ + qtbase5-dev \ + qtchooser \ + qt5-qmake \ + qtbase5-dev-tools \ + supervisor + +# Install specific numpy version first +RUN pip install --break-system-packages 'numpy<2.0.0' + +# Add ROS2 apt repository +RUN curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg && \ + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null + +# Install ROS2 packages and dependencies +RUN apt-get update && apt-get install -y \ + ros-${ROS_DISTRO}-desktop \ + ros-${ROS_DISTRO}-ros-base \ + ros-${ROS_DISTRO}-image-tools \ + ros-${ROS_DISTRO}-compressed-image-transport \ + ros-${ROS_DISTRO}-vision-msgs \ + ros-${ROS_DISTRO}-rviz2 \ + ros-${ROS_DISTRO}-rqt \ + ros-${ROS_DISTRO}-rqt-common-plugins \ + ros-${ROS_DISTRO}-twist-mux \ + ros-${ROS_DISTRO}-joy \ + ros-${ROS_DISTRO}-teleop-twist-joy \ + ros-${ROS_DISTRO}-navigation2 \ + ros-${ROS_DISTRO}-nav2-bringup \ + ros-${ROS_DISTRO}-nav2-amcl \ + ros-${ROS_DISTRO}-nav2-map-server \ + ros-${ROS_DISTRO}-nav2-util \ + ros-${ROS_DISTRO}-pointcloud-to-laserscan \ + ros-${ROS_DISTRO}-slam-toolbox \ + ros-${ROS_DISTRO}-foxglove-bridge \ + python3-rosdep \ + python3-rosinstall \ + python3-rosinstall-generator \ + python3-wstool \ + python3-colcon-common-extensions \ + python3-vcstool \ + build-essential \ + screen \ + tmux + +# Initialize rosdep +RUN rosdep init +RUN rosdep update + +# Source ROS2 and workspace in bashrc +RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> /root/.bashrc From cf7009f4dae1aef57e00bd8a58a56bf087370291 Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Tue, 2 Dec 2025 07:51:26 +0200 Subject: [PATCH 03/10] fix --- docker/ros-jazzy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/ros-jazzy/Dockerfile b/docker/ros-jazzy/Dockerfile index b7b64fc9f5..9cda44a1de 100644 --- a/docker/ros-jazzy/Dockerfile +++ b/docker/ros-jazzy/Dockerfile @@ -24,7 +24,7 @@ RUN apt-get install -y \ portaudio19-dev \ git \ mesa-utils \ - libgl1-mesa-glx \ + libgl1 \ libgl1-mesa-dri \ software-properties-common \ libxcb1-dev \ From 616ad6a0da7ae64b1d2c630a946b0d500a8e5799 Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Tue, 2 Dec 2025 09:53:00 +0200 Subject: [PATCH 04/10] fix2 --- docker/ros-jazzy/Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/docker/ros-jazzy/Dockerfile b/docker/ros-jazzy/Dockerfile index 9cda44a1de..582b4d3a91 100644 --- a/docker/ros-jazzy/Dockerfile +++ b/docker/ros-jazzy/Dockerfile @@ -72,9 +72,6 @@ RUN apt-get update && apt-get install -y \ ros-${ROS_DISTRO}-slam-toolbox \ ros-${ROS_DISTRO}-foxglove-bridge \ python3-rosdep \ - python3-rosinstall \ - python3-rosinstall-generator \ - python3-wstool \ python3-colcon-common-extensions \ python3-vcstool \ build-essential \ From ca336342b622c7fcfe7fcd451ce7e1a90d8dfb15 Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Tue, 2 Dec 2025 14:29:05 +0200 Subject: [PATCH 05/10] fix3 --- docker/python/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/python/Dockerfile b/docker/python/Dockerfile index 6fbd5545e5..63c482d892 100644 --- a/docker/python/Dockerfile +++ b/docker/python/Dockerfile @@ -13,7 +13,7 @@ RUN apt-get install -y \ portaudio19-dev \ git \ mesa-utils \ - libgl1-mesa-glx \ + libgl1 \ libgl1-mesa-dri \ software-properties-common \ libxcb1-dev \ From f73e329dbb61dda41d2c6bd86aeb3c9240a83e6f Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Wed, 3 Dec 2025 00:47:33 +0200 Subject: [PATCH 06/10] fix4 --- docker/python/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/python/Dockerfile b/docker/python/Dockerfile index 63c482d892..e8ab767cac 100644 --- a/docker/python/Dockerfile +++ b/docker/python/Dockerfile @@ -39,6 +39,7 @@ RUN apt-get purge -y python3-blinker python3-sympy python3-oauthlib || true # Install UV for fast Python package management ENV UV_SYSTEM_PYTHON=1 +ENV UV_BREAK_SYSTEM_PACKAGES=1 RUN curl -LsSf https://astral.sh/uv/install.sh | sh ENV PATH="/root/.local/bin:$PATH" From 7669fa6848f49e29c8f0f19424ee553184f2e28d Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Wed, 3 Dec 2025 02:55:25 +0200 Subject: [PATCH 07/10] fix5 --- dimos/robot/unitree_webrtc/unitree_g1_blueprints.py | 2 +- docker/python/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dimos/robot/unitree_webrtc/unitree_g1_blueprints.py b/dimos/robot/unitree_webrtc/unitree_g1_blueprints.py index 8f8f480ada..0ebceac51e 100644 --- a/dimos/robot/unitree_webrtc/unitree_g1_blueprints.py +++ b/dimos/robot/unitree_webrtc/unitree_g1_blueprints.py @@ -20,7 +20,7 @@ """ from dimos_lcm.foxglove_msgs import SceneUpdate # type: ignore[import-untyped] -from dimos_lcm.foxglove_msgs.ImageAnnotations import ( +from dimos_lcm.foxglove_msgs.ImageAnnotations import ( # type: ignore[import-untyped] ImageAnnotations, ) from dimos_lcm.sensor_msgs import CameraInfo # type: ignore[import-untyped] diff --git a/docker/python/Dockerfile b/docker/python/Dockerfile index e8ab767cac..aa53e31333 100644 --- a/docker/python/Dockerfile +++ b/docker/python/Dockerfile @@ -50,4 +50,4 @@ 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 '.[cpu]' + uv pip install '.[cpu,sim]' From e58090a60eacadbfdddb95af5d8f8e1ac33ca388 Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Wed, 3 Dec 2025 07:09:00 +0200 Subject: [PATCH 08/10] upgrade mypy --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 815b21008d..06f90c266b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -185,7 +185,7 @@ cuda = [ dev = [ "ruff==0.14.3", - "mypy==1.18.2", + "mypy==1.19.0", "pre_commit==4.2.0", "pytest==8.3.5", "pytest-asyncio==0.26.0", From 9123667e25fe7b037f90f9f8edaa41952f60ceac Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Wed, 3 Dec 2025 07:40:52 +0200 Subject: [PATCH 09/10] disable unused ignores --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 06f90c266b..2d0c2d67d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -270,6 +270,7 @@ force-sort-within-sections = true python_version = "3.12" incremental = true strict = true +warn_unused_ignores = false exclude = "^dimos/models/Detic(/|$)|.*/test_.|.*/conftest.py*" [tool.pytest.ini_options] From 6a02e6c77765928b4c2e962a4bbc9d69e96af06c Mon Sep 17 00:00:00 2001 From: Paul Nechifor Date: Wed, 3 Dec 2025 07:53:56 +0200 Subject: [PATCH 10/10] ignore more checks --- dimos/core/stream.py | 2 +- dimos/hardware/camera/zed/camera.py | 2 +- dimos/hardware/gstreamer_camera.py | 4 +-- dimos/hardware/gstreamer_sender.py | 4 +-- dimos/hardware/piper_arm.py | 2 +- dimos/manipulation/visual_servoing/pbvs.py | 2 +- dimos/models/vl/base.py | 2 +- dimos/msgs/geometry_msgs/Quaternion.py | 2 +- dimos/msgs/nav_msgs/OccupancyGrid.py | 2 +- .../navigation/bt_navigator/goal_validator.py | 2 +- .../navigation/frontier_exploration/utils.py | 2 +- dimos/perception/common/export_tensorrt.py | 4 +-- .../detection/detectors/person/yolo.py | 2 +- dimos/perception/detection/detectors/yolo.py | 2 +- dimos/perception/pointcloud/utils.py | 2 +- dimos/perception/segmentation/sam_2d_seg.py | 2 +- dimos/protocol/skill/test_coordinator.py | 28 ++++++++++--------- dimos/utils/transform_utils.py | 2 +- .../web/websocket_vis/websocket_vis_module.py | 12 ++++---- 19 files changed, 41 insertions(+), 39 deletions(-) diff --git a/dimos/core/stream.py b/dimos/core/stream.py index aa58904678..6e557f3b4a 100644 --- a/dimos/core/stream.py +++ b/dimos/core/stream.py @@ -256,7 +256,7 @@ def transport(self) -> Transport[T]: def publish(self, msg) -> None: # type: ignore[no-untyped-def] self.transport.broadcast(self, msg) # type: ignore[arg-type] - @transport.setter # type: ignore[attr-defined, misc, no-redef] + @transport.setter # type: ignore[attr-defined, misc, no-redef, untyped-decorator] def transport(self, value: Transport[T]) -> None: self.owner.set_transport(self.name, value).result() # type: ignore[union-attr] self._transport = value diff --git a/dimos/hardware/camera/zed/camera.py b/dimos/hardware/camera/zed/camera.py index b74942720c..3f72cf3b45 100644 --- a/dimos/hardware/camera/zed/camera.py +++ b/dimos/hardware/camera/zed/camera.py @@ -591,7 +591,7 @@ def __init__( # type: ignore[no-untyped-def] self.tf = TF() # Initialize storage for recording if path provided - self.storages = None + self.storages: dict[str, Any] | None = None if self.recording_path: from dimos.utils.testing import TimedSensorStorage diff --git a/dimos/hardware/gstreamer_camera.py b/dimos/hardware/gstreamer_camera.py index d40587278b..2e85420606 100644 --- a/dimos/hardware/gstreamer_camera.py +++ b/dimos/hardware/gstreamer_camera.py @@ -29,11 +29,11 @@ if "/usr/lib/python3/dist-packages" not in sys.path: sys.path.insert(0, "/usr/lib/python3/dist-packages") -import gi # type: ignore[import-not-found] +import gi # type: ignore[import-untyped,import-not-found] gi.require_version("Gst", "1.0") gi.require_version("GstApp", "1.0") -from gi.repository import GLib, Gst # type: ignore[import-not-found] +from gi.repository import GLib, Gst # type: ignore[import-untyped,import-not-found] logger = setup_logger("dimos.hardware.gstreamer_camera", level=logging.INFO) diff --git a/dimos/hardware/gstreamer_sender.py b/dimos/hardware/gstreamer_sender.py index 4f10c8eb76..3cd03fdce7 100755 --- a/dimos/hardware/gstreamer_sender.py +++ b/dimos/hardware/gstreamer_sender.py @@ -24,11 +24,11 @@ if "/usr/lib/python3/dist-packages" not in sys.path: sys.path.insert(0, "/usr/lib/python3/dist-packages") -import gi # type: ignore[import-not-found] +import gi # type: ignore[import-untyped,import-not-found] gi.require_version("Gst", "1.0") gi.require_version("GstVideo", "1.0") -from gi.repository import GLib, Gst # type: ignore[import-not-found] +from gi.repository import GLib, Gst # type: ignore[import-untyped,import-not-found] # Initialize GStreamer Gst.init(None) diff --git a/dimos/hardware/piper_arm.py b/dimos/hardware/piper_arm.py index 5d8a41545f..c3315b6e35 100644 --- a/dimos/hardware/piper_arm.py +++ b/dimos/hardware/piper_arm.py @@ -27,7 +27,7 @@ from piper_sdk import * # type: ignore[import-not-found] # from the official Piper SDK import pytest from reactivex.disposable import Disposable -from scipy.spatial.transform import Rotation as R +from scipy.spatial.transform import Rotation as R # type: ignore[import-untyped] import dimos.core as core from dimos.core import In, Module, rpc diff --git a/dimos/manipulation/visual_servoing/pbvs.py b/dimos/manipulation/visual_servoing/pbvs.py index ba1ab4c076..b2cf15ac5a 100644 --- a/dimos/manipulation/visual_servoing/pbvs.py +++ b/dimos/manipulation/visual_servoing/pbvs.py @@ -21,7 +21,7 @@ from dimos_lcm.vision_msgs import Detection3D # type: ignore[import-untyped] import numpy as np -from scipy.spatial.transform import Rotation as R +from scipy.spatial.transform import Rotation as R # type: ignore[import-untyped] from dimos.manipulation.visual_servoing.utils import ( create_pbvs_visualization, diff --git a/dimos/models/vl/base.py b/dimos/models/vl/base.py index acb998d274..cc9da9e540 100644 --- a/dimos/models/vl/base.py +++ b/dimos/models/vl/base.py @@ -72,7 +72,7 @@ def warmup(self) -> None: pass # requery once if JSON parsing fails - @retry(max_retries=2, on_exception=json.JSONDecodeError, delay=0.0) # type: ignore[misc] + @retry(max_retries=2, on_exception=json.JSONDecodeError, delay=0.0) # type: ignore[misc, untyped-decorator] def query_json(self, image: Image, query: str) -> dict: # type: ignore[type-arg] response = self.query(image, query) return extract_json(response) # type: ignore[return-value] diff --git a/dimos/msgs/geometry_msgs/Quaternion.py b/dimos/msgs/geometry_msgs/Quaternion.py index 14933ab712..d1420e78e1 100644 --- a/dimos/msgs/geometry_msgs/Quaternion.py +++ b/dimos/msgs/geometry_msgs/Quaternion.py @@ -22,7 +22,7 @@ from dimos_lcm.geometry_msgs import Quaternion as LCMQuaternion # type: ignore[import-untyped] import numpy as np from plum import dispatch -from scipy.spatial.transform import Rotation as R +from scipy.spatial.transform import Rotation as R # type: ignore[import-untyped] from dimos.msgs.geometry_msgs.Vector3 import Vector3 diff --git a/dimos/msgs/nav_msgs/OccupancyGrid.py b/dimos/msgs/nav_msgs/OccupancyGrid.py index 068422a7f2..e66ec4fb1d 100644 --- a/dimos/msgs/nav_msgs/OccupancyGrid.py +++ b/dimos/msgs/nav_msgs/OccupancyGrid.py @@ -24,7 +24,7 @@ ) from dimos_lcm.std_msgs import Time as LCMTime # type: ignore[import-untyped] import numpy as np -from scipy import ndimage +from scipy import ndimage # type: ignore[import-untyped] from dimos.msgs.geometry_msgs import Pose, Vector3, VectorLike from dimos.types.timestamped import Timestamped diff --git a/dimos/navigation/bt_navigator/goal_validator.py b/dimos/navigation/bt_navigator/goal_validator.py index 6583f157cb..cdf86ccac5 100644 --- a/dimos/navigation/bt_navigator/goal_validator.py +++ b/dimos/navigation/bt_navigator/goal_validator.py @@ -227,7 +227,7 @@ def _find_safe_goal_voronoi( - Requires scipy for efficient implementation """ - from scipy import ndimage + from scipy import ndimage # type: ignore[import-untyped] from skimage.morphology import skeletonize # type: ignore[import-not-found] # Convert goal to grid coordinates diff --git a/dimos/navigation/frontier_exploration/utils.py b/dimos/navigation/frontier_exploration/utils.py index d307749531..40073ded3a 100644 --- a/dimos/navigation/frontier_exploration/utils.py +++ b/dimos/navigation/frontier_exploration/utils.py @@ -59,7 +59,7 @@ def costmap_to_pil_image(costmap: OccupancyGrid, scale_factor: int = 2) -> Image # Scale up if requested if scale_factor > 1: new_size = (img.width * scale_factor, img.height * scale_factor) - img = img.resize(new_size, Image.NEAREST) # Use NEAREST to keep sharp pixels + img = img.resize(new_size, Image.NEAREST) # type: ignore[attr-defined] # Use NEAREST to keep sharp pixels return img diff --git a/dimos/perception/common/export_tensorrt.py b/dimos/perception/common/export_tensorrt.py index 71499173ca..f349390b57 100644 --- a/dimos/perception/common/export_tensorrt.py +++ b/dimos/perception/common/export_tensorrt.py @@ -14,7 +14,7 @@ import argparse -from ultralytics import YOLO, FastSAM +from ultralytics import YOLO, FastSAM # type: ignore[attr-defined] def parse_args(): # type: ignore[no-untyped-def] @@ -46,7 +46,7 @@ def main() -> None: int8 = args.precision == "int8" # Load the appropriate model if args.model_type == "yolo": - model = YOLO(args.model_path) + model: YOLO | FastSAM = YOLO(args.model_path) else: model = FastSAM(args.model_path) diff --git a/dimos/perception/detection/detectors/person/yolo.py b/dimos/perception/detection/detectors/person/yolo.py index 3f58dc75ce..1aef3c3621 100644 --- a/dimos/perception/detection/detectors/person/yolo.py +++ b/dimos/perception/detection/detectors/person/yolo.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ultralytics import YOLO +from ultralytics import YOLO # type: ignore[attr-defined] from dimos.msgs.sensor_msgs import Image from dimos.perception.detection.detectors.types import Detector diff --git a/dimos/perception/detection/detectors/yolo.py b/dimos/perception/detection/detectors/yolo.py index 22ecf16259..c7ab181e0b 100644 --- a/dimos/perception/detection/detectors/yolo.py +++ b/dimos/perception/detection/detectors/yolo.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ultralytics import YOLO +from ultralytics import YOLO # type: ignore[attr-defined] from dimos.msgs.sensor_msgs import Image from dimos.perception.detection.detectors.types import Detector diff --git a/dimos/perception/pointcloud/utils.py b/dimos/perception/pointcloud/utils.py index f79d1c9d74..682f65903c 100644 --- a/dimos/perception/pointcloud/utils.py +++ b/dimos/perception/pointcloud/utils.py @@ -25,7 +25,7 @@ import cv2 import numpy as np import open3d as o3d # type: ignore[import-untyped] -from scipy.spatial import cKDTree +from scipy.spatial import cKDTree # type: ignore[import-untyped] import yaml from dimos.perception.common.utils import project_3d_points_to_2d diff --git a/dimos/perception/segmentation/sam_2d_seg.py b/dimos/perception/segmentation/sam_2d_seg.py index 0fe5507d93..ab90597a3e 100644 --- a/dimos/perception/segmentation/sam_2d_seg.py +++ b/dimos/perception/segmentation/sam_2d_seg.py @@ -20,7 +20,7 @@ import cv2 import onnxruntime # type: ignore[import-untyped] -from ultralytics import FastSAM +from ultralytics import FastSAM # type: ignore[attr-defined] from dimos.perception.common.detection2d_tracker import get_tracked_results, target2dTracker from dimos.perception.segmentation.image_analyzer import ImageAnalyzer diff --git a/dimos/protocol/skill/test_coordinator.py b/dimos/protocol/skill/test_coordinator.py index e8d8c45a0c..63ff1a52f5 100644 --- a/dimos/protocol/skill/test_coordinator.py +++ b/dimos/protocol/skill/test_coordinator.py @@ -47,51 +47,53 @@ def delayadd(self, x: int, y: int) -> int: time.sleep(0.3) return x + y - @skill(stream=Stream.call_agent, reducer=Reducer.all) + @skill(stream=Stream.call_agent, reducer=Reducer.all) # type: ignore[arg-type] def counter(self, count_to: int, delay: float | None = 0.05) -> Generator[int, None, None]: """Counts from 1 to count_to, with an optional delay between counts.""" for i in range(1, count_to + 1): - if delay > 0: + if delay is not None and delay > 0: time.sleep(delay) yield i - @skill(stream=Stream.passive, reducer=Reducer.sum) + @skill(stream=Stream.passive, reducer=Reducer.sum) # type: ignore[arg-type] def counter_passive_sum( self, count_to: int, delay: float | None = 0.05 ) -> Generator[int, None, None]: """Counts from 1 to count_to, with an optional delay between counts.""" for i in range(1, count_to + 1): - if delay > 0: + if delay is not None and delay > 0: time.sleep(delay) yield i - @skill(stream=Stream.passive, reducer=Reducer.latest) + @skill(stream=Stream.passive, reducer=Reducer.latest) # type: ignore[arg-type] def current_time(self, frequency: float | None = 10) -> Generator[str, None, None]: """Provides current time.""" while True: yield str(datetime.datetime.now()) - time.sleep(1 / frequency) + if frequency is not None: + time.sleep(1 / frequency) - @skill(stream=Stream.passive, reducer=Reducer.latest) + @skill(stream=Stream.passive, reducer=Reducer.latest) # type: ignore[arg-type] def uptime_seconds(self, frequency: float | None = 10) -> Generator[float, None, None]: """Provides current uptime.""" start_time = datetime.datetime.now() while True: yield (datetime.datetime.now() - start_time).total_seconds() - time.sleep(1 / frequency) + if frequency is not None: + time.sleep(1 / frequency) @skill() def current_date(self, frequency: float | None = 10) -> str: """Provides current date.""" - return datetime.datetime.now() + return str(datetime.datetime.now()) @skill(output=Output.image) - def take_photo(self) -> str: + def take_photo(self) -> Image: # type: ignore[type-arg] """Takes a camera photo""" print("Taking photo...") - img = Image.from_file(get_data("cafe-smol.jpg")) + img = Image.from_file(str(get_data("cafe-smol.jpg"))) # type: ignore[arg-type] print("Photo taken.") - return img + return img # type: ignore[return-value] @pytest.mark.asyncio @@ -112,7 +114,7 @@ async def test_coordinator_parallel_calls() -> None: skill_id = f"test-call-{cnt}" tool_msg = skillstates[skill_id].agent_encode() - assert tool_msg.content == cnt + 2 + assert tool_msg.content == cnt + 2 # type: ignore[union-attr] cnt += 1 if cnt < 5: diff --git a/dimos/utils/transform_utils.py b/dimos/utils/transform_utils.py index c108bc34b9..6185bfb1ca 100644 --- a/dimos/utils/transform_utils.py +++ b/dimos/utils/transform_utils.py @@ -14,7 +14,7 @@ import numpy as np -from scipy.spatial.transform import Rotation as R +from scipy.spatial.transform import Rotation as R # type: ignore[import-untyped] from dimos.msgs.geometry_msgs import Pose, Quaternion, Transform, Vector3 diff --git a/dimos/web/websocket_vis/websocket_vis_module.py b/dimos/web/websocket_vis/websocket_vis_module.py index f39fb745df..886cabe235 100644 --- a/dimos/web/websocket_vis/websocket_vis_module.py +++ b/dimos/web/websocket_vis/websocket_vis_module.py @@ -186,7 +186,7 @@ async def serve_index(request): # type: ignore[no-untyped-def] self.app = socketio.ASGIApp(self.sio, starlette_app) # Register SocketIO event handlers - @self.sio.event # type: ignore[misc] + @self.sio.event # type: ignore[misc, untyped-decorator] async def connect(sid, environ) -> None: # type: ignore[no-untyped-def] with self.state_lock: current_state = dict(self.vis_state) @@ -196,7 +196,7 @@ async def connect(sid, environ) -> None: # type: ignore[no-untyped-def] await self.sio.emit("full_state", current_state, room=sid) # type: ignore[union-attr] - @self.sio.event # type: ignore[misc] + @self.sio.event # type: ignore[misc, untyped-decorator] async def click(sid, position) -> None: # type: ignore[no-untyped-def] goal = PoseStamped( position=(position[0], position[1], 0), @@ -206,22 +206,22 @@ async def click(sid, position) -> None: # type: ignore[no-untyped-def] self.goal_request.publish(goal) logger.info(f"Click goal published: ({goal.position.x:.2f}, {goal.position.y:.2f})") - @self.sio.event # type: ignore[misc] + @self.sio.event # type: ignore[misc, untyped-decorator] async def gps_goal(sid, goal) -> None: # type: ignore[no-untyped-def] logger.info(f"Set GPS goal: {goal}") self.gps_goal.publish(LatLon(lat=goal["lat"], lon=goal["lon"])) - @self.sio.event # type: ignore[misc] + @self.sio.event # type: ignore[misc, untyped-decorator] async def start_explore(sid) -> None: # type: ignore[no-untyped-def] logger.info("Starting exploration") self.explore_cmd.publish(Bool(data=True)) - @self.sio.event # type: ignore[misc] + @self.sio.event # type: ignore[misc, untyped-decorator] async def stop_explore(sid) -> None: # type: ignore[no-untyped-def] logger.info("Stopping exploration") self.stop_explore_cmd.publish(Bool(data=True)) - @self.sio.event # type: ignore[misc] + @self.sio.event # type: ignore[misc, untyped-decorator] async def move_command(sid, data) -> None: # type: ignore[no-untyped-def] # Publish Twist if transport is configured if self.cmd_vel and self.cmd_vel.transport: