-
Notifications
You must be signed in to change notification settings - Fork 158
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor get topic names and types (#4)
* ros2topic: use rclpy utility * ros2topic: fixup * ros2topic: support multiple types * ros2service: initial commit * ros2topic: support no_demangle * fix include order * missed a commit * ros2service: add pep257 tests * fix echo to support multiple types * improve shutdown behavior of call, add loop option * address comments
- Loading branch information
Showing
16 changed files
with
409 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?xml version="1.0"?> | ||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> | ||
<package format="2"> | ||
<name>ros2service</name> | ||
<version>0.0.0</version> | ||
<description> | ||
The service command for ROS 2 command line tools. | ||
</description> | ||
<maintainer email="william@osrfoundation.org">William Woodall</maintainer> | ||
<license>Apache License 2.0</license> | ||
|
||
<depend>rclpy</depend> | ||
<depend>ros2cli</depend> | ||
|
||
<test_depend>ament_copyright</test_depend> | ||
<test_depend>ament_flake8</test_depend> | ||
<test_depend>ament_pep257</test_depend> | ||
|
||
<export> | ||
<build_type>ament_python</build_type> | ||
</export> | ||
</package> |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from rclpy.topic_or_service_is_hidden import topic_or_service_is_hidden | ||
from ros2cli.node.strategy import NodeStrategy | ||
|
||
|
||
def get_service_names_and_types(*, node, include_hidden_services=False): | ||
service_names_and_types = node.get_service_names_and_types() | ||
if not include_hidden_services: | ||
service_names_and_types = [ | ||
(n, t) for (n, t) in service_names_and_types | ||
if not topic_or_service_is_hidden(n)] | ||
return service_names_and_types | ||
|
||
|
||
def get_service_names(*, node, include_hidden_services=False): | ||
service_names_and_types = get_service_names_and_types( | ||
node=node, include_hidden_services=include_hidden_services) | ||
return [n for (n, t) in service_names_and_types] | ||
|
||
|
||
class ServiceNameCompleter(object): | ||
"""Callable returning a list of service names.""" | ||
|
||
def __init__(self, *, include_hidden_services_key=None): | ||
self.include_hidden_services_key = include_hidden_services_key | ||
|
||
def __call__(self, prefix, parsed_args, **kwargs): | ||
with NodeStrategy(parsed_args) as node: | ||
return get_service_names( | ||
node=node, | ||
include_hidden_services=getattr( | ||
parsed_args, self.include_hidden_services_key)) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ros2cli.command import add_subparsers | ||
from ros2cli.command import CommandExtension | ||
from ros2cli.verb import get_verb_extensions | ||
|
||
|
||
class ServiceCommand(CommandExtension): | ||
"""Various service related sub-commands.""" | ||
|
||
def add_arguments(self, parser, cli_name): | ||
parser.add_argument( | ||
'--include-hidden-services', action='store_true', | ||
help='Consider hidden services as well') | ||
|
||
# get verb extensions and let them add their arguments | ||
verb_extensions = get_verb_extensions('ros2service.verb') | ||
add_subparsers(parser, cli_name, '_verb', verb_extensions) | ||
|
||
def main(self, *, parser, args): | ||
# the attribute should always exist | ||
# otherwise argparse should have exited | ||
extension = getattr(args, '_verb') | ||
|
||
# call the verb's main method | ||
return extension.main(args=args) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ros2cli.plugin_system import PLUGIN_SYSTEM_VERSION | ||
from ros2cli.plugin_system import satisfies_version | ||
|
||
|
||
class VerbExtension(object): | ||
""" | ||
The extension point for 'service' verb extensions. | ||
The following properties must be defined: | ||
* `NAME` (will be set to the entry point name) | ||
The following methods must be defined: | ||
* `main` | ||
The following methods can be defined: | ||
* `add_arguments` | ||
""" | ||
|
||
NAME = None | ||
EXTENSION_POINT_VERSION = '0.1' | ||
|
||
def __init__(self): | ||
super(VerbExtension, self).__init__() | ||
satisfies_version(PLUGIN_SYSTEM_VERSION, '^0.1') | ||
|
||
def add_arguments(self, parser, cli_name): | ||
pass | ||
|
||
def main(self, *, args): | ||
raise NotImplementedError() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# Copyright 2016-2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import argparse | ||
import importlib | ||
import json | ||
import time | ||
|
||
import rclpy | ||
from ros2service.api import ServiceNameCompleter | ||
from ros2service.verb import VerbExtension | ||
|
||
|
||
class CallVerb(VerbExtension): | ||
"""Call a service.""" | ||
|
||
def add_arguments(self, parser, cli_name): | ||
arg = parser.add_argument( | ||
'service_name', | ||
help="Name of the ROS service to call to (e.g. '/add_two_ints')") | ||
arg.completer = ServiceNameCompleter( | ||
include_hidden_services_key='include_hidden_services') | ||
parser.add_argument( | ||
'service_type', | ||
help="Type of the ROS service (e.g. 'std_srvs/Empty')") | ||
parser.add_argument( | ||
'values', nargs='?', default='{}', | ||
help='Values to fill the service request with in JSON format ' + | ||
'(e.g. {"a": 1, "b": 2}), ' + | ||
'otherwise the service request will be published with default values') | ||
|
||
def float_or_int(input_string): | ||
try: | ||
value = float(input_string) | ||
except ValueError: | ||
raise argparse.ArgumentTypeError("'%s' is not an integer or float" % input_string) | ||
return value | ||
|
||
parser.add_argument( | ||
'-r', '--repeat', metavar='N', type=float_or_int, | ||
help='Repeat the call every N seconds') | ||
|
||
def main(self, *, args): | ||
return requester(args.service_type, args.service_name, args.values, args.repeat) | ||
|
||
|
||
def requester(service_type, service_name, values, repeat): | ||
# TODO(wjwwood) this logic should come from a rosidl related package | ||
try: | ||
package_name, srv_name = service_type.split('/', 2) | ||
except ValueError: | ||
raise RuntimeError('The passed service type is invalid') | ||
module = importlib.import_module(package_name + '.srv') | ||
srv_module = getattr(module, srv_name) | ||
values_dictionary = json.loads(values) | ||
|
||
rclpy.init() | ||
|
||
node = rclpy.create_node('requester_%s_%s' % (package_name, srv_name)) | ||
|
||
cli = node.create_client(srv_module, service_name) | ||
|
||
request = srv_module.Request() | ||
for field_name, field_value in values_dictionary.items(): | ||
field_type = type(getattr(request, field_name)) | ||
setattr(request, field_name, field_type(field_value)) | ||
|
||
while True: | ||
print('requester: making request: %r\n' % request) | ||
last_call = time.time() | ||
cli.call(request) | ||
cli.wait_for_future() | ||
if cli.response is not None: | ||
print('response:\n%r\n' % cli.response) | ||
if repeat is None or not rclpy.ok(): | ||
break | ||
time_until_next_period = (last_call + repeat) - time.time() | ||
if time_until_next_period > 0: | ||
time.sleep(time_until_next_period) | ||
|
||
node.destroy_node() | ||
rclpy.try_shutdown() # avoid duplicate shutdown from shutdown within cli.wait_for_future() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ros2cli.node.strategy import add_arguments | ||
from ros2cli.node.strategy import NodeStrategy | ||
from ros2service.api import get_service_names_and_types | ||
from ros2service.verb import VerbExtension | ||
|
||
|
||
class ListVerb(VerbExtension): | ||
"""Output a list of available services.""" | ||
|
||
def add_arguments(self, parser, cli_name): | ||
add_arguments(parser) | ||
parser.add_argument( | ||
'-t', '--show-types', action='store_true', | ||
help='Additionally show the service type') | ||
parser.add_argument( | ||
'-c', '--count-services', action='store_true', | ||
help='Only display the number of services discovered') | ||
|
||
def main(self, *, args): | ||
with NodeStrategy(args) as node: | ||
service_names_and_types = get_service_names_and_types( | ||
node=node, include_hidden_services=args.include_hidden_services) | ||
|
||
if args.count_services: | ||
print(len(service_names_and_types)) | ||
elif service_names_and_types: | ||
for (service_name, service_types) in service_names_and_types: | ||
msg = '{service_name}' | ||
service_types_formatted = ', '.join(service_types) | ||
if args.show_types: | ||
msg += ' [{service_types_formatted}]' | ||
print(msg.format_map(locals())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from setuptools import find_packages | ||
from setuptools import setup | ||
|
||
setup( | ||
name='ros2service', | ||
version='0.0.0', | ||
packages=find_packages(exclude=['test']), | ||
install_requires=['ros2cli'], | ||
author='William Woodall', | ||
author_email='william@osrfoundation.org', | ||
maintainer='William Woodall', | ||
maintainer_email='william@osrfoundation.org', | ||
url='https://github.com/ros2/ros2cli/tree/master/ros2service', | ||
download_url='https://github.com/ros2/ros2cli/releases', | ||
keywords=[], | ||
classifiers=[ | ||
'Environment :: Console', | ||
'Intended Audience :: Developers', | ||
'License :: OSI Approved :: Apache Software License', | ||
'Programming Language :: Python', | ||
], | ||
description='The service command for ROS 2 command line tools.', | ||
long_description="""\ | ||
The package provides the service command for the ROS 2 command line tools.""", | ||
license='Apache License, Version 2.0', | ||
test_suite='test', | ||
entry_points={ | ||
'ros2cli.command': [ | ||
'service = ros2service.command.service:ServiceCommand', | ||
], | ||
'ros2cli.extension_point': [ | ||
'ros2service.verb = ros2service.verb:VerbExtension', | ||
], | ||
'ros2service.verb': [ | ||
'call = ros2service.verb.call:CallVerb', | ||
'list = ros2service.verb.list:ListVerb', | ||
], | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ament_copyright.main import main | ||
|
||
|
||
def test_copyright(): | ||
rc = main(argv=['.', 'test']) | ||
assert rc == 0, 'Found errors' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ament_flake8.main import main | ||
|
||
|
||
def test_flake8(): | ||
rc = main(argv=[]) | ||
assert rc == 0, 'Found errors' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright 2017 Open Source Robotics Foundation, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
from ament_pep257.main import main | ||
|
||
|
||
def test_pep257(): | ||
rc = main(argv=[]) | ||
assert rc == 0, 'Found code style errors / warnings' |
Oops, something went wrong.