Skip to content

Commit

Permalink
Add ament_mypy test and fix all mypy errors (#980)
Browse files Browse the repository at this point in the history
  • Loading branch information
bjsowa authored Dec 25, 2024
1 parent 25fe570 commit 5444d9b
Show file tree
Hide file tree
Showing 29 changed files with 111 additions and 68 deletions.
3 changes: 3 additions & 0 deletions rosapi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,7 @@ if(BUILD_TESTING)
find_package(ament_cmake_pytest REQUIRED)
ament_add_pytest_test(${PROJECT_NAME}_test_stringify_field_types test/test_stringify_field_types.py)
ament_add_pytest_test(${PROJECT_NAME}_test_typedefs test/test_typedefs.py)

find_package(ament_cmake_mypy REQUIRED)
ament_mypy()
endif()
1 change: 1 addition & 0 deletions rosapi/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<exec_depend>rosgraph</exec_depend>
-->

<test_depend>ament_cmake_mypy</test_depend>
<test_depend>ament_cmake_pytest</test_depend>
<test_depend>sensor_msgs</test_depend>
<test_depend>shape_msgs</test_depend>
Expand Down
3 changes: 3 additions & 0 deletions rosbridge_library/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ if (BUILD_TESTING)
find_package(ament_cmake_pytest REQUIRED)
ament_add_pytest_test(test_capabilities "test/capabilities/")
ament_add_pytest_test(test_internal "test/internal/")

find_package(ament_cmake_mypy REQUIRED)
ament_mypy()
endif()
1 change: 1 addition & 0 deletions rosbridge_library/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

<test_depend>rosbridge_test_msgs</test_depend>
<test_depend>action_msgs</test_depend>
<test_depend>ament_cmake_mypy</test_depend>
<test_depend>ament_cmake_pytest</test_depend>
<test_depend>builtin_interfaces</test_depend>
<test_depend>diagnostic_msgs</test_depend>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
import fnmatch
from typing import Any

import rclpy
from action_msgs.msg import GoalStatus
from rclpy.action import ActionServer
from rclpy.action.server import CancelResponse, ServerGoalHandle
from rclpy.callback_groups import ReentrantCallbackGroup
from rclpy.task import Future
from rosbridge_library.capability import Capability
from rosbridge_library.internal import message_conversion
from rosbridge_library.internal.ros_loader import get_action_class
Expand All @@ -51,9 +51,9 @@ class AdvertisedActionHandler:
def __init__(
self, action_name: str, action_type: str, protocol: Protocol, sleep_time: float = 0.001
) -> None:
self.goal_futures = {}
self.goal_handles = {}
self.goal_statuses = {}
self.goal_futures: dict[str, Future] = {}
self.goal_handles: dict[str, Any] = {}
self.goal_statuses: dict[str, GoalStatus] = {}

self.action_name = action_name
self.action_type = action_type
Expand All @@ -79,7 +79,7 @@ async def execute_callback(self, goal: Any) -> Any:
# generate a unique ID
goal_id = f"action_goal:{self.action_name}:{self.next_id()}"

def done_callback(fut: rclpy.task.Future) -> None:
def done_callback(fut: Future) -> None:
if fut.cancelled():
goal.abort()
self.protocol.log("info", f"Aborted goal {goal_id}")
Expand All @@ -94,7 +94,7 @@ def done_callback(fut: rclpy.task.Future) -> None:
else:
goal.abort()

future = rclpy.task.Future()
future: Future = Future()
future.add_done_callback(done_callback)
self.goal_handles[goal_id] = goal
self.goal_futures[goal_id] = future
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def spam(self):
# }
# },
# ...
lists = {}
lists: dict[str, dict] = {}

def __init__(self):
"""Create singleton instance"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import fnmatch
from functools import partial
from threading import Thread
from typing import Any

from action_msgs.msg import GoalStatus
from rosbridge_library.capability import Capability
Expand All @@ -52,7 +53,7 @@ class SendActionGoal(Capability):
cancel_action_goal_msg_fields = [(True, "action", str)]

actions_glob = None
client_handler_list = {}
client_handler_list: dict[str, ActionClientHandler] = {}

def __init__(self, protocol: Protocol) -> None:
# Call superclass constructor
Expand Down Expand Up @@ -182,7 +183,7 @@ def _failure(self, cid: str, action: str, exc: Exception) -> None:
outgoing_message["id"] = cid
self.protocol.send(outgoing_message)

def _feedback(self, cid: str, action: str, message: dict) -> None:
def _feedback(self, cid: str, action: str, message: Any) -> None:
outgoing_message = {
"op": "action_feedback",
"action": action,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@
from rosbridge_library.internal.subscription_modifiers import MessageHandler

try:
from ujson import dumps as encode_json
from ujson import dumps as encode_json # type: ignore[import-untyped]
except ImportError:
try:
from simplejson import dumps as encode_json
from simplejson import dumps as encode_json # type: ignore[import-untyped]
except ImportError:
from json import dumps as encode_json

Expand Down
16 changes: 8 additions & 8 deletions rosbridge_library/src/rosbridge_library/internal/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

import time
from threading import Thread
from typing import Any, Callable, Optional, Union
from typing import Any, Callable, Optional

from rclpy.action import ActionClient
from rclpy.expand_topic_name import expand_topic_name
Expand All @@ -59,9 +59,9 @@ def __init__(
action: str,
action_type: str,
args: dict,
success_callback: Callable[[str, str, int, bool, dict], None],
error_callback: Callable[[str, str, Exception], None],
feedback_callback: Callable[[str, str, dict], None],
success_callback: Callable[[dict], None],
error_callback: Callable[[Exception], None],
feedback_callback: Optional[Callable[[dict], None]],
node_handle: Node,
) -> None:
"""
Expand Down Expand Up @@ -90,12 +90,11 @@ def __init__(
self.error = error_callback
self.feedback = feedback_callback
self.node_handle = node_handle
self.send_goal_helper = None
self.send_goal_helper = SendGoal()

def run(self) -> None:
try:
# Call the service and pass the result to the success handler
self.send_goal_helper = SendGoal()
self.success(
self.send_goal_helper.send_goal(
self.node_handle,
Expand All @@ -110,7 +109,7 @@ def run(self) -> None:
self.error(e)


def args_to_action_goal_instance(action: str, inst: Any, args: Union[list, dict]) -> Any:
def args_to_action_goal_instance(action: str, inst: Any, args: list | dict | None) -> Any:
""" "
Populate an action goal instance with the provided args
Expand Down Expand Up @@ -142,6 +141,7 @@ def get_result_cb(self, future: Future) -> None:

def goal_response_cb(self, future: Future) -> None:
self.goal_handle = future.result()
assert self.goal_handle is not None
if not self.goal_handle.accepted:
raise Exception("Action goal was rejected")
result_future = self.goal_handle.get_result_async()
Expand All @@ -156,7 +156,7 @@ def send_goal(
action: str,
action_type: str,
args: Optional[dict] = None,
feedback_cb: Optional[Callable[[str, str, dict], None]] = None,
feedback_cb: Optional[Callable[[dict], None]] = None,
) -> dict:
# Given the action name and type, fetch a request instance
action_name = expand_topic_name(action, node_handle.get_name(), node_handle.get_namespace())
Expand Down
10 changes: 5 additions & 5 deletions rosbridge_library/src/rosbridge_library/internal/ros_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@
"""

# Variable containing the loaded classes
_loaded_msgs = {}
_loaded_srvs = {}
_loaded_actions = {}
_loaded_msgs: dict[str, Any] = {}
_loaded_srvs: dict[str, Any] = {}
_loaded_actions: dict[str, Any] = {}
_msgs_lock = Lock()
_srvs_lock = Lock()
_actions_lock = Lock()
Expand Down Expand Up @@ -185,7 +185,7 @@ def _get_class(typestring: str, subname: str, cache: Dict[str, Any], lock: Lock)
return cls


def _load_class(modname: str, subname: str, classname: str) -> None:
def _load_class(modname: str, subname: str, classname: str) -> Any:
"""Loads the manifest and imports the module that contains the specified
type.
Expand Down Expand Up @@ -220,7 +220,7 @@ def _splittype(typestring: str) -> Tuple[str, str]:
raise InvalidTypeStringException(typestring)


def _add_to_cache(cache: Dict[str, Any], lock: Lock, key: str, value: any) -> None:
def _add_to_cache(cache: Dict[str, Any], lock: Lock, key: str, value: Any) -> None:
lock.acquire()
cache[key] = value
lock.release()
Expand Down
16 changes: 8 additions & 8 deletions rosbridge_library/src/rosbridge_library/internal/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ def __init__(
self,
service: str,
args: dict,
success_callback: Callable[[str, str, int, bool, Any], None],
error_callback: Callable[[str, str, Exception], None],
success_callback: Callable[[dict], None],
error_callback: Callable[[Exception], None],
node_handle: Node,
) -> None:
"""Create a service caller for the specified service. Use start()
Expand Down Expand Up @@ -94,7 +94,7 @@ def run(self) -> None:
self.error(e)


def args_to_service_request_instance(service: str, inst: Any, args: dict) -> Any:
def args_to_service_request_instance(service: str, inst: Any, args: list | dict | None) -> Any:
"""Populate a service request instance with the provided args
args can be a dictionary of values, or a list, or None
Expand Down Expand Up @@ -122,14 +122,14 @@ def call_service(
service = expand_topic_name(service, node_handle.get_name(), node_handle.get_namespace())

service_names_and_types = dict(node_handle.get_service_names_and_types())
service_type = service_names_and_types.get(service)
if service_type is None:
service_types = service_names_and_types.get(service)
if service_types is None:
raise InvalidServiceException(service)

# service_type is a tuple of types at this point; only one type is supported.
if len(service_type) > 1:
node_handle.get_logger().warning(f"More than one service type detected: {service_type}")
service_type = service_type[0]
if len(service_types) > 1:
node_handle.get_logger().warning(f"More than one service type detected: {service_types}")
service_type = service_types[0]

service_class = get_service_class(service_type)
inst = get_service_request_instance(service_type)
Expand Down
5 changes: 3 additions & 2 deletions rosbridge_library/src/rosbridge_library/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
# POSSIBILITY OF SUCH DAMAGE.

import time
from typing import Any

from rosbridge_library.capabilities.fragmentation import Fragmentation
from rosbridge_library.util import bson, json
Expand Down Expand Up @@ -81,9 +82,9 @@ class Protocol:
# !! this might be related to (or even be avoided by using) throttle_rate !!
delay_between_messages = 0
# global list of non-ros advertised services
external_service_list = {}
external_service_list: dict[str, Any] = {}
# global list of non-ros advertised actions
external_action_list = {}
external_action_list: dict[str, Any] = {}
# Use only BSON for the whole communication if the server has been started with bson_only_mode:=True
bson_only_mode = False

Expand Down
4 changes: 2 additions & 2 deletions rosbridge_library/src/rosbridge_library/util/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# try to import json-lib: 1st try ujson, 2nd try simplejson, else import standard Python json
try:
import ujson as json
import ujson as json # type: ignore[import-untyped]
except ImportError:
try:
import simplejson as json
import simplejson as json # type: ignore[import-untyped]
except ImportError:
import json # noqa: F401

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ def request_service():
try:
incoming = sock.recv(max_msg_length) # receive service_response from rosbridge
if buffer == "":
buffer = incoming
buffer = incoming.decode("utf-8")
if incoming == "":
print("closing socket")
sock.close()
break
else:
buffer = buffer + incoming
buffer = buffer + incoming.decode("utf-8")
# print "buffer-length:", len(buffer)
try: # try to access service_request directly (not fragmented)
data_object = json.loads(buffer)
Expand All @@ -90,14 +90,14 @@ def request_service():
"}{"
) # split buffer into fragments and re-fill curly brackets
result = []
for fragment in result_string:
if fragment[0] != "{":
fragment = "{" + fragment
if fragment[len(fragment) - 1] != "}":
fragment = fragment + "}"
for fragment_str in result_string:
if fragment_str[0] != "{":
fragment_str = "{" + fragment_str
if fragment_str[len(fragment_str) - 1] != "}":
fragment_str = fragment_str + "}"
try:
result.append(
json.loads(fragment)
json.loads(fragment_str)
) # try to parse json from string, and append if successful
except Exception:
# print(e)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/python
import socket
from typing import Any

from rosbridge_library.util import json

Expand Down Expand Up @@ -63,13 +64,13 @@ def request_service():
try:
incoming = sock.recv(max_msg_length) # receive service_response from rosbridge
if buffer == "":
buffer = incoming
buffer = incoming.decode("utf-8")
if incoming == "":
print("closing socket")
sock.close()
break
else:
buffer = buffer + incoming
buffer = buffer + incoming.decode("utf-8")
# print "buffer-length:", len(buffer)
try: # try to access service_request directly (not fragmented)
data_object = json.loads(buffer)
Expand All @@ -86,14 +87,14 @@ def request_service():
"}{"
) # split buffer into fragments and re-fill curly brackets
result = []
for fragment in result_string:
if fragment[0] != "{":
fragment = "{" + fragment
if fragment[len(fragment) - 1] != "}":
fragment = fragment + "}"
for fragment_str in result_string:
if fragment_str[0] != "{":
fragment_str = "{" + fragment_str
if fragment_str[len(fragment_str) - 1] != "}":
fragment_str = fragment_str + "}"
try:
result.append(
json.loads(fragment)
json.loads(fragment_str)
) # try to parse json from string, and append if successful
except Exception:
# print(e)
Expand All @@ -105,7 +106,7 @@ def request_service():
announced = int(result[0]["total"])
if fragment_count == announced: # if all fragments received --> sort and defragment
# sort fragments
sorted_result = [None] * fragment_count
sorted_result: list[Any] = [None] * fragment_count
unsorted_result = []
for fragment in result:
unsorted_result.append(fragment)
Expand Down
3 changes: 3 additions & 0 deletions rosbridge_server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ if(BUILD_TESTING)
add_launch_test(test/websocket/transient_local_publisher.test.py)
add_launch_test(test/websocket/best_effort_publisher.test.py)
add_launch_test(test/websocket/multiple_subscribers_raw.test.py)

find_package(ament_cmake_mypy REQUIRED)
ament_mypy()
endif()
1 change: 1 addition & 0 deletions rosbridge_server/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<exec_depend>rosbridge_msgs</exec_depend>
<exec_depend>rosapi</exec_depend>

<test_depend>ament_cmake_mypy</test_depend>
<test_depend>example_interfaces</test_depend>
<test_depend>python3-autobahn</test_depend>
<test_depend>launch</test_depend>
Expand Down
Loading

0 comments on commit 5444d9b

Please sign in to comment.