diff --git a/ros2node/ros2node/api/__init__.py b/ros2node/ros2node/api/__init__.py index 512f7e34b..d49ecafb0 100644 --- a/ros2node/ros2node/api/__init__.py +++ b/ros2node/ros2node/api/__init__.py @@ -13,6 +13,8 @@ # limitations under the License. from collections import namedtuple +from typing import Any +from typing import List from rclpy.action.graph import get_action_client_names_and_types_by_node from rclpy.action.graph import get_action_server_names_and_types_by_node @@ -51,6 +53,11 @@ def parse_node_name(node_name): return NodeName(node_basename, namespace, full_node_name) +def has_duplicates(values: List[Any]) -> bool: + """Find out if there are any exact duplicates in a list of strings.""" + return len(set(values)) < len(values) + + def get_node_names(*, node, include_hidden_nodes=False): node_names_and_namespaces = node.get_node_names_and_namespaces() return [ diff --git a/ros2node/ros2node/verb/list.py b/ros2node/ros2node/verb/list.py index 55eaad52b..6dea04cde 100644 --- a/ros2node/ros2node/verb/list.py +++ b/ros2node/ros2node/verb/list.py @@ -12,9 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +import sys + from ros2cli.node.strategy import add_arguments from ros2cli.node.strategy import NodeStrategy from ros2node.api import get_node_names +from ros2node.api import has_duplicates from ros2node.verb import VerbExtension @@ -37,4 +40,8 @@ def main(self, *, args): if args.count_nodes: print(len(node_names)) elif node_names: - print(*sorted(n.full_name for n in node_names), sep='\n') + sorted_names = sorted(n.full_name for n in node_names) + if has_duplicates(sorted_names): + print('WARNING: Be aware that are nodes in the graph that share an exact name, ' + 'this can have unintended side effects.', file=sys.stderr) + print(*sorted_names, sep='\n') diff --git a/ros2node/test/test_node.py b/ros2node/test/test_node.py index d07addbb8..43a1e0ce3 100644 --- a/ros2node/test/test_node.py +++ b/ros2node/test/test_node.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from ros2node.api import has_duplicates from ros2node.api import parse_node_name @@ -34,3 +35,11 @@ def test_parse_node_name(): assert name.full_name == '/ns/talker' assert name.namespace == '/ns' assert name.name == 'talker' + + +def test_has_duplicates(): + assert not has_duplicates([]) + assert not has_duplicates(['ns_foo/foo', 'ns_foo/bar']) + assert has_duplicates(['ns_foo/foo'] * 2) + assert has_duplicates(['ns_foo/foo'] * 3) + assert has_duplicates(['ns_foo/foo', 'ns_foo/foo', 'ns_foo/bar'])