From 7b212b8654252edd12af822e9e1fe8f5e4ccf770 Mon Sep 17 00:00:00 2001 From: Kenji Miyake Date: Sat, 25 Sep 2021 03:06:37 +0900 Subject: [PATCH 1/7] Add pre-commit Signed-off-by: Kenji Miyake --- .github/workflows/pre-commit.yaml | 19 +++++++++++++++ .pre-commit-config.yaml | 40 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 .github/workflows/pre-commit.yaml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml new file mode 100644 index 000000000..f273d445d --- /dev/null +++ b/.github/workflows/pre-commit.yaml @@ -0,0 +1,19 @@ +name: pre-commit + +on: + pull_request: + workflow_dispatch: + +jobs: + pre-commit: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Run pre-commit + uses: pre-commit/action@v2.0.3 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..ef4064acc --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,40 @@ +# Modified from https://github.com/ros-planning/moveit2/blob/d184714751b347a2389cf1e8742b1be94eed63b8/.pre-commit-config.yaml +# +# To use: +# +# pre-commit run -a +# +# Or: +# +# pre-commit install # (runs every time you commit in git) +# +# To update this file: +# +# pre-commit autoupdate +# +# See https://github.com/pre-commit/pre-commit + +repos: + # Standard hooks + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-json + - id: check-merge-conflict + - id: check-symlinks + - id: check-toml + - id: check-yaml + - id: debug-statements + - id: destroyed-symlinks + - id: detect-private-key + - id: end-of-file-fixer + - id: mixed-line-ending + - id: pretty-format-json + - id: trailing-whitespace + + - repo: https://github.com/psf/black + rev: 21.9b0 + hooks: + - id: black From ea5609fd492e7627cbe4d9d91047131dc400b38c Mon Sep 17 00:00:00 2001 From: Kenji Miyake Date: Sat, 25 Sep 2021 03:08:42 +0900 Subject: [PATCH 2/7] Apply pre-commit to python files Signed-off-by: Kenji Miyake --- rosapi/src/rosapi/glob_helper.py | 23 +- rosapi/src/rosapi/objectutils.py | 105 ++-- rosapi/src/rosapi/params.py | 81 +++- rosapi/src/rosapi/proxy.py | 124 +++-- rosapi/src/rosapi/stringify_field_types.py | 4 +- .../capabilities/advertise.py | 68 ++- .../capabilities/advertise_service.py | 54 ++- .../capabilities/call_service.py | 52 +- .../capabilities/defragmentation.py | 79 +-- .../capabilities/fragmentation.py | 51 +- .../rosbridge_library/capabilities/publish.py | 32 +- .../capabilities/service_response.py | 15 +- .../capabilities/subscribe.py | 157 ++++-- .../capabilities/unadvertise_service.py | 44 +- .../src/rosbridge_library/capability.py | 23 +- .../internal/cbor_conversion.py | 49 +- .../rosbridge_library/internal/exceptions.py | 2 + .../internal/message_conversion.py | 139 ++++-- .../internal/outgoing_message.py | 5 +- .../internal/pngcompression.py | 13 +- .../rosbridge_library/internal/publishers.py | 98 ++-- .../rosbridge_library/internal/ros_loader.py | 63 +-- .../rosbridge_library/internal/services.py | 17 +- .../rosbridge_library/internal/subscribers.py | 57 ++- .../internal/subscription_modifiers.py | 14 +- .../src/rosbridge_library/internal/topics.py | 19 +- .../src/rosbridge_library/protocol.py | 92 ++-- .../rosbridge_library/rosbridge_protocol.py | 19 +- .../src/rosbridge_library/util/__init__.py | 1 + .../src/rosbridge_library/util/cbor.py | 135 +++--- .../test/capabilities/test_advertise.py | 143 ++++-- .../test/capabilities/test_call_service.py | 31 +- .../test/capabilities/test_publish.py | 13 +- .../capabilities/test_service_capabilities.py | 168 ++++--- .../test/capabilities/test_subscribe.py | 26 +- ...test_non-ros_service_client_complex-srv.py | 95 ++-- ...test_non-ros_service_server_complex-srv.py | 226 +++++---- .../test_non-ros_service_client_fragmented.py | 89 ++-- .../test_non-ros_service_server_fragmented.py | 229 +++++---- .../publishers/test_multi_publisher.py | 39 +- .../publishers/test_multi_unregistering.py | 13 +- .../publishers/test_publisher_manager.py | 38 +- .../subscribers/test_multi_subscriber.py | 30 +- .../subscribers/test_subscriber_manager.py | 31 +- .../test_subscription_modifiers.py | 21 +- .../test/internal/test_cbor_conversion.py | 148 +++--- .../test/internal/test_compression.py | 9 +- .../test/internal/test_message_conversion.py | 93 ++-- .../test/internal/test_outgoing_message.py | 10 +- .../test/internal/test_ros_loader.py | 459 +++++++++++++----- .../test/internal/test_services.py | 78 ++- rosbridge_server/scripts/rosbridge_tcp.py | 103 ++-- rosbridge_server/scripts/rosbridge_udp.py | 85 ++-- .../scripts/rosbridge_websocket.py | 130 +++-- .../src/rosbridge_server/client_mananger.py | 12 +- .../src/rosbridge_server/tcp_handler.py | 68 +-- .../src/rosbridge_server/udp_handler.py | 18 +- .../src/rosbridge_server/websocket_handler.py | 51 +- 58 files changed, 2641 insertions(+), 1450 deletions(-) diff --git a/rosapi/src/rosapi/glob_helper.py b/rosapi/src/rosapi/glob_helper.py index 82ddd0d14..0e52e39db 100644 --- a/rosapi/src/rosapi/glob_helper.py +++ b/rosapi/src/rosapi/glob_helper.py @@ -4,26 +4,26 @@ import fnmatch from rcl_interfaces.msg import ParameterType -Globs = namedtuple('Globs', ['topics', 'services', 'params']) +Globs = namedtuple("Globs", ["topics", "services", "params"]) def get_globs(node): - def get_param(parameter_name): parameter_value = node.get_parameter(parameter_name).get_parameter_value() if parameter_value.type == ParameterType.PARAMETER_STRING: parameter_value = parameter_value.string_value else: - parameter_value = '' + parameter_value = "" # strips array delimiters in case of an array style value return [ element.strip().strip("'") - for element in parameter_value.strip('[').strip(']').split(',') - if len(element.strip().strip("'")) > 0] + for element in parameter_value.strip("[").strip("]").split(",") + if len(element.strip().strip("'")) > 0 + ] - topics_glob = get_param('topics_glob') - services_glob = get_param('services_glob') - params_glob = get_param('params_glob') + topics_glob = get_param("topics_glob") + services_glob = get_param("services_glob") + params_glob = get_param("params_glob") return Globs(topics_glob, services_glob, params_glob) @@ -36,5 +36,8 @@ def filter_globs(globs, full_list): def any_match(query, globs): - return globs is None or len(globs) == 0 or any(fnmatch.fnmatch(str(query), glob) for glob in globs) - + return ( + globs is None + or len(globs) == 0 + or any(fnmatch.fnmatch(str(query), glob) for glob in globs) + ) diff --git a/rosapi/src/rosapi/objectutils.py b/rosapi/src/rosapi/objectutils.py index da29801cb..0f825e4e1 100644 --- a/rosapi/src/rosapi/objectutils.py +++ b/rosapi/src/rosapi/objectutils.py @@ -36,11 +36,26 @@ import inspect # Keep track of atomic types and special types -atomics = ['bool', 'byte','int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', 'float32', 'float64', 'string'] -specials = ['time', 'duration'] +atomics = [ + "bool", + "byte", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float32", + "float64", + "string", +] +specials = ["time", "duration"] + def get_typedef(type): - """ A typedef is a dict containing the following fields: + """A typedef is a dict containing the following fields: - string type - string[] fieldnames - string[] fieldtypes @@ -48,7 +63,7 @@ def get_typedef(type): - string[] examples - string[] constnames - string[] constvalues - get_typedef will return a typedef dict for the specified message type """ + get_typedef will return a typedef dict for the specified message type""" if type in atomics: # Atomics don't get a typedef return None @@ -61,25 +76,29 @@ def get_typedef(type): instance = ros_loader.get_message_instance(type) return _get_typedef(instance) + def get_service_request_typedef(servicetype): - """ Returns a typedef dict for the service request class for the specified service type """ + """Returns a typedef dict for the service request class for the specified service type""" # Get an instance of the service request class and return its typedef instance = ros_loader.get_service_request_instance(servicetype) return _get_typedef(instance) + def get_service_response_typedef(servicetype): - """ Returns a typedef dict for the service response class for the specified service type """ + """Returns a typedef dict for the service response class for the specified service type""" # Get an instance of the service response class and return its typedef instance = ros_loader.get_service_response_instance(servicetype) return _get_typedef(instance) + def get_typedef_recursive(type): - """ Returns a list of typedef dicts for this type and all contained type fields """ + """Returns a list of typedef dicts for this type and all contained type fields""" # Just go straight into the recursive method return _get_typedefs_recursive(type, []) + def get_service_request_typedef_recursive(servicetype): - """ Returns a list of typedef dicts for this type and all contained type fields """ + """Returns a list of typedef dicts for this type and all contained type fields""" # Get an instance of the service request class and get its typedef instance = ros_loader.get_service_request_instance(servicetype) typedef = _get_typedef(instance) @@ -87,8 +106,9 @@ def get_service_request_typedef_recursive(servicetype): # Return the list of sub-typedefs return _get_subtypedefs_recursive(typedef, []) + def get_service_response_typedef_recursive(servicetype): - """ Returns a list of typedef dicts for this type and all contained type fields """ + """Returns a list of typedef dicts for this type and all contained type fields""" # Get an instance of the service response class and get its typedef instance = ros_loader.get_service_response_instance(servicetype) typedef = _get_typedef(instance) @@ -96,8 +116,9 @@ def get_service_response_typedef_recursive(servicetype): # Return the list of sub-typedefs return _get_subtypedefs_recursive(typedef, []) + def get_typedef_full_text(ty): - """ Returns the full text (similar to `gendeps --cat`) for the specified message type """ + """Returns the full text (similar to `gendeps --cat`) for the specified message type""" try: return stringify_field_types(ty) except Exception as e: @@ -105,8 +126,12 @@ def get_typedef_full_text(ty): def _get_typedef(instance): - """ Gets a typedef dict for the specified instance """ - if instance is None or not hasattr(instance, "__slots__") or not hasattr(instance, "_fields_and_field_types"): + """Gets a typedef dict for the specified instance""" + if ( + instance is None + or not hasattr(instance, "__slots__") + or not hasattr(instance, "_fields_and_field_types") + ): return None fieldnames = [] @@ -121,15 +146,17 @@ def _get_typedef(instance): fieldnames.append(name) # Pull out the type and determine whether it's an array - field_type = instance._fields_and_field_types[name[1:]] # Remove trailing underscore. + field_type = instance._fields_and_field_types[ + name[1:] + ] # Remove trailing underscore. arraylen = -1 - if field_type[-1:]==']': - if field_type[-2:-1]=='[': + if field_type[-1:] == "]": + if field_type[-2:-1] == "[": arraylen = 0 field_type = field_type[:-2] else: - split = field_type.find('[') - arraylen = int(field_type[split+1:-1]) + split = field_type.find("[") + arraylen = int(field_type[split + 1 : -1]) field_type = field_type[:split] fieldarraylen.append(arraylen) @@ -139,7 +166,7 @@ def _get_typedef(instance): # Set the example as appropriate example = field_instance - if arraylen>=0: + if arraylen >= 0: example = [] elif field_type not in atomics: example = {} @@ -148,38 +175,44 @@ def _get_typedef(instance): # Add pseudo constants names and values filtering members attributes = inspect.getmembers(instance) for attribute in attributes: - if attribute[0] not in instance.__slots__ and not attribute[0].startswith('_') and not inspect.isroutine(attribute[1]): + if ( + attribute[0] not in instance.__slots__ + and not attribute[0].startswith("_") + and not inspect.isroutine(attribute[1]) + ): constnames.append(str(attribute[0])) constvalues.append(str(attribute[1])) typedef = { - "type" : _type_name_from_instance(instance), - "fieldnames" : fieldnames, - "fieldtypes" : fieldtypes, - "fieldarraylen" : fieldarraylen, - "examples" : examples, - "constnames" : constnames, - "constvalues" : constvalues + "type": _type_name_from_instance(instance), + "fieldnames": fieldnames, + "fieldtypes": fieldtypes, + "fieldarraylen": fieldarraylen, + "examples": examples, + "constnames": constnames, + "constvalues": constvalues, } return typedef + def _get_special_typedef(type): example = None - if type=="time" or type=="duration": + if type == "time" or type == "duration": example = { "type": type, "fieldnames": ["secs", "nsecs"], "fieldtypes": ["int32", "int32"], "fieldarraylen": [-1, -1], - "examples": [ "0", "0" ], + "examples": ["0", "0"], "constnames": [], - "constvalues": [] + "constvalues": [], } return example + def _get_typedefs_recursive(type, typesseen): - """ returns the type def for this type as well as the type defs for any fields within the type """ + """returns the type def for this type as well as the type defs for any fields within the type""" if type in typesseen: # Don't put a type if it's already been seen return [] @@ -192,20 +225,22 @@ def _get_typedefs_recursive(type, typesseen): return _get_subtypedefs_recursive(typedef, typesseen) + def _get_subtypedefs_recursive(typedef, typesseen): if typedef is None: return [] # Create the list of subtypes and get the typedefs for fields - typedefs = [ typedef ] + typedefs = [typedef] for fieldtype in typedef["fieldtypes"]: typedefs = typedefs + _get_typedefs_recursive(fieldtype, typesseen) return typedefs + def _type_name(type, instance): - """ given a short type, and an object instance of that type, - determines and returns the fully qualified type """ + """given a short type, and an object instance of that type, + determines and returns the fully qualified type""" # The fully qualified type of atomic and special types is just their original name if type in atomics or type in specials: return type @@ -218,8 +253,8 @@ def _type_name(type, instance): # Otherwise, the type will come from the module and class name of the instance return _type_name_from_instance(instance) + def _type_name_from_instance(instance): mod = instance.__module__ - type = mod[0:mod.find('.')]+"/"+instance.__class__.__name__ + type = mod[0 : mod.find(".")] + "/" + instance.__class__.__name__ return type - diff --git a/rosapi/src/rosapi/params.py b/rosapi/src/rosapi/params.py index 51565551c..f7015b25b 100644 --- a/rosapi/src/rosapi/params.py +++ b/rosapi/src/rosapi/params.py @@ -49,10 +49,19 @@ # Ensure thread safety for setting / getting parameters. param_server_lock = threading.RLock() _node = None -_parent_node_name = '' +_parent_node_name = "" -_parameter_type_mapping = ['', 'bool_value', 'integer_value', 'double_value', 'string_value', 'byte_array_value' - 'bool_array_value', 'integer_array_value', 'double_array_value', 'string_array_value'] +_parameter_type_mapping = [ + "", + "bool_value", + "integer_value", + "double_value", + "string_value", + "byte_array_value" "bool_array_value", + "integer_array_value", + "double_array_value", + "string_array_value", +] def init(parent_node_name): @@ -63,14 +72,16 @@ def init(parent_node_name): global _node, _parent_node_name # TODO(@jubeira): remove this node; use rosapi node with MultiThreadedExecutor or # async / await to prevent the service calls from blocking. - _node = rclpy.create_node('rosapi_params') + _node = rclpy.create_node("rosapi_params") _parent_node_name = get_absolute_node_name(parent_node_name) def set_param(node_name, name, value, params_glob): - """ Sets a parameter in a given node """ + """Sets a parameter in a given node""" - if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): + if params_glob and not any( + fnmatch.fnmatch(str(name), glob) for glob in params_glob + ): # If the glob list is not empty and there are no glob matches, # stop the attempt to set the parameter. return @@ -81,7 +92,9 @@ def set_param(node_name, name, value, params_glob): d = loads(value) value = d if isinstance(d, str) else value except ValueError: - raise Exception("Due to the type flexibility of the ROS parameter server, the value argument to set_param must be a JSON-formatted string.") + raise Exception( + "Due to the type flexibility of the ROS parameter server, the value argument to set_param must be a JSON-formatted string." + ) node_name = get_absolute_node_name(node_name) with param_server_lock: @@ -113,9 +126,11 @@ def _set_param(node_name, name, value, parameter_type=None): def get_param(node_name, name, default, params_glob): - """ Gets a parameter from a given node """ + """Gets a parameter from a given node""" - if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): + if params_glob and not any( + fnmatch.fnmatch(str(name), glob) for glob in params_glob + ): # If the glob list is not empty and there are no glob matches, # stop the attempt to get the parameter. return @@ -132,8 +147,8 @@ def get_param(node_name, name, default, params_glob): try: # call_get_parameters will fail if node does not exist. response = call_get_parameters( - node=_node, node_name=node_name, - parameter_names=[name]) + node=_node, node_name=node_name, parameter_names=[name] + ) pvalue = response.values[0] # if type is 0 (parameter not set), the next line will raise an exception # and return value shall go to default. @@ -146,9 +161,11 @@ def get_param(node_name, name, default, params_glob): def has_param(node_name, name, params_glob): - """ Checks whether a given node has a parameter or not """ + """Checks whether a given node has a parameter or not""" - if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): + if params_glob and not any( + fnmatch.fnmatch(str(name), glob) for glob in params_glob + ): # If the glob list is not empty and there are no glob matches, # stop the attempt to set the parameter. return False @@ -158,18 +175,22 @@ def has_param(node_name, name, params_glob): with param_server_lock: try: response = call_get_parameters( - node=_node, node_name=node_name, - parameter_names=[name]) + node=_node, node_name=node_name, parameter_names=[name] + ) except Exception: return False - return response.values[0].type > 0 and response.values[0].type < len(_parameter_type_mapping) + return response.values[0].type > 0 and response.values[0].type < len( + _parameter_type_mapping + ) def delete_param(node_name, name, params_glob): - """ Deletes a parameter in a given node """ + """Deletes a parameter in a given node""" - if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): + if params_glob and not any( + fnmatch.fnmatch(str(name), glob) for glob in params_glob + ): # If the glob list is not empty and there are no glob matches, # stop the attempt to delete the parameter. return @@ -190,16 +211,22 @@ def get_param_names(params_glob): return params + def get_node_param_names(node_name, params_glob): - """ Gets list of parameter names for a given node """ + """Gets list of parameter names for a given node""" node_name = get_absolute_node_name(node_name) with param_server_lock: if params_glob: # If there is a parameter glob, filter by it. - return list(filter( - lambda x: any(fnmatch.fnmatch(str(x), glob) for glob in params_glob), - _get_param_names(node_name))) + return list( + filter( + lambda x: any( + fnmatch.fnmatch(str(x), glob) for glob in params_glob + ), + _get_param_names(node_name), + ) + ) else: # If there is no parameter glob, don't filter. return _get_param_names(node_name) @@ -212,11 +239,11 @@ def _get_param_names(node_name): if node_name == _parent_node_name: return [] - client = _node.create_client(ListParameters, f'{node_name}/list_parameters') + client = _node.create_client(ListParameters, f"{node_name}/list_parameters") ready = client.wait_for_service(timeout_sec=5.0) if not ready: - raise RuntimeError('Wait for list_parameters service timed out') + raise RuntimeError("Wait for list_parameters service timed out") request = ListParameters.Request() future = client.call_async(request) @@ -224,14 +251,16 @@ def _get_param_names(node_name): response = future.result() if response is not None: - return [f'{node_name}:{param_name}' for param_name in response.result.names] + return [f"{node_name}:{param_name}" for param_name in response.result.names] else: return [] # TODO(@jubeira): functions to be ported below. def search_param(name, params_glob): - if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): + if params_glob and not any( + fnmatch.fnmatch(str(name), glob) for glob in params_glob + ): # If the glob list is not empty and there are no glob matches, # stop the attempt to find the parameter. return None diff --git a/rosapi/src/rosapi/proxy.py b/rosapi/src/rosapi/proxy.py index 0a5bc6357..ec10a64d4 100644 --- a/rosapi/src/rosapi/proxy.py +++ b/rosapi/src/rosapi/proxy.py @@ -31,7 +31,12 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from ros2node.api import get_node_names, get_publisher_info, get_service_server_info, get_subscriber_info +from ros2node.api import ( + get_node_names, + get_publisher_info, + get_service_server_info, + get_subscriber_info, +) from ros2service.api import get_service_names, get_service_names_and_types from ros2topic.api import get_topic_names, get_topic_names_and_types @@ -50,56 +55,78 @@ def init(node): def get_topics(topics_glob, include_hidden=False): - """ Returns a list of all the active topics in the ROS system """ + """Returns a list of all the active topics in the ROS system""" topic_names = get_topic_names(node=_node, include_hidden_topics=include_hidden) return filter_globs(topics_glob, topic_names) def get_topics_and_types(topics_glob, include_hidden=False): - return get_publications_and_types(topics_glob, get_topic_names_and_types, include_hidden_topics=include_hidden) + return get_publications_and_types( + topics_glob, get_topic_names_and_types, include_hidden_topics=include_hidden + ) def get_topics_for_type(topic_type, topics_glob, include_hidden=False): - topic_names_and_types = get_topic_names_and_types(node=_node, include_hidden_topics=include_hidden) + topic_names_and_types = get_topic_names_and_types( + node=_node, include_hidden_topics=include_hidden + ) # topic[0] has the topic name and topic[1] has the type wrapped in a list. - topics_for_type = [topic[0] for topic in topic_names_and_types if topic[1][0] == topic_type] + topics_for_type = [ + topic[0] for topic in topic_names_and_types if topic[1][0] == topic_type + ] return filter_globs(topics_glob, topics_for_type) def get_services(services_glob, include_hidden=False): - """ Returns a list of all the services advertised in the ROS system """ + """Returns a list of all the services advertised in the ROS system""" # Filter the list of services by whether they are public before returning. - service_names = get_service_names(node=_node, include_hidden_services=include_hidden) + service_names = get_service_names( + node=_node, include_hidden_services=include_hidden + ) return filter_globs(services_glob, service_names) def get_services_and_types(services_glob, include_hidden=False): - return get_publications_and_types(services_glob, get_service_names_and_types, include_hidden_services=include_hidden) + return get_publications_and_types( + services_glob, + get_service_names_and_types, + include_hidden_services=include_hidden, + ) def get_services_for_type(service_type, services_glob, include_hidden=False): - """ Returns a list of services as specific service type """ + """Returns a list of services as specific service type""" # Filter the list of services by whether they are public before returning. - services_names_and_types = get_service_names_and_types(node=_node, include_hidden_services=include_hidden) + services_names_and_types = get_service_names_and_types( + node=_node, include_hidden_services=include_hidden + ) # service[0] has the topic name and service[1] has the type wrapped in a list. - services_for_type = [service[0] for service in services_names_and_types if service[1][0] == service_type] + services_for_type = [ + service[0] + for service in services_names_and_types + if service[1][0] == service_type + ] return filter_globs(services_glob, services_for_type) def get_publications_and_types(glob, getter_function, **include_hidden_publications): - """ Generic getter function for both services and topics """ - publication_names_and_types = getter_function(node=_node, **include_hidden_publications) + """Generic getter function for both services and topics""" + publication_names_and_types = getter_function( + node=_node, **include_hidden_publications + ) # publication[0] has the publication name and publication[1] has the type wrapped in a list. all_publications = [publication[0] for publication in publication_names_and_types] filtered_publications = filter_globs(glob, all_publications) - filtered_publication_types = [publication[1][0] for publication - in publication_names_and_types - if publication[0] in filtered_publications] + filtered_publication_types = [ + publication[1][0] + for publication in publication_names_and_types + if publication[0] in filtered_publications + ] return filtered_publications, filtered_publication_types def get_nodes(include_hidden=False): - """ Returns a list of all the nodes registered in the ROS system """ + """Returns a list of all the nodes registered in the ROS system""" node_names = get_node_names(node=_node, include_hidden_nodes=include_hidden) full_names = [node_name.full_name for node_name in node_names] return full_names @@ -117,31 +144,31 @@ def get_node_info(node_name, include_hidden=False): def get_node_publications(node_name): - """ Returns a list of topic names that are being published by the specified node """ + """Returns a list of topic names that are being published by the specified node""" publishers = get_publisher_info(node=_node, remote_node_name=node_name) return [publisher.name for publisher in publishers] def get_node_subscriptions(node_name): - """ Returns a list of topic names that are being subscribed by the specified node """ + """Returns a list of topic names that are being subscribed by the specified node""" subscribers = get_subscriber_info(node=_node, remote_node_name=node_name) return [subscriber.name for subscriber in subscribers] def get_node_services(node_name): - """ Returns a list of service names that are being hosted by the specified node """ + """Returns a list of service names that are being hosted by the specified node""" services = get_service_server_info(node=_node, remote_node_name=node_name) return [service.name for service in services] def get_node_service_types(node_name): - """ Returns a list of service types that are being hosted by the specified node """ + """Returns a list of service types that are being hosted by the specified node""" services = get_service_server_info(node=_node, remote_node_name=node_name) return [service.types[0] for service in services] def get_topic_type(topic, topics_glob): - """ Returns the type of the specified ROS topic """ + """Returns the type of the specified ROS topic""" # Note: this doesn't consider hidden topics. topics, types = get_topics_and_types(topics_glob) try: @@ -152,23 +179,23 @@ def get_topic_type(topic, topics_glob): def filter_action_servers(topics): - """ Returns a list of action servers """ + """Returns a list of action servers""" # Note(@jubeira): filtering by topic should be enough; services can be taken into account as well. action_servers = [] - possible_action_server = '' + possible_action_server = "" possibility = [0, 0] - action_topics = ['feedback', 'status'] + action_topics = ["feedback", "status"] for topic in sorted(topics): - split = topic.split('/') - if(len(split) >= 4): + split = topic.split("/") + if len(split) >= 4: topic = split.pop() action_prefix = split.pop() - if action_prefix != '_action': + if action_prefix != "_action": continue - namespace = '/'.join(split) - if(possible_action_server != namespace): + namespace = "/".join(split) + if possible_action_server != namespace: possible_action_server = namespace possibility = [0, 0] if possible_action_server == namespace and topic in action_topics: @@ -181,7 +208,7 @@ def filter_action_servers(topics): def get_service_type(service, services_glob): - """ Returns the type of the specified ROS service, """ + """Returns the type of the specified ROS service,""" # Note: this doesn't consider hidden services. services, types = get_services_and_types(services_glob) try: @@ -192,8 +219,8 @@ def get_service_type(service, services_glob): def get_channel_info(channel, channels_glob, getter_function, include_hidden=False): - """ Returns a list of node names that are publishing / subscribing to the specified topic, - or advertising a given service. """ + """Returns a list of node names that are publishing / subscribing to the specified topic, + or advertising a given service.""" if any_match(str(channel), channels_glob): channel_info_list = [] node_list = get_nodes(include_hidden) @@ -207,23 +234,34 @@ def get_channel_info(channel, channels_glob, getter_function, include_hidden=Fal def get_publishers(topic, topics_glob, include_hidden=False): - """ Returns a list of node names that are publishing the specified topic """ - return get_channel_info(topic, topics_glob, get_node_publications, include_hidden=include_hidden) + """Returns a list of node names that are publishing the specified topic""" + return get_channel_info( + topic, topics_glob, get_node_publications, include_hidden=include_hidden + ) def get_subscribers(topic, topics_glob, include_hidden=False): - """ Returns a list of node names that are subscribing to the specified topic """ - return get_channel_info(topic, topics_glob, get_node_subscriptions, include_hidden=include_hidden) + """Returns a list of node names that are subscribing to the specified topic""" + return get_channel_info( + topic, topics_glob, get_node_subscriptions, include_hidden=include_hidden + ) def get_service_providers(queried_type, services_glob, include_hidden=False): - """ Returns a list of node names that are advertising a service with the specified type """ - return get_channel_info(queried_type, services_glob, get_node_service_types, include_hidden=include_hidden) + """Returns a list of node names that are advertising a service with the specified type""" + return get_channel_info( + queried_type, + services_glob, + get_node_service_types, + include_hidden=include_hidden, + ) def get_service_node(queried_type, services_glob, include_hidden=False): - """ Returns the name of the node that is providing the given service, or empty string """ - node_name = get_channel_info(queried_type, services_glob, get_node_services, include_hidden=include_hidden) + """Returns the name of the node that is providing the given service, or empty string""" + node_name = get_channel_info( + queried_type, services_glob, get_node_services, include_hidden=include_hidden + ) if node_name: return node_name[0] else: @@ -231,11 +269,11 @@ def get_service_node(queried_type, services_glob, include_hidden=False): def get_service_host(service): - """ Returns the name of the machine that is hosting the given service, or empty string """ + """Returns the name of the machine that is hosting the given service, or empty string""" uri = get_service_uri(service) # noqa: F821 # To be fixed in issue #604 if uri is None: uri = "" else: uri = uri[9:] - uri = uri[:uri.find(':')] + uri = uri[: uri.find(":")] return uri diff --git a/rosapi/src/rosapi/stringify_field_types.py b/rosapi/src/rosapi/stringify_field_types.py index 49b36db69..f6b280d6e 100644 --- a/rosapi/src/rosapi/stringify_field_types.py +++ b/rosapi/src/rosapi/stringify_field_types.py @@ -17,9 +17,7 @@ def stringify_field_types(root_type): msg_name = parts[2] if len(parts) == 3 else parts[1] interface_name = ty if len(parts) == 3 else f"{parts[0]}/msg/{parts[1]}" - with open( - get_interface_path(interface_name), encoding="utf-8" - ) as msg_file: + with open(get_interface_path(interface_name), encoding="utf-8") as msg_file: msg_definition = msg_file.read() definition += msg_definition diff --git a/rosbridge_library/src/rosbridge_library/capabilities/advertise.py b/rosbridge_library/src/rosbridge_library/capabilities/advertise.py index 316efc281..a3660da80 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/advertise.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/advertise.py @@ -36,8 +36,8 @@ from rosbridge_library.internal.publishers import manager -class Registration(): - """ Keeps track of how many times a client has requested to advertise +class Registration: + """Keeps track of how many times a client has requested to advertise a publisher. A client could advertise and unadvertise a topic multiple times, and we @@ -56,10 +56,18 @@ def __init__(self, client_id, topic, node_handle): def unregister(self): manager.unregister(self.client_id, self.topic) - def register_advertisement(self, msg_type, adv_id=None, latch=False, queue_size=100): + def register_advertisement( + self, msg_type, adv_id=None, latch=False, queue_size=100 + ): # Register with the publisher manager, propagating any exception manager.register( - self.client_id, self.topic, self.node_handle, msg_type=msg_type, latch=latch, queue_size=queue_size) + self.client_id, + self.topic, + self.node_handle, + msg_type=msg_type, + latch=latch, + queue_size=queue_size, + ) self.clients[adv_id] = True @@ -105,26 +113,42 @@ def advertise(self, message): queue_size = message.get("queue_size", 100) if Advertise.topics_glob is not None and Advertise.topics_glob: - self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + self.protocol.log( + "debug", "Topic security glob enabled, checking topic: " + topic + ) match = False for glob in Advertise.topics_glob: - if (fnmatch.fnmatch(topic, glob)): - self.protocol.log("debug", "Found match with glob " + glob + ", continuing advertisement...") + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + + glob + + ", continuing advertisement...", + ) match = True break if not match: - self.protocol.log("warn", "No match found for topic, cancelling advertisement of: " + topic) + self.protocol.log( + "warn", + "No match found for topic, cancelling advertisement of: " + topic, + ) return else: - self.protocol.log("debug", "No topic security glob, not checking advertisement.") + self.protocol.log( + "debug", "No topic security glob, not checking advertisement." + ) # Create the Registration if one doesn't yet exist if topic not in self._registrations: client_id = self.protocol.client_id - self._registrations[topic] = Registration(client_id, topic, self.protocol.node_handle) + self._registrations[topic] = Registration( + client_id, topic, self.protocol.node_handle + ) # Register, propagating any exceptions - self._registrations[topic].register_advertisement(msg_type, aid, latch, queue_size) + self._registrations[topic].register_advertisement( + msg_type, aid, latch, queue_size + ) def unadvertise(self, message): # Pull out the ID @@ -134,18 +158,30 @@ def unadvertise(self, message): topic = message["topic"] if Advertise.topics_glob is not None and Advertise.topics_glob: - self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + self.protocol.log( + "debug", "Topic security glob enabled, checking topic: " + topic + ) match = False for glob in Advertise.topics_glob: - if (fnmatch.fnmatch(topic, glob)): - self.protocol.log("debug", "Found match with glob " + glob + ", continuing unadvertisement...") + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + + glob + + ", continuing unadvertisement...", + ) match = True break if not match: - self.protocol.log("warn", "No match found for topic, cancelling unadvertisement of: " + topic) + self.protocol.log( + "warn", + "No match found for topic, cancelling unadvertisement of: " + topic, + ) return else: - self.protocol.log("debug", "No topic security glob, not checking unadvertisement.") + self.protocol.log( + "debug", "No topic security glob, not checking unadvertisement." + ) # Now unadvertise the topic if topic not in self._registrations: diff --git a/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py b/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py index df224fcb5..ed4f99a4b 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py @@ -7,7 +7,7 @@ from rosbridge_library.capability import Capability -class AdvertisedServiceHandler(): +class AdvertisedServiceHandler: id_counter = 1 responses = {} @@ -20,7 +20,9 @@ def __init__(self, service_name, service_type, protocol): self.service_type = service_type self.protocol = protocol # setup the service - self.service_handle = protocol.node_handle.create_service(get_service_class(service_type), service_name, self.handle_request) + self.service_handle = protocol.node_handle.create_service( + get_service_class(service_type), service_name, self.handle_request + ) def next_id(self): id = self.id_counter @@ -38,7 +40,7 @@ def handle_request(self, req): "op": "call_service", "id": request_id, "service": self.service_name, - "args": message_conversion.extract_values(req) + "args": message_conversion.extract_values(req), } self.protocol.send(request_message) @@ -56,7 +58,9 @@ def handle_request(self, req): self.protocol.log( "warning", "Service %s was unadvertised with a service call in progress, " - "aborting service call with request ID %s" % (self.service_name, request_id)) + "aborting service call with request ID %s" + % (self.service_name, request_id), + ) return None resp = self.responses[request_id] @@ -78,6 +82,7 @@ def graceful_shutdown(self, timeout): time.sleep(0) self.protocol.node_handle.destroy_service(self.service_handle) + class AdvertiseService(Capability): services_glob = None @@ -97,28 +102,51 @@ def advertise_service(self, message): # parse the incoming message service_name = message["service"] - if AdvertiseService.services_glob is not None and AdvertiseService.services_glob: - self.protocol.log("debug", "Service security glob enabled, checking service: " + service_name) + if ( + AdvertiseService.services_glob is not None + and AdvertiseService.services_glob + ): + self.protocol.log( + "debug", + "Service security glob enabled, checking service: " + service_name, + ) match = False for glob in AdvertiseService.services_glob: - if (fnmatch.fnmatch(service_name, glob)): - self.protocol.log("debug", "Found match with glob " + glob + ", continuing service advertisement...") + if fnmatch.fnmatch(service_name, glob): + self.protocol.log( + "debug", + "Found match with glob " + + glob + + ", continuing service advertisement...", + ) match = True break if not match: - self.protocol.log("warn", "No match found for service, cancelling service advertisement for: " + service_name) + self.protocol.log( + "warn", + "No match found for service, cancelling service advertisement for: " + + service_name, + ) return else: - self.protocol.log("debug", "No service security glob, not checking service advertisement.") + self.protocol.log( + "debug", "No service security glob, not checking service advertisement." + ) # check for an existing entry if service_name in self.protocol.external_service_list.keys(): - self.protocol.log("warn", "Duplicate service advertised. Overwriting %s." % service_name) - self.protocol.external_service_list[service_name].service_handle.shutdown("Duplicate advertiser.") + self.protocol.log( + "warn", "Duplicate service advertised. Overwriting %s." % service_name + ) + self.protocol.external_service_list[service_name].service_handle.shutdown( + "Duplicate advertiser." + ) del self.protocol.external_service_list[service_name] # setup and store the service information service_type = message["type"] - service_handler = AdvertisedServiceHandler(service_name, service_type, self.protocol) + service_handler = AdvertisedServiceHandler( + service_name, service_type, self.protocol + ) self.protocol.external_service_list[service_name] = service_handler self.protocol.log("info", "Advertised service %s." % service_name) diff --git a/rosbridge_library/src/rosbridge_library/capabilities/call_service.py b/rosbridge_library/src/rosbridge_library/capabilities/call_service.py index 5e70d3b95..ddfc71e84 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/call_service.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/call_service.py @@ -38,9 +38,11 @@ class CallService(Capability): - call_service_msg_fields = [(True, "service", str), - (False, "fragment_size", (int, type(None))), - (False, "compression", str)] + call_service_msg_fields = [ + (True, "service", str), + (False, "fragment_size", (int, type(None))), + (False, "compression", str), + ] services_glob = None @@ -65,18 +67,31 @@ def call_service(self, message): args = message.get("args", []) if CallService.services_glob is not None and CallService.services_glob: - self.protocol.log("debug", "Service security glob enabled, checking service: " + service) + self.protocol.log( + "debug", "Service security glob enabled, checking service: " + service + ) match = False for glob in CallService.services_glob: - if (fnmatch.fnmatch(service, glob)): - self.protocol.log("debug", "Found match with glob " + glob + ", continuing service call...") + if fnmatch.fnmatch(service, glob): + self.protocol.log( + "debug", + "Found match with glob " + + glob + + ", continuing service call...", + ) match = True break if not match: - self.protocol.log("warn", "No match found for service, cancelling service call for: " + service) + self.protocol.log( + "warn", + "No match found for service, cancelling service call for: " + + service, + ) return else: - self.protocol.log("debug", "No service security glob, not checking service call.") + self.protocol.log( + "debug", "No service security glob, not checking service call." + ) # Check for deprecated service ID, eg. /rosbridge/topics#33 cid = extract_id(service, cid) @@ -86,14 +101,16 @@ def call_service(self, message): e_cb = partial(self._failure, cid, service) # Run service caller in the same thread. - ServiceCaller(trim_servicename(service), args, s_cb, e_cb, self.protocol.node_handle).run() + ServiceCaller( + trim_servicename(service), args, s_cb, e_cb, self.protocol.node_handle + ).run() def _success(self, cid, service, fragment_size, compression, message): outgoing_message = { "op": "service_response", "service": service, "values": message, - "result": True + "result": True, } if cid is not None: outgoing_message["id"] = cid @@ -101,14 +118,15 @@ def _success(self, cid, service, fragment_size, compression, message): self.protocol.send(outgoing_message) def _failure(self, cid, service, exc): - self.protocol.log("error", "call_service %s: %s" % - (type(exc).__name__, str(exc)), cid) + self.protocol.log( + "error", "call_service %s: %s" % (type(exc).__name__, str(exc)), cid + ) # send response with result: false outgoing_message = { "op": "service_response", "service": service, "values": str(exc), - "result": False + "result": False, } if cid is not None: outgoing_message["id"] = cid @@ -116,13 +134,13 @@ def _failure(self, cid, service, exc): def trim_servicename(service): - if '#' in service: - return service[:service.find('#')] + if "#" in service: + return service[: service.find("#")] return service def extract_id(service, cid): if cid is not None: return cid - elif '#' in service: - return service[service.find('#') + 1:] + elif "#" in service: + return service[service.find("#") + 1 :] diff --git a/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py b/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py index f2d3eb16f..6b7e7452f 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py @@ -2,14 +2,17 @@ from datetime import datetime import threading -class ReceivedFragments(): + +class ReceivedFragments: """ Singleton class to hold lists of received fragments in one 'global' object """ + class __impl: - """ Implementation of the singleton interface """ + """Implementation of the singleton interface""" + def spam(self): - """ Test method, return singleton id """ + """Test method, return singleton id""" return id(self) __instance = None @@ -29,21 +32,22 @@ def spam(self): lists = {} def __init__(self): - """ Create singleton instance """ + """Create singleton instance""" if ReceivedFragments.__instance is None: ReceivedFragments.__instance = ReceivedFragments.__impl() self.lists = {} - self.__dict__['_ReceivedFragments__instance'] = ReceivedFragments.__instance + self.__dict__["_ReceivedFragments__instance"] = ReceivedFragments.__instance def __getattr__(self, attr): - """ Delegate access to implementation """ + """Delegate access to implementation""" return getattr(self.__instance, attr) def __setattr__(self, attr, value): - """ Delegate access to implementation """ + """Delegate access to implementation""" return setattr(self.__instance, attr, value) + class Defragment(Capability, threading.Thread): fragment_timeout = 600 @@ -66,7 +70,6 @@ def __init__(self, protocol): self.received_fragments = ReceivedFragments().lists threading.Thread.__init__(self) - # defragment() does: # 1) take any incoming message with op-code "fragment" # 2) check all existing fragment lists for time out # could be done by a thread but should be okay this way: @@ -78,15 +81,17 @@ def __init__(self, protocol): # 4) check if the list of current fragment (message id) is complete # 4.a) reconstruct the original message by concatenating the fragments # 4.b) pass the reconstructed message string to protocol.incoming() # protocol.incoming is checking message fields by itself, so no need to do this before passing the reconstructed message to protocol - # 4.c) remove the fragment list to free up memory + # 4.c) remove the fragment list to free up memory def defragment(self, message): now = datetime.now() if self.received_fragments is not None: - for id in self.received_fragments.keys() : + for id in self.received_fragments.keys(): time_diff = now - self.received_fragments[id]["timestamp_last_append"] - if (time_diff.total_seconds() > self.fragment_timeout and - not self.received_fragments[id]["is_reconstructing"]): + if ( + time_diff.total_seconds() > self.fragment_timeout + and not self.received_fragments[id]["is_reconstructing"] + ): log_msg = ["fragment list ", str(id), " timed out.."] if message["id"] != id: @@ -95,9 +100,11 @@ def defragment(self, message): else: log_msg.extend([" -> but we're just about to add fragment #"]) log_msg.extend([str(message.get("num")), " of "]) - log_msg.extend([str(self.received_fragments[message.get("id")]["total"])]) + log_msg.extend( + [str(self.received_fragments[message.get("id")]["total"])] + ) log_msg.extend([" ..keeping the list"]) - self.protocol.log("warning", ''.join(log_msg)) + self.protocol.log("warning", "".join(log_msg)) msg_opcode = message.get("op") msg_id = message.get("id") @@ -119,23 +126,31 @@ def defragment(self, message): "is_reconstructing": False, "total": message["total"], "timestamp_last_append": now, - "fragment_list": {} + "fragment_list": {}, } log_msg = "opened new fragment list for messageID " + str(msg_id) self.protocol.log("debug", log_msg) - #print "received fragments:", len(self.received_fragments[msg_id]["fragment_list"].keys()) + # print "received fragments:", len(self.received_fragments[msg_id]["fragment_list"].keys()) # Add fragment to fragment container's list if not already in list - if ((msg_num not in self.received_fragments[msg_id]["fragment_list"].keys() ) and - msg_num <= self.received_fragments[msg_id]["total"] and - msg_total == self.received_fragments[msg_id]["total"] - ): + if ( + (msg_num not in self.received_fragments[msg_id]["fragment_list"].keys()) + and msg_num <= self.received_fragments[msg_id]["total"] + and msg_total == self.received_fragments[msg_id]["total"] + ): self.received_fragments[msg_id]["fragment_list"][msg_num] = msg_data self.received_fragments[msg_id]["timestamp_last_append"] = now log_msg = ["appended fragment #" + str(msg_num)] - log_msg.extend([" (total: ", str(msg_total), ") to fragment list for messageID ", str(msg_id)]) - self.protocol.log("debug", ''.join(log_msg)) + log_msg.extend( + [ + " (total: ", + str(msg_total), + ") to fragment list for messageID ", + str(msg_id), + ] + ) + self.protocol.log("debug", "".join(log_msg)) else: log_msg = "error while trying to append fragment " + str(msg_num) self.protocol.log("error", log_msg) @@ -147,16 +162,18 @@ def defragment(self, message): # Make sure total number of fragments received if existing_fragments == announced_total: - log_msg = ["enough/all fragments for messageID " + str(msg_id) + " received"] + log_msg = [ + "enough/all fragments for messageID " + str(msg_id) + " received" + ] log_msg.extend([" [", str(existing_fragments), "]"]) - log_msg = ''.join(log_msg) + log_msg = "".join(log_msg) self.protocol.log("debug", log_msg) # Check each fragment matches up received_all_fragments = True for i in range(0, announced_total): if i not in self.received_fragments[msg_id]["fragment_list"]: received_all_fragments = False - log_msg = "fragment #" +str(i) + log_msg = "fragment #" + str(i) log_msg += " for messageID " + str(msg_id) + " is missing! " self.protocol.log("error", log_msg) @@ -167,11 +184,13 @@ def defragment(self, message): self.protocol.log("debug", log_msg) # Reconstruct the message - reconstructed_msg = ''.join(self.received_fragments[msg_id]["fragment_list"].values()) + reconstructed_msg = "".join( + self.received_fragments[msg_id]["fragment_list"].values() + ) log_msg = ["reconstructed original message:\n"] log_msg.append(reconstructed_msg) - log_msg = ''.join(log_msg) + log_msg = "".join(log_msg) self.protocol.log("debug", log_msg) duration = datetime.now() - now @@ -181,9 +200,9 @@ def defragment(self, message): log_msg = ["reconstructed message (ID:" + str(msg_id) + ") from "] log_msg.extend([str(msg_total), " fragments. "]) # cannot access msg.data if message is a service_response or else! - #log_msg += "[message length: " + str(len(str(json.loads(reconstructed_msg)["msg"]["data"]))) +"]" - log_msg.extend(["[duration: ", str(duration.total_seconds()), " s]"]) - log_msg = ''.join(log_msg) + # log_msg += "[message length: " + str(len(str(json.loads(reconstructed_msg)["msg"]["data"]))) +"]" + log_msg.extend(["[duration: ", str(duration.total_seconds()), " s]"]) + log_msg = "".join(log_msg) self.protocol.log("info", log_msg) # Remove fragmentation container diff --git a/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py b/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py index a5b582034..da376cc8f 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py @@ -35,9 +35,9 @@ class Fragmentation(Capability): - """ The Fragmentation capability doesn't define any incoming operation - handlers, but provides methods to fragment outgoing messages """ - + """The Fragmentation capability doesn't define any incoming operation + handlers, but provides methods to fragment outgoing messages""" + fragmentation_seed = 0 def __init__(self, protocol): @@ -45,15 +45,15 @@ def __init__(self, protocol): Capability.__init__(self, protocol) def fragment(self, message, fragment_size, mid=None): - """ Serializes the provided message, then splits the serialized + """Serializes the provided message, then splits the serialized message according to fragment_size, then sends the fragments. - + If the size of the message is less than the fragment size, then the original message is returned rather than a single fragment - + Since fragmentation is typically only used for very large messages, this method returns a generator for fragments rather than a list - + Keyword Arguments message -- the message dict object to be fragmented fragment_size -- the max size for the fragments @@ -66,41 +66,52 @@ def fragment(self, message, fragment_size, mid=None): if mid is None: mid = self.fragmentation_seed self.fragmentation_seed = self.fragmentation_seed + 1 - + serialized = self.protocol.serialize(message, mid) - + if serialized is None: return [] - + message_length = len(serialized) if message_length <= fragment_size: return [message] msg_id = message.get("id", None) - expected_duration = int(math.ceil(math.ceil(message_length / float(fragment_size))) * self.protocol.delay_between_messages) + expected_duration = int( + math.ceil(math.ceil(message_length / float(fragment_size))) + * self.protocol.delay_between_messages + ) - log_msg = "sending " + str(int(math.ceil(message_length / float(fragment_size)))) + " parts [fragment size: " + str(fragment_size) +"; expected duration: ~" + str(expected_duration) + "s]" + log_msg = ( + "sending " + + str(int(math.ceil(message_length / float(fragment_size)))) + + " parts [fragment size: " + + str(fragment_size) + + "; expected duration: ~" + + str(expected_duration) + + "s]" + ) self.protocol.log("info", log_msg) return self._fragment_generator(serialized, fragment_size, mid) - + def _fragment_generator(self, msg, size, mid): - """ Returns a generator of fragment messages """ - total = ((len(msg)-1) / size) + 1 + """Returns a generator of fragment messages""" + total = ((len(msg) - 1) / size) + 1 n = 0 for i in range(0, len(msg), size): - fragment = msg[i:i+size] + fragment = msg[i : i + size] yield self._create_fragment(fragment, n, total, mid) n = n + 1 - + def _create_fragment(self, fragment, num, total, mid): - """ Given a string fragment of the original message, creates - the appropriate fragment message """ + """Given a string fragment of the original message, creates + the appropriate fragment message""" return { "op": "fragment", "id": mid, "data": fragment, "num": num, - "total": total + "total": total, } diff --git a/rosbridge_library/src/rosbridge_library/capabilities/publish.py b/rosbridge_library/src/rosbridge_library/capabilities/publish.py index 533315df1..fdd44febc 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/publish.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/publish.py @@ -63,29 +63,49 @@ def publish(self, message): queue_size = message.get("queue_size", 100) if Publish.topics_glob is not None and Publish.topics_glob: - self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + self.protocol.log( + "debug", "Topic security glob enabled, checking topic: " + topic + ) match = False for glob in Publish.topics_glob: - if (fnmatch.fnmatch(topic, glob)): - self.protocol.log("debug", "Found match with glob " + glob + ", continuing publish...") + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + glob + ", continuing publish...", + ) match = True break if not match: - self.protocol.log("warn", "No match found for topic, cancelling publish to: " + topic) + self.protocol.log( + "warn", "No match found for topic, cancelling publish to: " + topic + ) return else: self.protocol.log("debug", "No topic security glob, not checking publish.") # Register as a publishing client, propagating any exceptions client_id = self.protocol.client_id - manager.register(client_id, topic, self.protocol.node_handle, latch=latch, queue_size=queue_size) + manager.register( + client_id, + topic, + self.protocol.node_handle, + latch=latch, + queue_size=queue_size, + ) self._published[topic] = True # Get the message if one was provided msg = message.get("msg", {}) # Publish the message - manager.publish(client_id, topic, msg, self.protocol.node_handle, latch=latch, queue_size=queue_size) + manager.publish( + client_id, + topic, + msg, + self.protocol.node_handle, + latch=latch, + queue_size=queue_size, + ) def finish(self): client_id = self.protocol.client_id diff --git a/rosbridge_library/src/rosbridge_library/capabilities/service_response.py b/rosbridge_library/src/rosbridge_library/capabilities/service_response.py index e4848cfb1..e7ebb6809 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/service_response.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/service_response.py @@ -5,8 +5,10 @@ class ServiceResponse(Capability): service_response_msg_fields = [ - (True, "service", str), (False, "id", str), - (False, "values", dict), (True, "result", bool) + (True, "service", str), + (False, "id", str), + (False, "values", dict), + (True, "result", bool), ] def __init__(self, protocol): @@ -28,9 +30,14 @@ def service_response(self, message): request_id = message["id"] values = message["values"] # create a message instance - resp = ros_loader.get_service_response_instance(service_handler.service_type) + resp = ros_loader.get_service_response_instance( + service_handler.service_type + ) message_conversion.populate_instance(values, resp) # pass along the response service_handler.responses[request_id] = resp else: - self.protocol.log("error", "Service %s has not been advertised via rosbridge." % service_name) + self.protocol.log( + "error", + "Service %s has not been advertised via rosbridge." % service_name, + ) diff --git a/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py b/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py index ac88b06fc..efb9d7dfd 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py @@ -52,13 +52,13 @@ from json import dumps as encode_json -class Subscription(): - """ Keeps track of the clients multiple calls to subscribe. +class Subscription: + """Keeps track of the clients multiple calls to subscribe. - Chooses the most appropriate settings to send messages """ + Chooses the most appropriate settings to send messages""" def __init__(self, client_id, topic, publish, node_handle): - """ Create a subscription for the specified client on the specified + """Create a subscription for the specified client on the specified topic, with callback publish Keyword arguments: @@ -80,15 +80,22 @@ def __init__(self, client_id, topic, publish, node_handle): self.update_params() def unregister(self): - """ Unsubscribes this subscription and cleans up resources """ + """Unsubscribes this subscription and cleans up resources""" manager.unsubscribe(self.client_id, self.topic) with self.handler_lock: self.handler.finish() self.clients.clear() - def subscribe(self, sid=None, msg_type=None, throttle_rate=0, - queue_length=0, fragment_size=None, compression="none"): - """ Add another client's subscription request + def subscribe( + self, + sid=None, + msg_type=None, + throttle_rate=0, + queue_length=0, + fragment_size=None, + compression="none", + ): + """Add another client's subscription request If there are multiple calls to subscribe, the values actually used for queue_length, fragment_size, compression and throttle_rate are @@ -106,13 +113,13 @@ def subscribe(self, sid=None, msg_type=None, throttle_rate=0, compression -- "none" if no compression, or some other value if compression is to be used (current valid values are 'png') - """ + """ client_details = { "throttle_rate": throttle_rate, "queue_length": queue_length, "fragment_size": fragment_size, - "compression": compression + "compression": compression, } self.clients[sid] = client_details @@ -123,10 +130,16 @@ def subscribe(self, sid=None, msg_type=None, throttle_rate=0, # Subscribe with the manager. This will propagate any exceptions manager.subscribe( - self.client_id, self.topic, self.on_msg, self.node_handle, msg_type=msg_type, raw=raw) + self.client_id, + self.topic, + self.on_msg, + self.node_handle, + msg_type=msg_type, + raw=raw, + ) def unsubscribe(self, sid=None): - """ Unsubscribe this particular client's subscription + """Unsubscribe this particular client's subscription Keyword arguments: sid -- the individual subscription id. If None, all are unsubscribed @@ -141,16 +154,16 @@ def unsubscribe(self, sid=None): self.update_params() def is_empty(self): - """ Return true if there are no subscriptions currently """ + """Return true if there are no subscriptions currently""" return len(self.clients) == 0 def _publish(self, message): - """ Internal method to propagate published messages to the registered - publish callback """ + """Internal method to propagate published messages to the registered + publish callback""" self.publish(message, self.fragment_size, self.compression) def on_msg(self, msg): - """ Raw callback called by subscription manager for all incoming + """Raw callback called by subscription manager for all incoming messages. Incoming messages are passed to the message handler which may drop, @@ -161,8 +174,8 @@ def on_msg(self, msg): self.handler.handle_message(msg) def update_params(self): - """ Determine the 'lowest common denominator' params to satisfy all - subscribed clients. """ + """Determine the 'lowest common denominator' params to satisfy all + subscribed clients.""" if len(self.clients) == 0: self.throttle_rate = 0 self.queue_length = 0 @@ -196,9 +209,14 @@ def f(fieldname): class Subscribe(Capability): - subscribe_msg_fields = [(True, "topic", str), (False, "type", str), - (False, "throttle_rate", int), (False, "fragment_size", int), - (False, "queue_length", int), (False, "compression", str)] + subscribe_msg_fields = [ + (True, "topic", str), + (False, "type", str), + (False, "throttle_rate", int), + (False, "fragment_size", int), + (False, "queue_length", int), + (False, "compression", str), + ] unsubscribe_msg_fields = [(True, "topic", str)] topics_glob = None @@ -224,32 +242,46 @@ def subscribe(self, msg): topic = msg["topic"] if Subscribe.topics_glob is not None and Subscribe.topics_glob: - self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + self.protocol.log( + "debug", "Topic security glob enabled, checking topic: " + topic + ) match = False for glob in Subscribe.topics_glob: - if (fnmatch.fnmatch(topic, glob)): - self.protocol.log("debug", "Found match with glob " + glob + ", continuing subscription...") + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + + glob + + ", continuing subscription...", + ) match = True break if not match: - self.protocol.log("warn", "No match found for topic, cancelling subscription to: " + topic) + self.protocol.log( + "warn", + "No match found for topic, cancelling subscription to: " + topic, + ) return else: - self.protocol.log("debug", "No topic security glob, not checking subscription.") + self.protocol.log( + "debug", "No topic security glob, not checking subscription." + ) if topic not in self._subscriptions: client_id = self.protocol.client_id cb = partial(self.publish, topic) - self._subscriptions[topic] = Subscription(client_id, topic, cb, self.protocol.node_handle) + self._subscriptions[topic] = Subscription( + client_id, topic, cb, self.protocol.node_handle + ) # Register the subscriber subscribe_args = { - "sid": sid, - "msg_type": msg.get("type", None), - "throttle_rate": msg.get("throttle_rate", 0), - "fragment_size": msg.get("fragment_size", None), - "queue_length": msg.get("queue_length", 0), - "compression": msg.get("compression", "none") + "sid": sid, + "msg_type": msg.get("type", None), + "throttle_rate": msg.get("throttle_rate", 0), + "fragment_size": msg.get("fragment_size", None), + "queue_length": msg.get("queue_length", 0), + "compression": msg.get("compression", "none"), } self._subscriptions[topic].subscribe(**subscribe_args) @@ -263,18 +295,31 @@ def unsubscribe(self, msg): topic = msg["topic"] if Subscribe.topics_glob is not None and Subscribe.topics_glob: - self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + self.protocol.log( + "debug", "Topic security glob enabled, checking topic: " + topic + ) match = False for glob in Subscribe.topics_glob: - if (fnmatch.fnmatch(topic, glob)): - self.protocol.log("debug", "Found match with glob " + glob + ", continuing unsubscription...") + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + + glob + + ", continuing unsubscription...", + ) match = True break if not match: - self.protocol.log("warn", "No match found for topic, cancelling unsubscription from: " + topic) + self.protocol.log( + "warn", + "No match found for topic, cancelling unsubscription from: " + + topic, + ) return else: - self.protocol.log("debug", "No topic security glob, not checking unsubscription.") + self.protocol.log( + "debug", "No topic security glob, not checking unsubscription." + ) if topic not in self._subscriptions: return @@ -287,7 +332,7 @@ def unsubscribe(self, msg): self.protocol.log("info", "Unsubscribed from %s" % topic) def publish(self, topic, message, fragment_size=None, compression="none"): - """ Publish a message to the client + """Publish a message to the client Keyword arguments: topic -- the topic to publish the message on @@ -300,33 +345,47 @@ def publish(self, topic, message, fragment_size=None, compression="none"): """ # TODO: fragmentation, proper ids if Subscribe.topics_glob and Subscribe.topics_glob: - self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + self.protocol.log( + "debug", "Topic security glob enabled, checking topic: " + topic + ) match = False for glob in Subscribe.topics_glob: - if (fnmatch.fnmatch(topic, glob)): - self.protocol.log("debug", "Found match with glob " + glob + ", continuing topic publish...") + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + + glob + + ", continuing topic publish...", + ) match = True break if not match: - self.protocol.log("warn", "No match found for topic, cancelling topic publish to: " + topic) + self.protocol.log( + "warn", + "No match found for topic, cancelling topic publish to: " + topic, + ) return else: - self.protocol.log("debug", "No topic security glob, not checking topic publish.") + self.protocol.log( + "debug", "No topic security glob, not checking topic publish." + ) outgoing_msg = {"op": "publish", "topic": topic} - if compression=="png": + if compression == "png": outgoing_msg["msg"] = message.get_json_values() outgoing_msg_dumped = encode_json(outgoing_msg) outgoing_msg = {"op": "png", "data": encode_png(outgoing_msg_dumped)} - elif compression=="cbor": + elif compression == "cbor": outgoing_msg["msg"] = message.get_cbor_values() outgoing_msg = bytearray(encode_cbor(outgoing_msg)) - elif compression=="cbor-raw": - (secs, nsecs) = self.protocol.node_handle.get_clock().now().seconds_nanoseconds() + elif compression == "cbor-raw": + (secs, nsecs) = ( + self.protocol.node_handle.get_clock().now().seconds_nanoseconds() + ) outgoing_msg["msg"] = { "secs": secs, "nsecs": nsecs, - "bytes": message.message + "bytes": message.message, } outgoing_msg = bytearray(encode_cbor(outgoing_msg)) else: diff --git a/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py b/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py index 2d4ce64cc..0790a05c6 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py @@ -19,25 +19,51 @@ def unadvertise_service(self, message): # parse the message service_name = message["service"] - if UnadvertiseService.services_glob is not None and UnadvertiseService.services_glob: - self.protocol.log("debug", "Service security glob enabled, checking service: " + service_name) + if ( + UnadvertiseService.services_glob is not None + and UnadvertiseService.services_glob + ): + self.protocol.log( + "debug", + "Service security glob enabled, checking service: " + service_name, + ) match = False for glob in UnadvertiseService.services_glob: - if (fnmatch.fnmatch(service_name, glob)): - self.protocol.log("debug", "Found match with glob " + glob + ", continuing service unadvertisement...") + if fnmatch.fnmatch(service_name, glob): + self.protocol.log( + "debug", + "Found match with glob " + + glob + + ", continuing service unadvertisement...", + ) match = True break if not match: - self.protocol.log("warn", "No match found for service, cancelling service unadvertisement for: " + service_name) + self.protocol.log( + "warn", + "No match found for service, cancelling service unadvertisement for: " + + service_name, + ) return else: - self.protocol.log("debug", "No service security glob, not checking service unadvertisement...") + self.protocol.log( + "debug", + "No service security glob, not checking service unadvertisement...", + ) # unregister service in ROS if service_name in self.protocol.external_service_list.keys(): - self.protocol.external_service_list[service_name].graceful_shutdown(timeout=1.0) - self.protocol.external_service_list[service_name].service_handle.shutdown("Unadvertise request.") + self.protocol.external_service_list[service_name].graceful_shutdown( + timeout=1.0 + ) + self.protocol.external_service_list[service_name].service_handle.shutdown( + "Unadvertise request." + ) del self.protocol.external_service_list[service_name] self.protocol.log("info", "Unadvertised service %s." % service_name) else: - self.protocol.log("error", "Service %s has not been advertised via rosbridge, can't unadvertise." % service_name) + self.protocol.log( + "error", + "Service %s has not been advertised via rosbridge, can't unadvertise." + % service_name, + ) diff --git a/rosbridge_library/src/rosbridge_library/capability.py b/rosbridge_library/src/rosbridge_library/capability.py index 87f04921c..0fe0cc73a 100644 --- a/rosbridge_library/src/rosbridge_library/capability.py +++ b/rosbridge_library/src/rosbridge_library/capability.py @@ -35,7 +35,7 @@ class Capability: - """ Handles the operation-specific logic of a rosbridge message + """Handles the operation-specific logic of a rosbridge message May define one or more opcodes to handle, for example 'publish' or 'call_service' @@ -48,7 +48,7 @@ class Capability: """ def __init__(self, protocol): - """ Abstract class constructor. All capabilities require a handle to + """Abstract class constructor. All capabilities require a handle to the containing protocol. Keyword arguments: @@ -58,7 +58,7 @@ def __init__(self, protocol): self.protocol = protocol def handle_message(self, message): - """ Handle an incoming message. + """Handle an incoming message. Called by the protocol after having already checked the message op code @@ -69,12 +69,12 @@ def handle_message(self, message): pass def finish(self): - """ Notify this capability that the client is finished and that it's - time to free up resources. """ + """Notify this capability that the client is finished and that it's + time to free up resources.""" pass def basic_type_check(self, msg, types_info): - """ Performs basic typechecking on fields in msg. + """Performs basic typechecking on fields in msg. Keyword arguments: msg -- a message, deserialized into a dictoinary @@ -92,14 +92,17 @@ def basic_type_check(self, msg, types_info): """ for mandatory, fieldname, fieldtypes in types_info: if mandatory and fieldname not in msg: - raise MissingArgumentException("Expected a %s field but none was found." % fieldname) + raise MissingArgumentException( + "Expected a %s field but none was found." % fieldname + ) elif fieldname in msg: if not isinstance(fieldtypes, tuple): - fieldtypes = (fieldtypes, ) + fieldtypes = (fieldtypes,) valid = False for typ in fieldtypes: if isinstance(msg[fieldname], typ): valid = True if not valid: - raise InvalidArgumentException(f"Expected field {fieldname} to be one of {fieldtypes}. Invalid value: {msg[fieldname]}") - + raise InvalidArgumentException( + f"Expected field {fieldname} to be one of {fieldtypes}. Invalid value: {msg[fieldname]}" + ) diff --git a/rosbridge_library/src/rosbridge_library/internal/cbor_conversion.py b/rosbridge_library/src/rosbridge_library/internal/cbor_conversion.py index 74e9350b1..3e2128771 100644 --- a/rosbridge_library/src/rosbridge_library/internal/cbor_conversion.py +++ b/rosbridge_library/src/rosbridge_library/internal/cbor_conversion.py @@ -7,27 +7,38 @@ LIST_TYPES = [list, tuple] -INT_TYPES = ['byte', 'char', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'] -FLOAT_TYPES = ['float32', 'float64'] -STRING_TYPES = ['string'] -BOOL_TYPES = ['bool'] -TIME_TYPES = ['time', 'duration'] -BOOL_ARRAY_TYPES = ['bool[]'] -BYTESTREAM_TYPES = ['uint8[]', 'char[]'] +INT_TYPES = [ + "byte", + "char", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", +] +FLOAT_TYPES = ["float32", "float64"] +STRING_TYPES = ["string"] +BOOL_TYPES = ["bool"] +TIME_TYPES = ["time", "duration"] +BOOL_ARRAY_TYPES = ["bool[]"] +BYTESTREAM_TYPES = ["uint8[]", "char[]"] # Typed array tags according to # Always encode to little-endian variant, for now. TAGGED_ARRAY_FORMATS = { - 'uint16[]': (69, '<{}H'), - 'uint32[]': (70, '<{}I'), - 'uint64[]': (71, '<{}Q'), - 'byte[]': (72, '{}b'), - 'int8[]': (72, '{}b'), - 'int16[]': (77, '<{}h'), - 'int32[]': (78, '<{}i'), - 'int64[]': (79, '<{}q'), - 'float32[]': (85, '<{}f'), - 'float64[]': (86, '<{}d'), + "uint16[]": (69, "<{}H"), + "uint32[]": (70, "<{}I"), + "uint64[]": (71, "<{}Q"), + "byte[]": (72, "{}b"), + "int8[]": (72, "{}b"), + "int16[]": (77, "<{}h"), + "int32[]": (78, "<{}i"), + "int64[]": (79, "<{}q"), + "float32[]": (85, "<{}f"), + "float64[]": (86, "<{}d"), } @@ -61,8 +72,8 @@ def extract_cbor_values(msg): # time/duration elif slot_type in TIME_TYPES: out[slot] = { - 'secs': int(val.secs), - 'nsecs': int(val.nsecs), + "secs": int(val.secs), + "nsecs": int(val.nsecs), } # byte array diff --git a/rosbridge_library/src/rosbridge_library/internal/exceptions.py b/rosbridge_library/src/rosbridge_library/internal/exceptions.py index 24b545908..3f04a941c 100644 --- a/rosbridge_library/src/rosbridge_library/internal/exceptions.py +++ b/rosbridge_library/src/rosbridge_library/internal/exceptions.py @@ -30,8 +30,10 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. + class InvalidArgumentException(Exception): pass + class MissingArgumentException(Exception): pass diff --git a/rosbridge_library/src/rosbridge_library/internal/message_conversion.py b/rosbridge_library/src/rosbridge_library/internal/message_conversion.py index ac9311ed9..adff2c1a1 100644 --- a/rosbridge_library/src/rosbridge_library/internal/message_conversion.py +++ b/rosbridge_library/src/rosbridge_library/internal/message_conversion.py @@ -51,73 +51,121 @@ rospy = None type_map = { - "bool": ["bool", "boolean"], - "int": ["int8", "byte", "uint8", "char", - "int16", "uint16", "int32", "uint32", - "int64", "uint64", "float32", "float64"], - "float": ["float32", "float64", "double", "float"], - "str": ["string"] + "bool": ["bool", "boolean"], + "int": [ + "int8", + "byte", + "uint8", + "char", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float32", + "float64", + ], + "float": ["float32", "float64", "double", "float"], + "str": ["string"], } primitive_types = [bool, int, float] list_types = [list, tuple, np.ndarray, array.array] ros_time_types = ["builtin_interfaces/Time", "builtin_interfaces/Duration"] -ros_primitive_types = ["bool", "boolean", "byte", "char", "int8", "uint8", "int16", - "uint16", "int32", "uint32", "int64", "uint64", - "float32", "float64", "float", "double", "string"] +ros_primitive_types = [ + "bool", + "boolean", + "byte", + "char", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float32", + "float64", + "float", + "double", + "string", +] ros_header_types = ["Header", "std_msgs/Header", "roslib/Header"] ros_binary_types = ["uint8[]", "char[]"] -list_tokens = re.compile('<(.+?)>') -bounded_array_tokens = re.compile(r'(.+)\[.*\]') -ros_binary_types_list_braces = [("uint8[]", re.compile(r'uint8\[[^\]]*\]')), - ("char[]", re.compile(r'char\[[^\]]*\]'))] +list_tokens = re.compile("<(.+?)>") +bounded_array_tokens = re.compile(r"(.+)\[.*\]") +ros_binary_types_list_braces = [ + ("uint8[]", re.compile(r"uint8\[[^\]]*\]")), + ("char[]", re.compile(r"char\[[^\]]*\]")), +] binary_encoder = None -binary_encoder_type = 'default' +binary_encoder_type = "default" bson_only_mode = False - # TODO(@jubeira): configure module with a node handle. # The original code doesn't seem to actually use these parameters. def configure(node_handle=None): global binary_encoder, binary_encoder_type, bson_only_mode if node_handle is not None: - binary_encoder_type = node_handle.get_parameter_or('binary_encoder', - Parameter('', value='default')).value - bson_only_mode = node_handle.get_parameter_or('bson_only_mode', - Parameter('', value=False)).value + binary_encoder_type = node_handle.get_parameter_or( + "binary_encoder", Parameter("", value="default") + ).value + bson_only_mode = node_handle.get_parameter_or( + "bson_only_mode", Parameter("", value=False) + ).value if binary_encoder is None: - if binary_encoder_type == 'bson' or bson_only_mode: + if binary_encoder_type == "bson" or bson_only_mode: binary_encoder = bson.Binary - elif binary_encoder_type == 'default' or binary_encoder_type == 'b64': - binary_encoder = standard_b64encode + elif binary_encoder_type == "default" or binary_encoder_type == "b64": + binary_encoder = standard_b64encode else: - print("Unknown encoder type '%s'"%binary_encoder_type) + print("Unknown encoder type '%s'" % binary_encoder_type) exit(0) + def get_encoder(): configure() return binary_encoder + class InvalidMessageException(Exception): def __init__(self, inst): - Exception.__init__(self, "Unable to extract message values from %s instance" % type(inst).__name__) + Exception.__init__( + self, + "Unable to extract message values from %s instance" % type(inst).__name__, + ) class NonexistentFieldException(Exception): def __init__(self, basetype, fields): - Exception.__init__(self, "Message type {} does not have a field {}".format(basetype, '.'.join(fields))) + Exception.__init__( + self, + "Message type {} does not have a field {}".format( + basetype, ".".join(fields) + ), + ) class FieldTypeMismatchException(Exception): def __init__(self, roottype, fields, expected_type, found_type): if roottype == expected_type: - Exception.__init__(self, f"Expected a JSON object for type {roottype} but received a {found_type}") + Exception.__init__( + self, + f"Expected a JSON object for type {roottype} but received a {found_type}", + ) else: - Exception.__init__(self, "{} message requires a {} for field {}, but got a {}".format(roottype, expected_type, '.'.join(fields), found_type)) + Exception.__init__( + self, + "{} message requires a {} for field {}, but got a {}".format( + roottype, expected_type, ".".join(fields), found_type + ), + ) def extract_values(inst): @@ -126,13 +174,15 @@ def extract_values(inst): raise InvalidMessageException(inst=inst) return _from_inst(inst, rostype) + def populate_instance(msg, inst): - """ Returns an instance of the provided class, with its fields populated - according to the values in msg """ + """Returns an instance of the provided class, with its fields populated + according to the values in msg""" inst_type = msg_instance_type_repr(inst) return _to_inst(msg, inst_type, inst_type, inst) + def msg_instance_type_repr(msg_inst): """Returns a string representation of a ROS2 message type from a message instance""" # Message representation: '{package}.msg.{message_name}({fields})'. @@ -141,8 +191,8 @@ def msg_instance_type_repr(msg_inst): msg_type = type(msg_inst) if msg_type in primitive_types or msg_type in list_types: return str(type(msg_inst)) - inst_repr = str(msg_inst).split('.') - return '{}/{}'.format(inst_repr[0], inst_repr[2].split('(')[0]) + inst_repr = str(msg_inst).split(".") + return "{}/{}".format(inst_repr[0], inst_repr[2].split("(")[0]) def msg_class_type_repr(msg_class): @@ -150,8 +200,8 @@ def msg_class_type_repr(msg_class): # The string representation of the class is # (e.g. ). # This has to be converted to {package}/msg/{Message} (e.g. std_msgs/msg/String). - class_repr = str(msg_class).split('\'')[1].split('.') - return f'{class_repr[0]}/{class_repr[1]}/{class_repr[3]}' + class_repr = str(msg_class).split("'")[1].split(".") + return f"{class_repr[0]}/{class_repr[1]}/{class_repr[3]}" def _from_inst(inst, rostype): @@ -160,7 +210,7 @@ def _from_inst(inst, rostype): for binary_type, expression in ros_binary_types_list_braces: if expression.sub(binary_type, rostype) in ros_binary_types: encoded = get_encoder()(inst) - return encoded.decode('ascii') + return encoded.decode("ascii") # Check for time or duration if rostype in ros_time_types: @@ -169,13 +219,12 @@ def _from_inst(inst, rostype): except AttributeError: return {"secs": inst.secs, "nsecs": inst.nsecs} - if bson_only_mode is None: - bson_only_mode = rospy.get_param('~bson_only_mode', False) + bson_only_mode = rospy.get_param("~bson_only_mode", False) # Check for primitive types if rostype in ros_primitive_types: - #JSON does not support Inf and NaN. They are mapped to None and encoded as null - if (not bson_only_mode) and (rostype in type_map.get('float')): + # JSON does not support Inf and NaN. They are mapped to None and encoded as null + if (not bson_only_mode) and (rostype in type_map.get("float")): if math.isnan(inst) or math.isinf(inst): return None return inst @@ -200,7 +249,7 @@ def _from_list_inst(inst, rostype): rostype = re.search(bounded_array_tokens, rostype).group(1) # Shortcut for primitives - if rostype in ros_primitive_types and rostype not in type_map.get('float'): + if rostype in ros_primitive_types and rostype not in type_map.get("float"): return list(inst) # Call to _to_inst for every element of the list @@ -216,6 +265,7 @@ def _from_object_inst(inst, rostype): msg[field_name] = _from_inst(field_inst, field_rostype) return msg + def _to_inst(msg, rostype, roottype, inst=None, stack=[]): # Check if it's uint8[], and if it's a string, try to b64decode for binary_type, expression in ros_binary_types_list_braces: @@ -243,7 +293,9 @@ def _to_inst(msg, rostype, roottype, inst=None, stack=[]): def _to_binary_inst(msg): try: - return standard_b64decode(msg) if isinstance(msg, str) else bytes(bytearray(msg)) + return ( + standard_b64decode(msg) if isinstance(msg, str) else bytes(bytearray(msg)) + ) except Exception: return msg @@ -275,7 +327,7 @@ def _to_time_inst(msg, rostype, inst=None): def _to_primitive_inst(msg, rostype, roottype, stack): # Typecheck the msg - if isinstance(msg, int) and rostype in type_map['float']: + if isinstance(msg, int) and rostype in type_map["float"]: # probably wrong parsing, # fix that by casting the int to the expected float msg = float(msg) @@ -333,8 +385,9 @@ def _to_object_inst(msg, rostype, roottype, inst, stack): field_rostype = inst_fields[field_name] field_inst = getattr(inst, field_name) - field_value = _to_inst(msg[field_name], field_rostype, - roottype, field_inst, field_stack) + field_value = _to_inst( + msg[field_name], field_rostype, roottype, field_inst, field_stack + ) setattr(inst, field_name, field_value) diff --git a/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py b/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py index 12c18e59e..2ee306d5f 100644 --- a/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py +++ b/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py @@ -1,9 +1,12 @@ -from rosbridge_library.internal.message_conversion import extract_values as extract_json_values +from rosbridge_library.internal.message_conversion import ( + extract_values as extract_json_values, +) from rosbridge_library.internal.cbor_conversion import extract_cbor_values class OutgoingMessage: """A message wrapper for caching encoding operations.""" + def __init__(self, message): self._message = message self._json_values = None diff --git a/rosbridge_library/src/rosbridge_library/internal/pngcompression.py b/rosbridge_library/src/rosbridge_library/internal/pngcompression.py index 538348fd5..9ed4b1c7a 100644 --- a/rosbridge_library/src/rosbridge_library/internal/pngcompression.py +++ b/rosbridge_library/src/rosbridge_library/internal/pngcompression.py @@ -37,22 +37,23 @@ def encode(string): - """ PNG-compress the string in a square RBG image padded with '\n', return the b64 encoded bytes """ + """PNG-compress the string in a square RBG image padded with '\n', return the b64 encoded bytes""" length = len(string) - width = floor(sqrt(length/3.0)) - height = ceil((length/3.0) / width) + width = floor(sqrt(length / 3.0)) + height = ceil((length / 3.0) / width) bytes_needed = int(width * height * 3) while length < bytes_needed: - string += '\n' + string += "\n" length += 1 - i = Image.frombytes('RGB', (int(width), int(height)), string) + i = Image.frombytes("RGB", (int(width), int(height)), string) buff = StringIO() i.save(buff, "png") encoded = standard_b64encode(buff.getvalue()) return encoded + def decode(string): - """ b64 decode the string, then PNG-decompress """ + """b64 decode the string, then PNG-decompress""" decoded = standard_b64decode(string) buff = StringIO(decoded) i = Image.open(buff) diff --git a/rosbridge_library/src/rosbridge_library/internal/publishers.py b/rosbridge_library/src/rosbridge_library/internal/publishers.py index b217a4895..025fb311e 100644 --- a/rosbridge_library/src/rosbridge_library/internal/publishers.py +++ b/rosbridge_library/src/rosbridge_library/internal/publishers.py @@ -36,17 +36,22 @@ from rclpy.qos import QoSProfile, QoSDurabilityPolicy from rosbridge_library.internal import ros_loader, message_conversion from rosbridge_library.internal.message_conversion import msg_class_type_repr -from rosbridge_library.internal.topics import TopicNotEstablishedException, TypeConflictException +from rosbridge_library.internal.topics import ( + TopicNotEstablishedException, + TypeConflictException, +) -class MultiPublisher(): - """ Keeps track of the clients that are using a particular publisher. +class MultiPublisher: + """Keeps track of the clients that are using a particular publisher. Provides an API to publish messages and register clients that are using - this publisher """ + this publisher""" - def __init__(self, topic, node_handle, msg_type=None, latched_client_id=None, queue_size=100): - """ Register a publisher on the specified topic. + def __init__( + self, topic, node_handle, msg_type=None, latched_client_id=None, queue_size=100 + ): + """Register a publisher on the specified topic. Keyword arguments: topic -- the name of the topic to register the publisher to @@ -76,7 +81,9 @@ def __init__(self, topic, node_handle, msg_type=None, latched_client_id=None, qu # topic_type is a list of types or None at this point; only one type is supported. if topic_type is not None: if len(topic_type) > 1: - node_handle.get_logger().warning(f'More than one topic type detected: {topic_type}') + node_handle.get_logger().warning( + f"More than one topic type detected: {topic_type}" + ) topic_type = topic_type[0] # Use the established topic type if none was specified @@ -100,25 +107,29 @@ def __init__(self, topic, node_handle, msg_type=None, latched_client_id=None, qu # Adding a lifespan solves the problem of late-joining subscribers # without the need of a custom message publisher implementation. publisher_qos = QoSProfile( - depth=queue_size, durability=QoSDurabilityPolicy.RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL) + depth=queue_size, + durability=QoSDurabilityPolicy.RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL, + ) # For latched clients, no lifespan has to be specified (i.e. latch forever). # Otherwise we want to keep the messages for a second to prevent late-joining subscribers from # missing messages. if latched_client_id is None: - publisher_qos.lifespan=Duration(seconds=1) + publisher_qos.lifespan = Duration(seconds=1) else: publisher_qos.depth = 1 - self.publisher = node_handle.create_publisher(msg_class, topic, qos_profile=publisher_qos) + self.publisher = node_handle.create_publisher( + msg_class, topic, qos_profile=publisher_qos + ) def unregister(self): - """ Unregisters the publisher and clears the clients """ + """Unregisters the publisher and clears the clients""" self.node_handle.destroy_publisher(self.publisher) self.clients.clear() def verify_type(self, msg_type): - """ Verify that the publisher publishes messages of the specified type. + """Verify that the publisher publishes messages of the specified type. Keyword arguments: msg_type -- the type to check this publisher against @@ -130,12 +141,13 @@ def verify_type(self, msg_type): """ if not ros_loader.get_message_class(msg_type) is self.msg_class: - raise TypeConflictException(self.topic, - msg_class_type_repr(self.msg_class), msg_type) + raise TypeConflictException( + self.topic, msg_class_type_repr(self.msg_class), msg_type + ) return def publish(self, msg): - """ Publish a message using this publisher. + """Publish a message using this publisher. Keyword arguments: msg -- the dict (json) message to publish @@ -156,7 +168,7 @@ def publish(self, msg): self.publisher.publish(inst) def register_client(self, client_id): - """ Register the specified client as a client of this publisher. + """Register the specified client as a client of this publisher. Keyword arguments: client_id -- the ID of the client using the publisher @@ -165,7 +177,7 @@ def register_client(self, client_id): self.clients[client_id] = True def unregister_client(self, client_id): - """ Unregister the specified client from this publisher. + """Unregister the specified client from this publisher. If the specified client_id is not a client of this publisher, nothing happens. @@ -178,12 +190,12 @@ def unregister_client(self, client_id): del self.clients[client_id] def has_clients(self): - """ Return true if there are clients to this publisher. """ + """Return true if there are clients to this publisher.""" return len(self.clients) != 0 -class PublisherManager(): - """ The PublisherManager keeps track of ROS publishers +class PublisherManager: + """The PublisherManager keeps track of ROS publishers It maintains a MultiPublisher instance for each registered topic @@ -196,8 +208,10 @@ def __init__(self): self.unregister_timers = {} self.unregister_timeout = 10.0 - def register(self, client_id, topic, node_handle, msg_type=None, latch=False, queue_size=100): - """ Register a publisher on the specified topic. + def register( + self, client_id, topic, node_handle, msg_type=None, latch=False, queue_size=100 + ): + """Register a publisher on the specified topic. Publishers are shared between clients, so a single MultiPublisher instance is created per topic, even if multiple clients register. @@ -219,15 +233,28 @@ def register(self, client_id, topic, node_handle, msg_type=None, latch=False, qu latched_client_id = client_id if latch else None if topic not in self._publishers: self._publishers[topic] = MultiPublisher( - topic, node_handle, msg_type=msg_type, latched_client_id=latched_client_id, queue_size=queue_size) + topic, + node_handle, + msg_type=msg_type, + latched_client_id=latched_client_id, + queue_size=queue_size, + ) elif latch and self._publishers[topic].latched_client_id != client_id: - node_handle.get_logger().warn(f"Client ID {client_id} attempted to register topic [{topic}] as " - "latched but this topic was previously registered.") - node_handle.get_logger().warn("Only a single registered latched publisher is supported at the time") + node_handle.get_logger().warn( + f"Client ID {client_id} attempted to register topic [{topic}] as " + "latched but this topic was previously registered." + ) + node_handle.get_logger().warn( + "Only a single registered latched publisher is supported at the time" + ) elif not latch and self._publishers[topic].latched_client_id: - node_handle.get_logger().warn(f"New non-latched publisher registration for topic [{topic}] which is " - "already registered as latched. but this topic was previously registered.") - node_handle.get_logger().warn("Only a single registered latched publisher is supported at the time") + node_handle.get_logger().warn( + f"New non-latched publisher registration for topic [{topic}] which is " + "already registered as latched. but this topic was previously registered." + ) + node_handle.get_logger().warn( + "Only a single registered latched publisher is supported at the time" + ) if msg_type is not None: self._publishers[topic].verify_type(msg_type) @@ -235,7 +262,7 @@ def register(self, client_id, topic, node_handle, msg_type=None, latch=False, qu self._publishers[topic].register_client(client_id) def unregister(self, client_id, topic): - """ Unregister a client from the publisher for the given topic. + """Unregister a client from the publisher for the given topic. Will wait some time before actually unregistering, it is done in _unregister_impl @@ -254,8 +281,9 @@ def unregister(self, client_id, topic): if topic in self.unregister_timers: self.unregister_timers[topic].cancel() del self.unregister_timers[topic] - self.unregister_timers[topic] = Timer(self.unregister_timeout, self._unregister_impl, - [topic]) + self.unregister_timers[topic] = Timer( + self.unregister_timeout, self._unregister_impl, [topic] + ) self.unregister_timers[topic].start() def _unregister_impl(self, topic): @@ -265,16 +293,16 @@ def _unregister_impl(self, topic): del self.unregister_timers[topic] def unregister_all(self, client_id): - """ Unregisters a client from all publishers that they are registered + """Unregisters a client from all publishers that they are registered to. Keyword arguments: - client_id -- the ID of the client making this request """ + client_id -- the ID of the client making this request""" for topic in self._publishers.keys(): self.unregister(client_id, topic) def publish(self, client_id, topic, msg, node_handle, latch=False, queue_size=100): - """ Publish a message on the given topic. + """Publish a message on the given topic. Tries to create a publisher on the topic if one does not already exist. diff --git a/rosbridge_library/src/rosbridge_library/internal/ros_loader.py b/rosbridge_library/src/rosbridge_library/internal/ros_loader.py index bb91c9481..d640116e2 100644 --- a/rosbridge_library/src/rosbridge_library/internal/ros_loader.py +++ b/rosbridge_library/src/rosbridge_library/internal/ros_loader.py @@ -55,52 +55,55 @@ def __init__(self, typestring): class InvalidPackageException(Exception): def __init__(self, package, original_exception): - Exception.__init__(self, - "Unable to load the manifest for package %s. Caused by: %s" - % (package, str(original_exception)) - ) + Exception.__init__( + self, + "Unable to load the manifest for package %s. Caused by: %s" + % (package, str(original_exception)), + ) class InvalidModuleException(Exception): def __init__(self, modname, subname, original_exception): - Exception.__init__(self, - "Unable to import %s.%s from package %s. Caused by: %s" - % (modname, subname, modname, str(original_exception)) + Exception.__init__( + self, + "Unable to import %s.%s from package %s. Caused by: %s" + % (modname, subname, modname, str(original_exception)), ) class InvalidClassException(Exception): def __init__(self, modname, subname, classname, original_exception): - Exception.__init__(self, - "Unable to import %s class %s from package %s. Caused by %s" - % (subname, classname, modname, str(original_exception)) + Exception.__init__( + self, + "Unable to import %s class %s from package %s. Caused by %s" + % (subname, classname, modname, str(original_exception)), ) def get_message_class(typestring): - """ Loads the message type specified. + """Loads the message type specified. - Returns the loaded class, or throws exceptions on failure """ + Returns the loaded class, or throws exceptions on failure""" return _get_msg_class(typestring) def get_service_class(typestring): - """ Loads the service type specified. + """Loads the service type specified. - Returns the loaded class, or None on failure """ + Returns the loaded class, or None on failure""" return _get_srv_class(typestring) def get_message_instance(typestring): - """ If not loaded, loads the specified type. - Then returns an instance of it, or None. """ + """If not loaded, loads the specified type. + Then returns an instance of it, or None.""" cls = get_message_class(typestring) return cls() def get_service_instance(typestring): - """ If not loaded, loads the specified type. - Then returns an instance of it, or None. """ + """If not loaded, loads the specified type. + Then returns an instance of it, or None.""" cls = get_service_class(typestring) return cls() @@ -116,30 +119,30 @@ def get_service_response_instance(typestring): def _get_msg_class(typestring): - """ If not loaded, loads the specified msg class then returns an instance + """If not loaded, loads the specified msg class then returns an instance of it - Throws various exceptions if loading the msg class fails """ + Throws various exceptions if loading the msg class fails""" global _loaded_msgs, _msgs_lock return _get_class(typestring, "msg", _loaded_msgs, _msgs_lock) def _get_srv_class(typestring): - """ If not loaded, loads the specified srv class then returns an instance + """If not loaded, loads the specified srv class then returns an instance of it - Throws various exceptions if loading the srv class fails """ + Throws various exceptions if loading the srv class fails""" global _loaded_srvs, _srvs_lock return _get_class(typestring, "srv", _loaded_srvs, _srvs_lock) def _get_class(typestring, subname, cache, lock): - """ If not loaded, loads the specified class then returns an instance + """If not loaded, loads the specified class then returns an instance of it. Loaded classes are cached in the provided cache dict - Throws various exceptions if loading the msg class fails """ + Throws various exceptions if loading the msg class fails""" # First, see if we have this type string cached cls = _get_from_cache(cache, lock, typestring) @@ -166,17 +169,17 @@ def _get_class(typestring, subname, cache, lock): def _load_class(modname, subname, classname): - """ Loads the manifest and imports the module that contains the specified + """Loads the manifest and imports the module that contains the specified type. Logic is similar to that of roslib.message.get_message_class, but we want more expressive exceptions. - Returns the loaded module, or None on failure """ + Returns the loaded module, or None on failure""" # This assumes the module is already in the path. try: - pypkg = importlib.import_module(f'{modname}.{subname}') + pypkg = importlib.import_module(f"{modname}.{subname}") except Exception as exc: raise InvalidModuleException(modname, subname, exc) @@ -187,7 +190,7 @@ def _load_class(modname, subname, classname): def _splittype(typestring): - """ Split the string the / delimiter and strip out empty strings + """Split the string the / delimiter and strip out empty strings Performs similar logic to roslib.names.package_resource_name but is a bit more forgiving about excess slashes @@ -207,8 +210,8 @@ def _add_to_cache(cache, lock, key, value): def _get_from_cache(cache, lock, key): - """ Returns the value for the specified key from the cache. - Locks the lock before doing anything. Returns None if key not in cache """ + """Returns the value for the specified key from the cache. + Locks the lock before doing anything. Returns None if key not in cache""" lock.acquire() ret = None if key in cache: diff --git a/rosbridge_library/src/rosbridge_library/internal/services.py b/rosbridge_library/src/rosbridge_library/internal/services.py index 6e8309c62..30bac0b39 100644 --- a/rosbridge_library/src/rosbridge_library/internal/services.py +++ b/rosbridge_library/src/rosbridge_library/internal/services.py @@ -45,9 +45,8 @@ def __init__(self, servicename): class ServiceCaller(Thread): - def __init__(self, service, args, success_callback, error_callback, node_handle): - """ Create a service caller for the specified service. Use start() + """Create a service caller for the specified service. Use start() to start in a separate thread or run() to run in this thread. Keyword arguments: @@ -61,7 +60,7 @@ def __init__(self, service, args, success_callback, error_callback, node_handle) error_callback -- a callback to call if an error occurs. The callback will be passed the exception that caused the failure node_handle -- a ROS2 node handle to call services. - """ + """ Thread.__init__(self) self.daemon = True self.service = service @@ -80,11 +79,11 @@ def run(self): def args_to_service_request_instance(service, inst, args): - """ Populate a service request instance with the provided args + """Populate a service request instance with the provided args args can be a dictionary of values, or a list, or None - Propagates any exceptions that may be raised. """ + Propagates any exceptions that may be raised.""" msg = {} if isinstance(args, list): msg = dict(zip(inst.__slots__, args)) @@ -100,7 +99,9 @@ def call_service(node_handle, service, args=None): # and a request instance # This should be equivalent to rospy.resolve_name. - service = expand_topic_name(service, node_handle.get_name(), node_handle.get_namespace()) + 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) @@ -108,7 +109,9 @@ def call_service(node_handle, service, args=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}') + node_handle.get_logger().warning( + f"More than one service type detected: {service_type}" + ) service_type = service_type[0] service_class = get_service_class(service_type) diff --git a/rosbridge_library/src/rosbridge_library/internal/subscribers.py b/rosbridge_library/src/rosbridge_library/internal/subscribers.py index f496e4d95..f6a308a25 100644 --- a/rosbridge_library/src/rosbridge_library/internal/subscribers.py +++ b/rosbridge_library/src/rosbridge_library/internal/subscribers.py @@ -43,15 +43,18 @@ is shared between multiple clients """ -class MultiSubscriber(): - """ Handles multiple clients for a single subscriber. + +class MultiSubscriber: + """Handles multiple clients for a single subscriber. Converts msgs to JSON before handing them to callbacks. Due to subscriber callbacks being called in separate threads, must lock whenever modifying - or accessing the subscribed clients. """ + or accessing the subscribed clients.""" - def __init__(self, topic, client_id, callback, node_handle, msg_type=None, raw=False): - """ Register a subscriber on the specified topic. + def __init__( + self, topic, client_id, callback, node_handle, msg_type=None, raw=False + ): + """Register a subscriber on the specified topic. Keyword arguments: topic -- the name of the topic to register the subscriber on @@ -82,7 +85,9 @@ def __init__(self, topic, client_id, callback, node_handle, msg_type=None, raw=F # topic_type is a list of types or None at this point; only one type is supported. if topic_type is not None: if len(topic_type) > 1: - node_handle.get_logger().warning(f'More than one topic type detected: {topic_type}') + node_handle.get_logger().warning( + f"More than one topic type detected: {topic_type}" + ) topic_type = topic_type[0] # Use the established topic type if none was specified @@ -105,7 +110,9 @@ def __init__(self, topic, client_id, callback, node_handle, msg_type=None, raw=F self.msg_class = msg_class self.node_handle = node_handle # TODO(@jubeira): add support for other QoS. - self.subscriber = node_handle.create_subscription(msg_class, topic, self.callback, 10, raw=raw) + self.subscriber = node_handle.create_subscription( + msg_class, topic, self.callback, 10, raw=raw + ) self.new_subscriber = None self.new_subscriptions = {} @@ -115,7 +122,7 @@ def unregister(self): self.subscriptions.clear() def verify_type(self, msg_type): - """ Verify that the subscriber subscribes to messages of this type. + """Verify that the subscriber subscribes to messages of this type. Keyword arguments: msg_type -- the type to check this subscriber against @@ -127,12 +134,13 @@ def verify_type(self, msg_type): """ if not ros_loader.get_message_class(msg_type) is self.msg_class: - raise TypeConflictException(self.topic, - msg_class_type_repr(self.msg_class), msg_type) + raise TypeConflictException( + self.topic, msg_class_type_repr(self.msg_class), msg_type + ) return def subscribe(self, client_id, callback): - """ Subscribe the specified client to this subscriber. + """Subscribe the specified client to this subscriber. Keyword arguments: client_id -- the ID of the client subscribing @@ -148,10 +156,11 @@ def subscribe(self, client_id, callback): self.new_subscriptions.update({client_id: callback}) if self.new_subscriber is None: self.new_subscriber = self.node_handle.create_subscription( - self.msg_class, self.topic, self._new_sub_callback, 10) + self.msg_class, self.topic, self._new_sub_callback, 10 + ) def unsubscribe(self, client_id): - """ Unsubscribe the specified client from this subscriber + """Unsubscribe the specified client from this subscriber Keyword arguments: client_id -- the ID of the client to unsubscribe @@ -161,13 +170,13 @@ def unsubscribe(self, client_id): del self.subscriptions[client_id] def has_subscribers(self): - """ Return true if there are subscribers """ + """Return true if there are subscribers""" with self.lock: ret = len(self.subscriptions) != 0 return ret def callback(self, msg, callbacks=None): - """ Callback for incoming messages on the rclpy subscription. + """Callback for incoming messages on the rclpy subscription. Passes the message to registered subscriber callbacks. @@ -189,7 +198,9 @@ def callback(self, msg, callbacks=None): callback(outgoing) except Exception as exc: # Do nothing if one particular callback fails except log it - self.node_handle.get_logger().error(f"Exception calling subscribe callback: {exc}") + self.node_handle.get_logger().error( + f"Exception calling subscribe callback: {exc}" + ) pass def _new_sub_callback(self, msg): @@ -211,7 +222,7 @@ def _new_sub_callback(self, msg): self.new_subscriber = None -class SubscriberManager(): +class SubscriberManager: """ Keeps track of client subscriptions """ @@ -219,8 +230,10 @@ class SubscriberManager(): def __init__(self): self._subscribers = {} - def subscribe(self, client_id, topic, callback, node_handle, msg_type=None, raw=False): - """ Subscribe to a topic + def subscribe( + self, client_id, topic, callback, node_handle, msg_type=None, raw=False + ): + """Subscribe to a topic Keyword arguments: client_id -- the ID of the client making this subscribe request @@ -231,7 +244,8 @@ def subscribe(self, client_id, topic, callback, node_handle, msg_type=None, raw= """ if topic not in self._subscribers: self._subscribers[topic] = MultiSubscriber( - topic, client_id, callback, node_handle, msg_type=msg_type, raw=raw) + topic, client_id, callback, node_handle, msg_type=msg_type, raw=raw + ) else: self._subscribers[topic].subscribe(client_id, callback) @@ -239,7 +253,7 @@ def subscribe(self, client_id, topic, callback, node_handle, msg_type=None, raw= self._subscribers[topic].verify_type(msg_type) def unsubscribe(self, client_id, topic): - """ Unsubscribe from a topic + """Unsubscribe from a topic Keyword arguments: client_id -- the ID of the client to unsubscribe @@ -257,4 +271,3 @@ def unsubscribe(self, client_id, topic): manager = SubscriberManager() - diff --git a/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py b/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py index 55905ea35..fdd01e8af 100644 --- a/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py +++ b/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py @@ -41,7 +41,7 @@ """ -class MessageHandler(): +class MessageHandler: def __init__(self, previous_handler=None, publish=None): if previous_handler: self.last_publish = previous_handler.last_publish @@ -82,7 +82,6 @@ def finish(self): class ThrottleMessageHandler(MessageHandler): - def handle_message(self, msg): if self.time_remaining() == 0: MessageHandler.handle_message(self, msg) @@ -100,7 +99,6 @@ def finish(self): class QueueMessageHandler(MessageHandler, Thread): - def __init__(self, previous_handler): Thread.__init__(self) MessageHandler.__init__(self, previous_handler) @@ -115,7 +113,7 @@ def handle_message(self, msg): should_notify = len(self.queue) == 0 self.queue.append(msg) if len(self.queue) > self.queue_length: - del self.queue[0:len(self.queue) - self.queue_length] + del self.queue[0 : len(self.queue) - self.queue_length] if should_notify: self.c.notify() @@ -129,12 +127,12 @@ def transition(self): else: with self.c: if len(self.queue) > self.queue_length: - del self.queue[0:len(self.queue) - self.queue_length] + del self.queue[0 : len(self.queue) - self.queue_length] self.c.notify() return self def finish(self): - """ If throttle was set to 0, this pushes all buffered messages """ + """If throttle was set to 0, this pushes all buffered messages""" # Notify the thread to finish with self.c: self.alive = False @@ -145,7 +143,9 @@ def finish(self): def run(self): while self.alive: with self.c: - while self.alive and (self.time_remaining() > 0 or len(self.queue) == 0): + while self.alive and ( + self.time_remaining() > 0 or len(self.queue) == 0 + ): if len(self.queue) == 0: self.c.wait() else: diff --git a/rosbridge_library/src/rosbridge_library/internal/topics.py b/rosbridge_library/src/rosbridge_library/internal/topics.py index 8f911daa8..259b6e198 100644 --- a/rosbridge_library/src/rosbridge_library/internal/topics.py +++ b/rosbridge_library/src/rosbridge_library/internal/topics.py @@ -35,13 +35,20 @@ class TopicNotEstablishedException(Exception): def __init__(self, topic): - Exception.__init__(self, - "Cannot infer topic type for topic %s as it is not yet advertised" % - (topic,)) + Exception.__init__( + self, + "Cannot infer topic type for topic %s as it is not yet advertised" + % (topic,), + ) class TypeConflictException(Exception): def __init__(self, topic, orig_type, new_type): - Exception.__init__(self, - ("Tried to register topic %s with type %s but it is already" + - " established with type %s") % (topic, new_type, orig_type)) + Exception.__init__( + self, + ( + "Tried to register topic %s with type %s but it is already" + + " established with type %s" + ) + % (topic, new_type, orig_type), + ) diff --git a/rosbridge_library/src/rosbridge_library/protocol.py b/rosbridge_library/src/rosbridge_library/protocol.py index 99139ecce..595781914 100644 --- a/rosbridge_library/src/rosbridge_library/protocol.py +++ b/rosbridge_library/src/rosbridge_library/protocol.py @@ -45,8 +45,7 @@ def is_number(s): def has_binary(obj): - """ Returns True if obj is a binary or contains a binary attribute - """ + """Returns True if obj is a binary or contains a binary attribute""" if isinstance(obj, list): return any(has_binary(item) for item in obj) @@ -58,7 +57,7 @@ def has_binary(obj): class Protocol: - """ The interface for a single client to interact with ROS. + """The interface for a single client to interact with ROS. See rosbridge_protocol for the default protocol used by rosbridge @@ -89,7 +88,7 @@ class Protocol: parameters = None def __init__(self, client_id, node_handle): - """ Keyword arguments: + """Keyword arguments: client_id -- a unique ID for this client to take. Uniqueness is important otherwise there will be conflicts between multiple clients with shared resources @@ -104,18 +103,18 @@ def __init__(self, client_id, node_handle): if self.parameters: self.fragment_size = self.parameters["max_message_size"] self.delay_between_messages = self.parameters["delay_between_messages"] - self.bson_only_mode = self.parameters.get('bson_only_mode', False) + self.bson_only_mode = self.parameters.get("bson_only_mode", False) # added default message_string="" to allow recalling incoming until buffer is empty without giving a parameter # --> allows to get rid of (..or minimize) delay between client-side sends def incoming(self, message_string=""): - """ Process an incoming message from the client + """Process an incoming message from the client Keyword arguments: message_string -- the wire-level message sent by the client """ - if(len(self.buffer) > 0): + if len(self.buffer) > 0: self.buffer = self.buffer + message_string else: self.buffer = message_string @@ -150,21 +149,25 @@ def incoming(self, message_string=""): # fragment data must NOT (!) contain a complete json-object that has an "op-field" # # an alternative solution would be to only check from first opening bracket and have a time out on data in input buffer.. (to handle broken data) - opening_brackets = [i for i, letter in enumerate(self.buffer) if letter == '{'] - closing_brackets = [i for i, letter in enumerate(self.buffer) if letter == '}'] + opening_brackets = [ + i for i, letter in enumerate(self.buffer) if letter == "{" + ] + closing_brackets = [ + i for i, letter in enumerate(self.buffer) if letter == "}" + ] for start in opening_brackets: for end in closing_brackets: try: - msg = self.deserialize(self.buffer[start:end+1]) - if msg.get("op",None) is not None: + msg = self.deserialize(self.buffer[start : end + 1]) + if msg.get("op", None) is not None: # TODO: check if throwing away leading data like this is okay.. loops look okay.. - self.buffer = self.buffer[end+1:len(self.buffer)] + self.buffer = self.buffer[end + 1 : len(self.buffer)] # jump out of inner loop if json-decode succeeded break except Exception: # debug json-decode errors with this line - #print e + # print e pass # if load was successful --> break outer loop, too.. -> no need to check if json begins at a "later" opening bracket.. if msg is not None: @@ -180,19 +183,31 @@ def incoming(self, message_string=""): mid = msg["id"] if "op" not in msg: if "receiver" in msg: - self.log("error", "Received a rosbridge v1.0 message. Please refer to rosbridge.org for the correct format of rosbridge v2.0 messages. Original message was: %s" % message_string) + self.log( + "error", + "Received a rosbridge v1.0 message. Please refer to rosbridge.org for the correct format of rosbridge v2.0 messages. Original message was: %s" + % message_string, + ) else: - self.log("error", f"Received a message without an op. All messages require 'op' field with value one of: {list(self.operations.keys())}. Original message was: {message_string}", mid) + self.log( + "error", + f"Received a message without an op. All messages require 'op' field with value one of: {list(self.operations.keys())}. Original message was: {message_string}", + mid, + ) return op = msg["op"] if op not in self.operations: - self.log("error", f"Unknown operation: {op}. Allowed operations: {list(self.operations.keys())}", mid) + self.log( + "error", + f"Unknown operation: {op}. Allowed operations: {list(self.operations.keys())}", + mid, + ) return # this way a client can change/overwrite it's active values anytime by just including parameter field in any message sent to rosbridge # maybe need to be improved to bind parameter values to specific operation.. if "fragment_size" in msg.keys(): self.fragment_size = msg["fragment_size"] - #print "fragment size set to:", self.fragment_size + # print "fragment size set to:", self.fragment_size if "message_intervall" in msg.keys() and is_number(msg["message_intervall"]): self.delay_between_messages = msg["message_intervall"] if "png" in msg.keys(): @@ -212,10 +227,8 @@ def incoming(self, message_string=""): self.old_buffer = self.buffer self.incoming() - - def outgoing(self, message): - """ Pass an outgoing message to the client. This method should be + """Pass an outgoing message to the client. This method should be overridden. Keyword arguments: @@ -225,7 +238,7 @@ def outgoing(self, message): pass def send(self, message, cid=None): - """ Called internally in preparation for sending messages to the client + """Called internally in preparation for sending messages to the client This method pre-processes the message then passes it to the overridden outgoing method. @@ -248,7 +261,9 @@ def send(self, message, cid=None): # TODO: think about splitting into fragments that have specified size including header-fields! # --> estimate header size --> split content into fragments that have the requested overall size, rather than requested content size - fragment_list = Fragmentation(self).fragment(message, self.fragment_size, mid ) + fragment_list = Fragmentation(self).fragment( + message, self.fragment_size, mid + ) # fragment list not empty -> send fragments if fragment_list is not None: @@ -266,7 +281,7 @@ def send(self, message, cid=None): time.sleep(self.delay_between_messages) def finish(self): - """ Indicate that the client is finished and clean up resources. + """Indicate that the client is finished and clean up resources. All clients should call this method after disconnecting. @@ -275,7 +290,7 @@ def finish(self): capability.finish() def serialize(self, msg, cid=None): - """ Turns a dictionary of values into the appropriate wire-level + """Turns a dictionary of values into the appropriate wire-level representation. Default behaviour uses JSON. Override to use a different container. @@ -291,18 +306,19 @@ def serialize(self, msg, cid=None): return msg if has_binary(msg) or self.bson_only_mode: return bson.BSON.encode(msg) - else: + else: return json.dumps(msg) except Exception: if cid is not None: # Only bother sending the log message if there's an id - self.log("error", "Unable to serialize %s message to client" - % msg["op"], cid) + self.log( + "error", "Unable to serialize %s message to client" % msg["op"], cid + ) return None def deserialize(self, msg, cid=None): - """ Turns the wire-level representation into a dictionary of values + """Turns the wire-level representation into a dictionary of values Default behaviour assumes JSON. Override to use a different container. @@ -326,18 +342,18 @@ def deserialize(self, msg, cid=None): # TODO: implement a way to have a final Exception when nothing works out to decode (multiple/broken/partial JSON..) # suppressed logging of exception on json-decode to keep rosbridge-logs "clean", otherwise console logs would get spammed for every failed json-decode try -# if msg != self.buffer: -# error_msg = "Unable to deserialize message from client: %s" % msg -# error_msg += "\nException was: " +str(e) -# -# self.log("error", error_msg, cid) + # if msg != self.buffer: + # error_msg = "Unable to deserialize message from client: %s" % msg + # error_msg += "\nException was: " +str(e) + # + # self.log("error", error_msg, cid) # re-raise Exception to allow handling outside of deserialize function instead of returning None raise - #return None + # return None def register_operation(self, opcode, handler): - """ Register a handler for an opcode + """Register a handler for an opcode Keyword arguments: opcode -- the opcode to register this handler for @@ -347,7 +363,7 @@ def register_operation(self, opcode, handler): self.operations[opcode] = handler def unregister_operation(self, opcode): - """ Unregister a handler for an opcode + """Unregister a handler for an opcode Keyword arguments: opcode -- the opcode to unregister the handler for @@ -357,7 +373,7 @@ def unregister_operation(self, opcode): del self.operations[opcode] def add_capability(self, capability_class): - """ Add a capability to the protocol. + """Add a capability to the protocol. This method is for convenience; assumes the default capability constructor @@ -369,7 +385,7 @@ def add_capability(self, capability_class): self.capabilities.append(capability_class(self)) def log(self, level, message, lid=None): - """ Log a message to the client. By default just sends to stdout + """Log a message to the client. By default just sends to stdout Keyword arguments: level -- the logger level of this message diff --git a/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py b/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py index 2af66646c..ed0f0c27a 100644 --- a/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py +++ b/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py @@ -35,18 +35,29 @@ from rosbridge_library.capabilities.advertise import Advertise from rosbridge_library.capabilities.publish import Publish from rosbridge_library.capabilities.subscribe import Subscribe + # imports for defragmentation from rosbridge_library.capabilities.defragmentation import Defragment + # imports for external service_server from rosbridge_library.capabilities.advertise_service import AdvertiseService from rosbridge_library.capabilities.service_response import ServiceResponse from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService - class RosbridgeProtocol(Protocol): - """ Adds the handlers for the rosbridge opcodes """ - rosbridge_capabilities = [CallService, Advertise, Publish, Subscribe, Defragment, AdvertiseService, ServiceResponse, UnadvertiseService] + """Adds the handlers for the rosbridge opcodes""" + + rosbridge_capabilities = [ + CallService, + Advertise, + Publish, + Subscribe, + Defragment, + AdvertiseService, + ServiceResponse, + UnadvertiseService, + ] print("registered capabilities (classes):") for cap in rosbridge_capabilities: @@ -54,7 +65,7 @@ class RosbridgeProtocol(Protocol): parameters = None - def __init__(self, client_id, node_handle, parameters = None): + def __init__(self, client_id, node_handle, parameters=None): self.parameters = parameters Protocol.__init__(self, client_id, node_handle) for capability_class in self.rosbridge_capabilities: diff --git a/rosbridge_library/src/rosbridge_library/util/__init__.py b/rosbridge_library/src/rosbridge_library/util/__init__.py index e69d21692..8b04567e1 100644 --- a/rosbridge_library/src/rosbridge_library/util/__init__.py +++ b/rosbridge_library/src/rosbridge_library/util/__init__.py @@ -8,6 +8,7 @@ import json # noqa: F401 import bson + try: bson.BSON except AttributeError: diff --git a/rosbridge_library/src/rosbridge_library/util/cbor.py b/rosbridge_library/src/rosbridge_library/util/cbor.py index bdb5db0fe..ce67adcf3 100644 --- a/rosbridge_library/src/rosbridge_library/util/cbor.py +++ b/rosbridge_library/src/rosbridge_library/util/cbor.py @@ -25,51 +25,53 @@ CBOR_INFO_BITS = 0x1F # low 5 bits -CBOR_UINT = 0x00 -CBOR_NEGINT = 0x20 -CBOR_BYTES = 0x40 -CBOR_TEXT = 0x60 -CBOR_ARRAY = 0x80 -CBOR_MAP = 0xA0 -CBOR_TAG = 0xC0 -CBOR_7 = 0xE0 # float and other types - -CBOR_UINT8_FOLLOWS = 24 # 0x18 +CBOR_UINT = 0x00 +CBOR_NEGINT = 0x20 +CBOR_BYTES = 0x40 +CBOR_TEXT = 0x60 +CBOR_ARRAY = 0x80 +CBOR_MAP = 0xA0 +CBOR_TAG = 0xC0 +CBOR_7 = 0xE0 # float and other types + +CBOR_UINT8_FOLLOWS = 24 # 0x18 CBOR_UINT16_FOLLOWS = 25 # 0x19 CBOR_UINT32_FOLLOWS = 26 # 0x1a CBOR_UINT64_FOLLOWS = 27 # 0x1b -CBOR_VAR_FOLLOWS = 31 # 0x1f - -CBOR_BREAK = 0xFF - -CBOR_FALSE = (CBOR_7 | 20) -CBOR_TRUE = (CBOR_7 | 21) -CBOR_NULL = (CBOR_7 | 22) -CBOR_UNDEFINED = (CBOR_7 | 23) # js 'undefined' value - -CBOR_FLOAT16 = (CBOR_7 | 25) -CBOR_FLOAT32 = (CBOR_7 | 26) -CBOR_FLOAT64 = (CBOR_7 | 27) - -CBOR_TAG_DATE_STRING = 0 # RFC3339 -CBOR_TAG_DATE_ARRAY = 1 # any number type follows, seconds since 1970-01-01T00:00:00 UTC -CBOR_TAG_BIGNUM = 2 # big endian byte string follows -CBOR_TAG_NEGBIGNUM = 3 # big endian byte string follows -CBOR_TAG_DECIMAL = 4 # [ 10^x exponent, number ] -CBOR_TAG_BIGFLOAT = 5 # [ 2^x exponent, number ] +CBOR_VAR_FOLLOWS = 31 # 0x1f + +CBOR_BREAK = 0xFF + +CBOR_FALSE = CBOR_7 | 20 +CBOR_TRUE = CBOR_7 | 21 +CBOR_NULL = CBOR_7 | 22 +CBOR_UNDEFINED = CBOR_7 | 23 # js 'undefined' value + +CBOR_FLOAT16 = CBOR_7 | 25 +CBOR_FLOAT32 = CBOR_7 | 26 +CBOR_FLOAT64 = CBOR_7 | 27 + +CBOR_TAG_DATE_STRING = 0 # RFC3339 +CBOR_TAG_DATE_ARRAY = ( + 1 # any number type follows, seconds since 1970-01-01T00:00:00 UTC +) +CBOR_TAG_BIGNUM = 2 # big endian byte string follows +CBOR_TAG_NEGBIGNUM = 3 # big endian byte string follows +CBOR_TAG_DECIMAL = 4 # [ 10^x exponent, number ] +CBOR_TAG_BIGFLOAT = 5 # [ 2^x exponent, number ] CBOR_TAG_BASE64URL = 21 CBOR_TAG_BASE64 = 22 CBOR_TAG_BASE16 = 23 -CBOR_TAG_CBOR = 24 # following byte string is embedded CBOR data +CBOR_TAG_CBOR = 24 # following byte string is embedded CBOR data CBOR_TAG_URI = 32 CBOR_TAG_BASE64URL = 33 CBOR_TAG_BASE64 = 34 CBOR_TAG_REGEX = 35 -CBOR_TAG_MIME = 36 # following text is MIME message, headers, separators and all -CBOR_TAG_CBOR_FILEHEADER = 55799 # can open a file with 0xd9d9f7 +CBOR_TAG_MIME = 36 # following text is MIME message, headers, separators and all +CBOR_TAG_CBOR_FILEHEADER = 55799 # can open a file with 0xd9d9f7 -_CBOR_TAG_BIGNUM_BYTES = struct.pack('B', CBOR_TAG | CBOR_TAG_BIGNUM) +_CBOR_TAG_BIGNUM_BYTES = struct.pack("B", CBOR_TAG | CBOR_TAG_BIGNUM) def dumps_int(val): @@ -77,15 +79,15 @@ def dumps_int(val): if val >= 0: # CBOR_UINT is 0, so I'm lazy/efficient about not OR-ing it in. if val <= 23: - return struct.pack('B', val) - if val <= 0x0ff: - return struct.pack('BB', CBOR_UINT8_FOLLOWS, val) - if val <= 0x0ffff: - return struct.pack('!BH', CBOR_UINT16_FOLLOWS, val) - if val <= 0x0ffffffff: - return struct.pack('!BI', CBOR_UINT32_FOLLOWS, val) - if val <= 0x0ffffffffffffffff: - return struct.pack('!BQ', CBOR_UINT64_FOLLOWS, val) + return struct.pack("B", val) + if val <= 0x0FF: + return struct.pack("BB", CBOR_UINT8_FOLLOWS, val) + if val <= 0x0FFFF: + return struct.pack("!BH", CBOR_UINT16_FOLLOWS, val) + if val <= 0x0FFFFFFFF: + return struct.pack("!BI", CBOR_UINT32_FOLLOWS, val) + if val <= 0x0FFFFFFFFFFFFFFFF: + return struct.pack("!BQ", CBOR_UINT64_FOLLOWS, val) outb = _dumps_bignum_to_bytearray(val) return _CBOR_TAG_BIGNUM_BYTES + _encode_type_num(CBOR_BYTES, len(outb)) + outb val = -1 - val @@ -95,7 +97,7 @@ def dumps_int(val): def _dumps_bignum_to_bytearray(val): out = [] while val > 0: - out.insert(0, val & 0x0ff) + out.insert(0, val & 0x0FF) val = val >> 8 return bytes(out) @@ -104,23 +106,24 @@ def dumps_float(val): return struct.pack("!Bd", CBOR_FLOAT64, val) -_CBOR_TAG_NEGBIGNUM_BYTES = struct.pack('B', CBOR_TAG | CBOR_TAG_NEGBIGNUM) +_CBOR_TAG_NEGBIGNUM_BYTES = struct.pack("B", CBOR_TAG | CBOR_TAG_NEGBIGNUM) def _encode_type_num(cbor_type, val): """For some CBOR primary type [0..7] and an auxiliary unsigned number, return CBOR encoded bytes""" assert val >= 0 if val <= 23: - return struct.pack('B', cbor_type | val) - if val <= 0x0ff: - return struct.pack('BB', cbor_type | CBOR_UINT8_FOLLOWS, val) - if val <= 0x0ffff: - return struct.pack('!BH', cbor_type | CBOR_UINT16_FOLLOWS, val) - if val <= 0x0ffffffff: - return struct.pack('!BI', cbor_type | CBOR_UINT32_FOLLOWS, val) - if (((cbor_type == CBOR_NEGINT) and (val <= 0x07fffffffffffffff)) or - ((cbor_type != CBOR_NEGINT) and (val <= 0x0ffffffffffffffff))): - return struct.pack('!BQ', cbor_type | CBOR_UINT64_FOLLOWS, val) + return struct.pack("B", cbor_type | val) + if val <= 0x0FF: + return struct.pack("BB", cbor_type | CBOR_UINT8_FOLLOWS, val) + if val <= 0x0FFFF: + return struct.pack("!BH", cbor_type | CBOR_UINT16_FOLLOWS, val) + if val <= 0x0FFFFFFFF: + return struct.pack("!BI", cbor_type | CBOR_UINT32_FOLLOWS, val) + if ((cbor_type == CBOR_NEGINT) and (val <= 0x07FFFFFFFFFFFFFFF)) or ( + (cbor_type != CBOR_NEGINT) and (val <= 0x0FFFFFFFFFFFFFFFF) + ): + return struct.pack("!BQ", cbor_type | CBOR_UINT64_FOLLOWS, val) if cbor_type != CBOR_NEGINT: raise Exception(f"value too big for CBOR unsigned number: {val!r}") outb = _dumps_bignum_to_bytearray(val) @@ -133,7 +136,7 @@ def _is_unicode(val): def dumps_string(val, is_text=None, is_bytes=None): if _is_unicode(val): - val = val.encode('utf8') + val = val.encode("utf8") is_text = True is_bytes = False if is_bytes or is_text is not True: @@ -144,7 +147,7 @@ def dumps_string(val, is_text=None, is_bytes=None): def dumps_array(arr, sort_keys=False): head = _encode_type_num(CBOR_ARRAY, len(arr)) parts = [dumps(x, sort_keys=sort_keys) for x in arr] - return head + b''.join(parts) + return head + b"".join(parts) def dumps_dict(d, sort_keys=False): @@ -156,16 +159,16 @@ def dumps_dict(d, sort_keys=False): parts.append(dumps(k, sort_keys=sort_keys)) parts.append(dumps(v, sort_keys=sort_keys)) else: - for k,v in d.items(): + for k, v in d.items(): parts.append(dumps(k, sort_keys=sort_keys)) parts.append(dumps(v, sort_keys=sort_keys)) - return b''.join(parts) + return b"".join(parts) def dumps_bool(b): if b: - return struct.pack('B', CBOR_TRUE) - return struct.pack('B', CBOR_FALSE) + return struct.pack("B", CBOR_TRUE) + return struct.pack("B", CBOR_FALSE) def dumps_tag(t, sort_keys=False): @@ -182,7 +185,7 @@ def _is_intish(x): def dumps(ob, sort_keys=False): if ob is None: - return struct.pack('B', CBOR_NULL) + return struct.pack("B", CBOR_NULL) if isinstance(ob, bool): return dumps_bool(ob) if _is_stringish(ob): @@ -349,9 +352,9 @@ def _loads_tb(fp, tb, limit=None, depth=0, returntags=False): val = mant * (2.0 ** -24) elif exp == 31: if mant == 0: - val = float('Inf') + val = float("Inf") else: - val = float('NaN') + val = float("NaN") else: val = (mant + 1024.0) * (2 ** (exp - 25)) if hibyte & 0x80: @@ -377,7 +380,7 @@ def _loads_tb(fp, tb, limit=None, depth=0, returntags=False): return (ob, bytes_read + subpos) elif tag == CBOR_TEXT: raw, subpos = loads_bytes(fp, aux, btag=CBOR_TEXT) - ob = raw.decode('utf8') + ob = raw.decode("utf8") return (ob, bytes_read + subpos) elif tag == CBOR_ARRAY: if aux is None: @@ -424,11 +427,11 @@ def loads_bytes(fp, aux, btag=CBOR_BYTES): total_bytes_read += 1 break tag, tag_aux, aux, bytes_read = _tag_aux(fp, tb) - assert tag == btag, 'variable length value contains unexpected component' + assert tag == btag, "variable length value contains unexpected component" ob = fp.read(aux) chunklist.append(ob) total_bytes_read += bytes_read + aux - return (b''.join(chunklist), total_bytes_read) + return (b"".join(chunklist), total_bytes_read) def _bytes_to_biguint(bs): diff --git a/rosbridge_library/test/capabilities/test_advertise.py b/rosbridge_library/test/capabilities/test_advertise.py index e2d94def0..267601acc 100755 --- a/rosbridge_library/test/capabilities/test_advertise.py +++ b/rosbridge_library/test/capabilities/test_advertise.py @@ -5,7 +5,10 @@ from time import sleep from rosbridge_library.protocol import Protocol -from rosbridge_library.protocol import InvalidArgumentException, MissingArgumentException +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, +) from rosbridge_library.capabilities.advertise import Advertise from rosbridge_library.internal.publishers import manager from rosbridge_library.internal import ros_loader @@ -14,7 +17,6 @@ class TestAdvertise(unittest.TestCase): - def setUp(self): rospy.init_node("test_advertise") manager.unregister_timeout = 1.0 @@ -45,75 +47,133 @@ def test_invalid_arguments(self): self.assertRaises(InvalidArgumentException, adv.advertise, loads(dumps(msg))) def test_invalid_msg_typestrings(self): - invalid = ["", "/", "//", "///", "////", "/////", "bad", "stillbad", - "not/better/still", "not//better//still", "not///better///still", - "better/", "better//", "better///", "/better", "//better", "///better", - r"this\isbad", "\\"] + invalid = [ + "", + "/", + "//", + "///", + "////", + "/////", + "bad", + "stillbad", + "not/better/still", + "not//better//still", + "not///better///still", + "better/", + "better//", + "better///", + "/better", + "//better", + "///better", + r"this\isbad", + "\\", + ] proto = Protocol("hello") adv = Advertise(proto) for invalid_type in invalid: - msg = {"op": "advertise", "topic": "/test_invalid_msg_typestrings", - "type": invalid_type} - self.assertRaises(ros_loader.InvalidTypeStringException, - adv.advertise, loads(dumps(msg))) + msg = { + "op": "advertise", + "topic": "/test_invalid_msg_typestrings", + "type": invalid_type, + } + self.assertRaises( + ros_loader.InvalidTypeStringException, adv.advertise, loads(dumps(msg)) + ) def test_invalid_msg_package(self): - nonexistent = ["wangle_msgs/Jam", "whistleblower_msgs/Document", - "sexual_harrassment_msgs/UnwantedAdvance", "coercion_msgs/Bribe", - "airconditioning_msgs/Cold", "pr2thoughts_msgs/Escape"] + nonexistent = [ + "wangle_msgs/Jam", + "whistleblower_msgs/Document", + "sexual_harrassment_msgs/UnwantedAdvance", + "coercion_msgs/Bribe", + "airconditioning_msgs/Cold", + "pr2thoughts_msgs/Escape", + ] proto = Protocol("hello") adv = Advertise(proto) for invalid_type in nonexistent: - msg = {"op": "advertise", "topic": "/test_invalid_msg_package", - "type": invalid_type} - self.assertRaises(ros_loader.InvalidPackageException, - adv.advertise, loads(dumps(msg))) + msg = { + "op": "advertise", + "topic": "/test_invalid_msg_package", + "type": invalid_type, + } + self.assertRaises( + ros_loader.InvalidPackageException, adv.advertise, loads(dumps(msg)) + ) def test_invalid_msg_module(self): - no_msgs = ["roslib/Time", "roslib/Duration", "roslib/Header", - "std_srvs/ConflictedMsg", "topic_tools/MessageMessage"] + no_msgs = [ + "roslib/Time", + "roslib/Duration", + "roslib/Header", + "std_srvs/ConflictedMsg", + "topic_tools/MessageMessage", + ] proto = Protocol("hello") adv = Advertise(proto) for invalid_type in no_msgs: - msg = {"op": "advertise", "topic": "/test_invalid_msg_module", - "type": invalid_type} - self.assertRaises(ros_loader.InvalidModuleException, - adv.advertise, loads(dumps(msg))) + msg = { + "op": "advertise", + "topic": "/test_invalid_msg_module", + "type": invalid_type, + } + self.assertRaises( + ros_loader.InvalidModuleException, adv.advertise, loads(dumps(msg)) + ) def test_invalid_msg_classes(self): - nonexistent = ["roscpp/Time", "roscpp/Duration", "roscpp/Header", - "rospy/Time", "rospy/Duration", "rospy/Header", "std_msgs/Spool", - "geometry_msgs/Tetrahedron", "sensor_msgs/TelepathyUnit"] + nonexistent = [ + "roscpp/Time", + "roscpp/Duration", + "roscpp/Header", + "rospy/Time", + "rospy/Duration", + "rospy/Header", + "std_msgs/Spool", + "geometry_msgs/Tetrahedron", + "sensor_msgs/TelepathyUnit", + ] proto = Protocol("hello") adv = Advertise(proto) for invalid_type in nonexistent: - msg = {"op": "advertise", "topic": "/test_invalid_msg_classes", - "type": invalid_type} - self.assertRaises(ros_loader.InvalidClassException, - adv.advertise, loads(dumps(msg))) + msg = { + "op": "advertise", + "topic": "/test_invalid_msg_classes", + "type": invalid_type, + } + self.assertRaises( + ros_loader.InvalidClassException, adv.advertise, loads(dumps(msg)) + ) def test_valid_msg_classes(self): - assortedmsgs = ["geometry_msgs/Pose", "actionlib_msgs/GoalStatus", - "geometry_msgs/WrenchStamped", "stereo_msgs/DisparityImage", - "nav_msgs/OccupancyGrid", "geometry_msgs/Point32", "std_msgs/String", - "trajectory_msgs/JointTrajectoryPoint", "diagnostic_msgs/KeyValue", - "visualization_msgs/InteractiveMarkerUpdate", "nav_msgs/GridCells", - "sensor_msgs/PointCloud2"] + assortedmsgs = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "std_msgs/String", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] proto = Protocol("hello") adv = Advertise(proto) for valid_type in assortedmsgs: - msg = {"op": "advertise", "topic": "/" + valid_type, - "type": valid_type} + msg = {"op": "advertise", "topic": "/" + valid_type, "type": valid_type} adv.advertise(loads(dumps(msg))) adv.unadvertise(loads(dumps(msg))) @@ -132,8 +192,7 @@ def test_do_advertise(self): self.assertFalse(self.is_topic_published(topic)) -PKG = 'rosbridge_library' -NAME = 'test_advertise' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_advertise" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestAdvertise) - diff --git a/rosbridge_library/test/capabilities/test_call_service.py b/rosbridge_library/test/capabilities/test_call_service.py index d91f85f27..c5b903eed 100755 --- a/rosbridge_library/test/capabilities/test_call_service.py +++ b/rosbridge_library/test/capabilities/test_call_service.py @@ -11,11 +11,13 @@ from rosbridge_library.capabilities.call_service import CallService from rosbridge_library.protocol import Protocol -from rosbridge_library.protocol import InvalidArgumentException, MissingArgumentException +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, +) class TestCallService(unittest.TestCase): - def setUp(self): rospy.init_node("test_call_service") @@ -40,7 +42,9 @@ def test_call_service_works(self): proto = Protocol("test_call_service_works") s = CallService(proto) - msg = loads(dumps({"op": "call_service", "service": rospy.get_name() + "/get_loggers"})) + msg = loads( + dumps({"op": "call_service", "service": rospy.get_name() + "/get_loggers"}) + ) received = {"msg": None, "arrived": False} @@ -70,14 +74,22 @@ def cb(msg, cid=None): def test_call_service_fail(self): # Dummy service that instantly fails - service_server = rospy.Service("set_bool_fail", SetBool, - lambda req: None) + service_server = rospy.Service("set_bool_fail", SetBool, lambda req: None) proto = Protocol("test_call_service_fail") s = CallService(proto) - send_msg = loads(dumps({"op": "call_service", "service": rospy.get_name() + "/set_bool_fail", "args": '[ true ]'})) + send_msg = loads( + dumps( + { + "op": "call_service", + "service": rospy.get_name() + "/set_bool_fail", + "args": "[ true ]", + } + ) + ) received = {"msg": None, "arrived": False} + def cb(msg, cid=None): received["msg"] = msg received["arrived"] = True @@ -96,8 +108,7 @@ def cb(msg, cid=None): self.assertFalse(received["msg"]["result"]) -PKG = 'rosbridge_library' -NAME = 'test_call_service' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_call_service" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestCallService) - diff --git a/rosbridge_library/test/capabilities/test_publish.py b/rosbridge_library/test/capabilities/test_publish.py index e1e3c7f40..117eda458 100755 --- a/rosbridge_library/test/capabilities/test_publish.py +++ b/rosbridge_library/test/capabilities/test_publish.py @@ -5,7 +5,10 @@ from time import sleep from rosbridge_library.protocol import Protocol -from rosbridge_library.protocol import InvalidArgumentException, MissingArgumentException +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, +) from rosbridge_library.capabilities.publish import Publish from std_msgs.msg import String @@ -14,7 +17,6 @@ class TestAdvertise(unittest.TestCase): - def setUp(self): rospy.init_node("test_advertise") @@ -54,8 +56,7 @@ def cb(msg): self.assertEqual(received["msg"].data, msg["data"]) -PKG = 'rosbridge_library' -NAME = 'test_publish' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_publish" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestAdvertise) - diff --git a/rosbridge_library/test/capabilities/test_service_capabilities.py b/rosbridge_library/test/capabilities/test_service_capabilities.py index 8f3c0583c..26793aea6 100755 --- a/rosbridge_library/test/capabilities/test_service_capabilities.py +++ b/rosbridge_library/test/capabilities/test_service_capabilities.py @@ -10,7 +10,10 @@ from rosbridge_library.capabilities.call_service import CallService from rosbridge_library.capabilities.service_response import ServiceResponse from rosbridge_library.protocol import Protocol -from rosbridge_library.protocol import InvalidArgumentException, MissingArgumentException +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, +) class TestServiceCapabilities(unittest.TestCase): @@ -35,41 +38,52 @@ def mock_log(self, loglevel, message, _=None): def test_advertise_missing_arguments(self): advertise_msg = loads(dumps({"op": "advertise_service"})) - self.assertRaises(MissingArgumentException, - self.advertise.advertise_service, advertise_msg) + self.assertRaises( + MissingArgumentException, self.advertise.advertise_service, advertise_msg + ) def test_advertise_invalid_arguments(self): - advertise_msg = loads(dumps({"op": "advertise_service", - "type": 42, - "service": None})) - self.assertRaises(InvalidArgumentException, - self.advertise.advertise_service, advertise_msg) + advertise_msg = loads( + dumps({"op": "advertise_service", "type": 42, "service": None}) + ) + self.assertRaises( + InvalidArgumentException, self.advertise.advertise_service, advertise_msg + ) def test_response_missing_arguments(self): response_msg = loads(dumps({"op": "service_response"})) - self.assertRaises(MissingArgumentException, - self.response.service_response, response_msg) + self.assertRaises( + MissingArgumentException, self.response.service_response, response_msg + ) # this message has the optional fields, with correct types, but not the # required ones - response_msg = loads(dumps({"op": "service_response", - "id": "dummy_service", - "values": "none"})) - self.assertRaises(MissingArgumentException, - self.response.service_response, response_msg) + response_msg = loads( + dumps({"op": "service_response", "id": "dummy_service", "values": "none"}) + ) + self.assertRaises( + MissingArgumentException, self.response.service_response, response_msg + ) def test_response_invalid_arguments(self): - response_msg = loads(dumps({"op": "service_response", - "service": 5, - "result": "error"})) - self.assertRaises(InvalidArgumentException, - self.response.service_response, response_msg) + response_msg = loads( + dumps({"op": "service_response", "service": 5, "result": "error"}) + ) + self.assertRaises( + InvalidArgumentException, self.response.service_response, response_msg + ) def test_advertise_service(self): service_path = "/set_bool_1" - advertise_msg = loads(dumps({"op": "advertise_service", - "type": "std_srvs/SetBool", - "service": service_path})) + advertise_msg = loads( + dumps( + { + "op": "advertise_service", + "type": "std_srvs/SetBool", + "service": service_path, + } + ) + ) self.advertise.advertise_service(advertise_msg) # This throws an exception if the timeout is exceeded (i.e. the service @@ -78,26 +92,42 @@ def test_advertise_service(self): def test_call_advertised_service(self): service_path = "/set_bool_2" - advertise_msg = loads(dumps({"op": "advertise_service", - "type": "std_srvs/SetBool", - "service": service_path})) + advertise_msg = loads( + dumps( + { + "op": "advertise_service", + "type": "std_srvs/SetBool", + "service": service_path, + } + ) + ) self.advertise.advertise_service(advertise_msg) # Call the service via rosbridge because rospy.ServiceProxy.call() is # blocking call_service = CallService(self.proto) - call_service.call_service(loads(dumps({"op": "call_service", - "id": "foo", - "service": service_path, - "args": [True]}))) + call_service.call_service( + loads( + dumps( + { + "op": "call_service", + "id": "foo", + "service": service_path, + "args": [True], + } + ) + ) + ) loop_iterations = 0 while self.received_message is None: rospy.sleep(rospy.Duration(0.5)) loop_iterations += 1 if loop_iterations > 3: - self.fail("did not receive service call rosbridge message " - "after waiting 2 seconds") + self.fail( + "did not receive service call rosbridge message " + "after waiting 2 seconds" + ) self.assertFalse(self.received_message is None) self.assertTrue("op" in self.received_message) @@ -105,12 +135,17 @@ def test_call_advertised_service(self): self.assertTrue("id" in self.received_message) # Now send the response - response_msg = loads(dumps({"op": "service_response", - "service": service_path, - "id": self.received_message["id"], - "values": {"success": True, - "message": ""}, - "result": True})) + response_msg = loads( + dumps( + { + "op": "service_response", + "service": service_path, + "id": self.received_message["id"], + "values": {"success": True, "message": ""}, + "result": True, + } + ) + ) self.received_message = None self.response.service_response(response_msg) @@ -119,8 +154,10 @@ def test_call_advertised_service(self): rospy.sleep(rospy.Duration(0.5)) loop_iterations += 1 if loop_iterations > 3: - self.fail("did not receive service response rosbridge message " - "after waiting 2 seconds") + self.fail( + "did not receive service response rosbridge message " + "after waiting 2 seconds" + ) self.assertFalse(self.received_message is None) # Rosbridge should forward the response message to the "client" @@ -130,26 +167,42 @@ def test_call_advertised_service(self): def test_unadvertise_with_live_request(self): service_path = "/set_bool_3" - advertise_msg = loads(dumps({"op": "advertise_service", - "type": "std_srvs/SetBool", - "service": service_path})) + advertise_msg = loads( + dumps( + { + "op": "advertise_service", + "type": "std_srvs/SetBool", + "service": service_path, + } + ) + ) self.advertise.advertise_service(advertise_msg) # Call the service via rosbridge because rospy.ServiceProxy.call() is # blocking call_service = CallService(self.proto) - call_service.call_service(loads(dumps({"op": "call_service", - "id": "foo", - "service": service_path, - "args": [True]}))) + call_service.call_service( + loads( + dumps( + { + "op": "call_service", + "id": "foo", + "service": service_path, + "args": [True], + } + ) + ) + ) loop_iterations = 0 while self.received_message is None: rospy.sleep(rospy.Duration(0.5)) loop_iterations += 1 if loop_iterations > 3: - self.fail("did not receive service call rosbridge message " - "after waiting 2 seconds") + self.fail( + "did not receive service call rosbridge message " + "after waiting 2 seconds" + ) self.assertFalse(self.received_message is None) self.assertTrue("op" in self.received_message) @@ -157,8 +210,9 @@ def test_unadvertise_with_live_request(self): self.assertTrue("id" in self.received_message) # Now send the response - response_msg = loads(dumps({"op": "unadvertise_service", - "service": service_path})) + response_msg = loads( + dumps({"op": "unadvertise_service", "service": service_path}) + ) self.received_message = None self.unadvertise.unadvertise_service(response_msg) @@ -167,8 +221,10 @@ def test_unadvertise_with_live_request(self): rospy.sleep(rospy.Duration(0.5)) loop_iterations += 1 if loop_iterations > 3: - self.fail("did not receive service response rosbridge message " - "after waiting 2 seconds") + self.fail( + "did not receive service response rosbridge message " + "after waiting 2 seconds" + ) self.assertFalse(self.received_message is None) # Rosbridge should abort the existing service call with an error @@ -177,8 +233,8 @@ def test_unadvertise_with_live_request(self): self.assertFalse(self.received_message["result"]) -PKG = 'rosbridge_library' -NAME = 'test_service_capabilities' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_service_capabilities" +if __name__ == "__main__": rospy.init_node(NAME) rostest.rosrun(PKG, NAME, TestServiceCapabilities) diff --git a/rosbridge_library/test/capabilities/test_subscribe.py b/rosbridge_library/test/capabilities/test_subscribe.py index 59c5ef5c0..628536a3a 100755 --- a/rosbridge_library/test/capabilities/test_subscribe.py +++ b/rosbridge_library/test/capabilities/test_subscribe.py @@ -9,11 +9,13 @@ from rosbridge_library.capabilities import subscribe from rosbridge_library.protocol import Protocol -from rosbridge_library.protocol import InvalidArgumentException, MissingArgumentException +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, +) class TestSubscribe(unittest.TestCase): - def setUp(self): rospy.init_node("test_subscribe") @@ -21,8 +23,8 @@ def dummy_cb(self, msg): pass def test_update_params(self): - """ Adds a bunch of random clients to the subscription and sees whether - the correct parameters are chosen as the min """ + """Adds a bunch of random clients to the subscription and sees whether + the correct parameters are chosen as the min""" client_id = "client_test_update_params" topic = "/test_update_params" msg_type = "std_msgs/String" @@ -37,8 +39,9 @@ def test_update_params(self): for queue_length in range(min_queue_length, min_queue_length + 10): for frag_size in range(min_frag_size, min_frag_size + 10): sid = throttle_rate * 100 + queue_length * 10 + frag_size - subscription.subscribe(sid, msg_type, throttle_rate, - queue_length, frag_size) + subscription.subscribe( + sid, msg_type, throttle_rate, queue_length, frag_size + ) subscription.update_params() @@ -102,7 +105,9 @@ def send(outgoing): proto.send = send - sub.subscribe(loads(dumps({"op": "subscribe", "topic": topic, "type": msg_type}))) + sub.subscribe( + loads(dumps({"op": "subscribe", "topic": topic, "type": msg_type})) + ) p = rospy.Publisher(topic, String, queue_size=5) time.sleep(0.25) @@ -112,8 +117,7 @@ def send(outgoing): self.assertEqual(received["msg"]["msg"]["data"], msg.data) -PKG = 'rosbridge_library' -NAME = 'test_subscribe' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_subscribe" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestSubscribe) - diff --git a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py index 4cb95b45f..859f3c9e8 100755 --- a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py +++ b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py @@ -7,14 +7,14 @@ # these parameters should be changed to match the actual environment # # ############################################################################## -client_socket_timeout = 6 # seconds -max_msg_length = 2000000 # bytes +client_socket_timeout = 6 # seconds +max_msg_length = 2000000 # bytes -rosbridge_ip = "localhost" # hostname or ip -rosbridge_port = 9090 # port as integer +rosbridge_ip = "localhost" # hostname or ip +rosbridge_port = 9090 # port as integer -service_name = "nested_srv" # service name -#request_byte_count = 5000 +service_name = "nested_srv" # service name +# request_byte_count = 5000 receiving_fragment_size = 1000 receive_message_intervall = 0.0 @@ -23,18 +23,26 @@ # ############################################################################## + def request_service(): - service_request_object = { "op" : "call_service", # op-code for rosbridge - "service": "/"+service_name, # select service - "fragment_size": receiving_fragment_size, # optional: tells rosbridge to send fragments if message size is bigger than requested - "message_intervall": receive_message_intervall, - "args": { "pose": {"position": {"y": 0.0, "x": 0.0, "z": 0.0}, "orientation": {"y": 0.0, "x": 0.0, "z": 0.0, "w": 0.0}}} - #"count" : request_byte_count # count is the parameter for send_bytes as defined in srv-file (always put into args field!) - } + service_request_object = { + "op": "call_service", # op-code for rosbridge + "service": "/" + service_name, # select service + "fragment_size": receiving_fragment_size, # optional: tells rosbridge to send fragments if message size is bigger than requested + "message_intervall": receive_message_intervall, + "args": { + "pose": { + "position": {"y": 0.0, "x": 0.0, "z": 0.0}, + "orientation": {"y": 0.0, "x": 0.0, "z": 0.0, "w": 0.0}, + } + } + # "count" : request_byte_count # count is the parameter for send_bytes as defined in srv-file (always put into args field!) + } service_request = json.dumps(service_request_object) print("sending JSON-message to rosbridge:", service_request) sock.send(service_request) + # ############################################################################## @@ -42,22 +50,24 @@ def request_service(): # should not need to be changed (but could be improved ;) ) # # ############################################################################## try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge sock.settimeout(client_socket_timeout) sock.connect((rosbridge_ip, rosbridge_port)) - request_service() # send service_request + request_service() # send service_request incoming = None buffer = "" done = False result = None reconstructed = None - # should not need a loop (maximum wait can be set by client_socket_timeout), + # should not need a loop (maximum wait can be set by client_socket_timeout), # but since its for test/demonstration only .. leave it as it is for now while not done: try: - incoming = sock.recv(max_msg_length) # receive service_response from rosbridge + incoming = sock.recv( + max_msg_length + ) # receive service_response from rosbridge if buffer == "": buffer = incoming if incoming == "": @@ -66,61 +76,70 @@ def request_service(): break else: buffer = buffer + incoming - #print "buffer-length:", len(buffer) - try: # try to access service_request directly (not fragmented) + # print "buffer-length:", len(buffer) + try: # try to access service_request directly (not fragmented) data_object = json.loads(buffer) if data_object["op"] == "service_response": reconstructed = buffer done = True except Exception: - #print "direct access to JSON failed.." - #print(e) + # print "direct access to JSON failed.." + # print(e) pass - try: - #print "defragmenting incoming messages" - result_string = buffer.split("}{") # split buffer into fragments and re-fill curly brackets + try: + # print "defragmenting incoming messages" + result_string = buffer.split( + "}{" + ) # 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 + if fragment[len(fragment) - 1] != "}": fragment = fragment + "}" try: - result.append(json.loads(fragment)) # try to parse json from string, and append if successful + result.append( + json.loads(fragment) + ) # try to parse json from string, and append if successful except Exception: - #print(e) - #print result_string - raise # re-raise the last exception, allows to see and continue with processing of exception + # print(e) + # print result_string + raise # re-raise the last exception, allows to see and continue with processing of exception fragment_count = len(result) print("fragment_count:", fragment_count) announced = int(result[0]["total"]) - if fragment_count == announced: # if all fragments received --> sort and defragment + if ( + fragment_count == announced + ): # if all fragments received --> sort and defragment # sort fragments sorted_result = [None] * fragment_count unsorted_result = [] for fragment in result: unsorted_result.append(fragment) sorted_result[int(fragment["num"])] = fragment - reconstructed = '' + reconstructed = "" for fragment in sorted_result: reconstructed = reconstructed + fragment["data"] done = True except Exception: - #print(e) + # print(e) pass except Exception: - #print(e) + # print(e) pass - - returned_data = json.loads(reconstructed) # when service response is received --> access it (as defined in srv-file) + returned_data = json.loads( + reconstructed + ) # when service response is received --> access it (as defined in srv-file) if returned_data["values"] is None: print("response was None -> service was not available") else: print("received:") - print(returned_data) # ["values"]#["data"].decode('base64','strict') # decode values-field - + print( + returned_data + ) # ["values"]#["data"].decode('base64','strict') # decode values-field + except Exception as e: print("ERROR - could not receive service_response") print(e) diff --git a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py index 7d6dc494a..209e7d2e0 100755 --- a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py +++ b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py @@ -10,14 +10,14 @@ # these parameters should be changed to match the actual environment # # ############################################################################## -tcp_socket_timeout = 10 # seconds -max_msg_length = 20000 # bytes +tcp_socket_timeout = 10 # seconds +max_msg_length = 20000 # bytes -rosbridge_ip = "localhost" # hostname or ip -rosbridge_port = 9090 # port as integer +rosbridge_ip = "localhost" # hostname or ip +rosbridge_port = 9090 # port as integer -service_type = "rosbridge_library/TestNestedService" # make sure this matches an existing service type on rosbridge-server (in specified srv_module) -service_name = "nested_srv" # service name +service_type = "rosbridge_library/TestNestedService" # make sure this matches an existing service type on rosbridge-server (in specified srv_module) +service_name = "nested_srv" # service name send_fragment_size = 1000 # delay between sends to rosbridge is not needed anymore, if using my version of protocol (uses buffer to collect data from stream) @@ -32,34 +32,37 @@ # change this function to match whatever service should be provided # # ############################################################################## + def calculate_service_response(request): - request_object = json.loads(request) # parse string for service request - args = request_object["args"] # get parameter field (args) -# count = int(args["count"] ) # get parameter(s) as described in corresponding ROS srv-file -# -# message = "" # calculate service response -# for i in range(0,count): -# message += str(chr(randint(32,126))) -# if i% 100000 == 0: -# print count - i, "bytes left to generate" + request_object = json.loads(request) # parse string for service request + args = request_object["args"] # get parameter field (args) + # count = int(args["count"] ) # get parameter(s) as described in corresponding ROS srv-file + # + # message = "" # calculate service response + # for i in range(0,count): + # message += str(chr(randint(32,126))) + # if i% 100000 == 0: + # print count - i, "bytes left to generate" message = {"data": {"data": 42.0}} - + """ IMPORTANT! use base64 encoding to avoid JSON-parsing problems! --> use .decode("base64","strict") at client side """ - #message = message.encode('base64','strict') - service_response_data = message # service response (as defined in srv-file) - - response_object = { "op": "service_response", - "id": request_object["id"], - "data": service_response_data # put service response in "data"-field of response object (in this case it's twice "data", because response value is also named data (in srv-file) - } + # message = message.encode('base64','strict') + service_response_data = message # service response (as defined in srv-file) + + response_object = { + "op": "service_response", + "id": request_object["id"], + "data": service_response_data, # put service response in "data"-field of response object (in this case it's twice "data", because response value is also named data (in srv-file) + } response_message = json.dumps(response_object) return response_message + # ##################### service_calculation end ################################ @@ -69,30 +72,33 @@ def calculate_service_response(request): buffer = "" + def connect_tcp_socket(): - tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge + tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge tcp_sock.settimeout(tcp_socket_timeout) tcp_sock.connect((rosbridge_ip, rosbridge_port)) return tcp_sock -def advertise_service(): # advertise service - advertise_message_object = {"op":"advertise_service", - "type": service_type, - "service": service_name, - "fragment_size": receive_fragment_size, - "message_intervall": receive_message_intervall - } - advertise_message = json.dumps(advertise_message_object) + +def advertise_service(): # advertise service + advertise_message_object = { + "op": "advertise_service", + "type": service_type, + "service": service_name, + "fragment_size": receive_fragment_size, + "message_intervall": receive_message_intervall, + } + advertise_message = json.dumps(advertise_message_object) tcp_socket.send(str(advertise_message)) -def unadvertise_service(): # unadvertise service - unadvertise_message_object = {"op":"unadvertise_service", - "service": service_name - } - unadvertise_message = json.dumps(unadvertise_message_object) + +def unadvertise_service(): # unadvertise service + unadvertise_message_object = {"op": "unadvertise_service", "service": service_name} + unadvertise_message = json.dumps(unadvertise_message_object) tcp_socket.send(str(unadvertise_message)) -def wait_for_service_request(): # receive data from rosbridge + +def wait_for_service_request(): # receive data from rosbridge data = None global buffer @@ -100,53 +106,55 @@ def wait_for_service_request(): done = False global buffer while not done: - incoming = tcp_socket.recv(max_msg_length) # get data from socket - if incoming == '': + incoming = tcp_socket.recv(max_msg_length) # get data from socket + if incoming == "": print("connection closed by peer") sys.exit(1) - buffer = buffer + incoming # append data to buffer - try: # try to parse JSON from buffer + buffer = buffer + incoming # append data to buffer + try: # try to parse JSON from buffer data_object = json.loads(buffer) if data_object["op"] == "call_service": data = buffer done = True - return data # if parsing was successful --> return data string + return data # if parsing was successful --> return data string except Exception: - #print "direct_access error:" - #print(e) + # print "direct_access error:" + # print(e) pass - - #print "trying to defragment" - try: # opcode was not "call_service" -> try to defragment - result_string = buffer.split("}{") # split buffer into fragments and re-fill with curly brackets + + # print "trying to defragment" + try: # opcode was not "call_service" -> try to defragment + result_string = buffer.split( + "}{" + ) # split buffer into fragments and re-fill with curly brackets result = [] for fragment in result_string: if fragment[0] != "{": - fragment = "{"+fragment - if fragment[len(fragment)-1] != "}": + fragment = "{" + fragment + if fragment[len(fragment) - 1] != "}": fragment = fragment + "}" result.append(json.loads(fragment)) - try: # try to defragment when received all fragments + try: # try to defragment when received all fragments fragment_count = len(result) announced = int(result[0]["total"]) if fragment_count == announced: reconstructed = "" - sorted_result = [None] * fragment_count # sort fragments.. + sorted_result = [None] * fragment_count # sort fragments.. unsorted_result = [] for fragment in result: unsorted_result.append(fragment) sorted_result[int(fragment["num"])] = fragment - for fragment in sorted_result: # reconstruct from fragments + for fragment in sorted_result: # reconstruct from fragments reconstructed = reconstructed + fragment["data"] - #print "reconstructed", reconstructed - buffer = "" # empty buffer + # print "reconstructed", reconstructed + buffer = "" # empty buffer done = True print("reconstructed message from", len(result), "fragments") - #print reconstructed + # print reconstructed return reconstructed except Exception as e: print("not possible to defragment:", buffer) @@ -156,16 +164,20 @@ def wait_for_service_request(): print(e) pass except Exception: - #print "network-error(?):", e + # print "network-error(?):", e pass return data -def send_service_response(response): # send response to rosbridge + +def send_service_response(response): # send response to rosbridge tcp_socket.send(response) -def list_of_fragments(full_message, fragment_size): # create fragment messages for a huge message - message_id = randint(0,64000) # generate random message id - fragments = [] # generate list of data fragments + +def list_of_fragments( + full_message, fragment_size +): # create fragment messages for a huge message + message_id = randint(0, 64000) # generate random message id + fragments = [] # generate list of data fragments cursor = 0 while cursor < len(full_message): fragment_begin = cursor @@ -178,20 +190,32 @@ def list_of_fragments(full_message, fragment_size): fragment = full_message[fragment_begin:fragment_end] fragments.append(fragment) - fragmented_messages_list = [] # generate list of fragmented messages (including headers) + fragmented_messages_list = ( + [] + ) # generate list of fragmented messages (including headers) if len(fragments) > 1: - for count, fragment in enumerate(fragments): # iterate through list and have index counter - fragmented_message_object = {"op":"fragment", # create Python-object for each fragment message - "id": str(message_id), - "data": str(fragment), - "num": count, - "total": len(fragments) - } - fragmented_message = json.dumps(fragmented_message_object) # create JSON-object from python-object for each fragment message - fragmented_messages_list.append(fragmented_message) # append JSON-object to list of fragmented messages - else: # if only 1 fragment --> do not send as fragment, but as service_response + for count, fragment in enumerate( + fragments + ): # iterate through list and have index counter + fragmented_message_object = { + "op": "fragment", # create Python-object for each fragment message + "id": str(message_id), + "data": str(fragment), + "num": count, + "total": len(fragments), + } + fragmented_message = json.dumps( + fragmented_message_object + ) # create JSON-object from python-object for each fragment message + fragmented_messages_list.append( + fragmented_message + ) # append JSON-object to list of fragmented messages + else: # if only 1 fragment --> do not send as fragment, but as service_response fragmented_messages_list.append(str(fragment)) - return fragmented_messages_list # return list of 'ready-to-send' fragmented messages + return ( + fragmented_messages_list # return list of 'ready-to-send' fragmented messages + ) + # ##################### helper functions end ################################### @@ -200,35 +224,41 @@ def list_of_fragments(full_message, fragment_size): # should not need to be changed (but could be improved ) # # ############################################################################## -tcp_socket = connect_tcp_socket() # open tcp_socket -advertise_service() # advertise service in ROS (via rosbridge) +tcp_socket = connect_tcp_socket() # open tcp_socket +advertise_service() # advertise service in ROS (via rosbridge) print("service provider started and waiting for requests") -try: # allows to catch KeyboardInterrupt - while True: # loop forever (or until ctrl-c is pressed) +try: # allows to catch KeyboardInterrupt + while True: # loop forever (or until ctrl-c is pressed) data = None - try: # allows to catch any Exception (network, json, ..) - data = wait_for_service_request() # receive request from rosbridge - if data == '': # exit on empty string - break - elif data: # received service_request (or at least some data..) - response = calculate_service_response(data) # generate service_response - - print("response calculated, now splitting into fragments..") - fragment_list = list_of_fragments(response, send_fragment_size) # generate fragments to send to rosbridge - - print("sending", len(fragment_list), "messages as response") - for fragment in fragment_list: - #print "sending:" ,fragment - send_service_response(fragment) # send service_response to rosbridge (or fragments; just send any list entry) - time.sleep(send_fragment_delay) # (not needed if using patched rosbridge protocol.py) + try: # allows to catch any Exception (network, json, ..) + data = wait_for_service_request() # receive request from rosbridge + if data == "": # exit on empty string + break + elif data: # received service_request (or at least some data..) + response = calculate_service_response(data) # generate service_response + + print("response calculated, now splitting into fragments..") + fragment_list = list_of_fragments( + response, send_fragment_size + ) # generate fragments to send to rosbridge + + print("sending", len(fragment_list), "messages as response") + for fragment in fragment_list: + # print "sending:" ,fragment + send_service_response( + fragment + ) # send service_response to rosbridge (or fragments; just send any list entry) + time.sleep( + send_fragment_delay + ) # (not needed if using patched rosbridge protocol.py) except Exception as e: - print(e) - pass + print(e) + pass except KeyboardInterrupt: try: - unadvertise_service() # unadvertise service - tcp_socket.close() # close tcp_socket + unadvertise_service() # unadvertise service + tcp_socket.close() # close tcp_socket except Exception as e: print(e) - print("non-ros_service_server stopped because user pressed \"Ctrl-C\"") + print('non-ros_service_server stopped because user pressed "Ctrl-C"') diff --git a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py index 70fb29ee7..baddd7a00 100755 --- a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py +++ b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py @@ -7,14 +7,14 @@ # these parameters should be changed to match the actual environment # # ############################################################################## -client_socket_timeout = 6 # seconds -max_msg_length = 2000000 # bytes +client_socket_timeout = 6 # seconds +max_msg_length = 2000000 # bytes -rosbridge_ip = "localhost" # hostname or ip -rosbridge_port = 9090 # port as integer +rosbridge_ip = "localhost" # hostname or ip +rosbridge_port = 9090 # port as integer -service_name = "send_bytes" # service name -request_byte_count = 500000 # NOTE: receiving more than ~100.000 bytes without setting a fragment_size was not possible during testing. +service_name = "send_bytes" # service name +request_byte_count = 500000 # NOTE: receiving more than ~100.000 bytes without setting a fragment_size was not possible during testing. receiving_fragment_size = 1000 receive_message_intervall = 0.0 @@ -23,18 +23,22 @@ # ############################################################################## + def request_service(): - service_request_object = { "op" : "call_service", # op-code for rosbridge - "service": "/"+service_name, # select service - "fragment_size": receiving_fragment_size, # optional: tells rosbridge to send fragments if message size is bigger than requested - "message_intervall": receive_message_intervall, - "args": { "count" : request_byte_count # count is the parameter for send_bytes as defined in srv-file (always put into args field!) - } - } + service_request_object = { + "op": "call_service", # op-code for rosbridge + "service": "/" + service_name, # select service + "fragment_size": receiving_fragment_size, # optional: tells rosbridge to send fragments if message size is bigger than requested + "message_intervall": receive_message_intervall, + "args": { + "count": request_byte_count # count is the parameter for send_bytes as defined in srv-file (always put into args field!) + }, + } service_request = json.dumps(service_request_object) print("sending JSON-message to rosbridge:", service_request) sock.send(service_request) + # ############################################################################## @@ -42,11 +46,11 @@ def request_service(): # should not need to be changed (but could be improved ;) ) # # ############################################################################## try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge sock.settimeout(client_socket_timeout) sock.connect((rosbridge_ip, rosbridge_port)) - request_service() # send service_request + request_service() # send service_request incoming = None buffer = "" @@ -57,7 +61,9 @@ def request_service(): # but since its for test/demonstration only .. leave it as it is for now while not done: try: - incoming = sock.recv(max_msg_length) # receive service_response from rosbridge + incoming = sock.recv( + max_msg_length + ) # receive service_response from rosbridge if buffer == "": buffer = incoming if incoming == "": @@ -66,61 +72,70 @@ def request_service(): break else: buffer = buffer + incoming - #print "buffer-length:", len(buffer) - try: # try to access service_request directly (not fragmented) + # print "buffer-length:", len(buffer) + try: # try to access service_request directly (not fragmented) data_object = json.loads(buffer) if data_object["op"] == "service_response": reconstructed = buffer done = True except Exception: - #print "direct access to JSON failed.." - #print(e) + # print "direct access to JSON failed.." + # print(e) pass - try: - #print "defragmenting incoming messages" - result_string = buffer.split("}{") # split buffer into fragments and re-fill curly brackets + try: + # print "defragmenting incoming messages" + result_string = buffer.split( + "}{" + ) # 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 + if fragment[len(fragment) - 1] != "}": fragment = fragment + "}" try: - result.append(json.loads(fragment)) # try to parse json from string, and append if successful + result.append( + json.loads(fragment) + ) # try to parse json from string, and append if successful except Exception: - #print(e) - #print result_string - raise # re-raise the last exception, allows to see and continue with processing of exception + # print(e) + # print result_string + raise # re-raise the last exception, allows to see and continue with processing of exception fragment_count = len(result) print("fragment_count:", fragment_count) announced = int(result[0]["total"]) - if fragment_count == announced: # if all fragments received --> sort and defragment + if ( + fragment_count == announced + ): # if all fragments received --> sort and defragment # sort fragments sorted_result = [None] * fragment_count unsorted_result = [] for fragment in result: unsorted_result.append(fragment) sorted_result[int(fragment["num"])] = fragment - reconstructed = '' + reconstructed = "" for fragment in sorted_result: reconstructed = reconstructed + fragment["data"] done = True except Exception: - #print(e) + # print(e) pass except Exception: -# print(e) + # print(e) pass - - returned_data = json.loads(reconstructed) # when service response is received --> access it (as defined in srv-file) + returned_data = json.loads( + reconstructed + ) # when service response is received --> access it (as defined in srv-file) if returned_data["values"] is None: print("response was None -> service was not available") else: print("received:") - print(returned_data["values"]["data"].decode('base64','strict')) # decode values-field - + print( + returned_data["values"]["data"].decode("base64", "strict") + ) # decode values-field + except Exception as e: print("ERROR - could not receive service_response") print(e) diff --git a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py index 5d6b67256..0a058d6bf 100755 --- a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py +++ b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py @@ -10,14 +10,14 @@ # these parameters should be changed to match the actual environment # # ############################################################################## -tcp_socket_timeout = 10 # seconds -max_msg_length = 20000 # bytes +tcp_socket_timeout = 10 # seconds +max_msg_length = 20000 # bytes -rosbridge_ip = "localhost" # hostname or ip -rosbridge_port = 9090 # port as integer +rosbridge_ip = "localhost" # hostname or ip +rosbridge_port = 9090 # port as integer -service_type = "rosbridge_library/SendBytes" # make sure this matches an existing service type on rosbridge-server (in specified srv_module) -service_name = "send_bytes" # service name +service_type = "rosbridge_library/SendBytes" # make sure this matches an existing service type on rosbridge-server (in specified srv_module) +service_name = "send_bytes" # service name send_fragment_size = 1000 # delay between sends to rosbridge is not needed anymore, if using my version of @@ -33,17 +33,20 @@ # change this function to match whatever service should be provided # # ############################################################################## + def calculate_service_response(request): - request_object = json.loads(request) # parse string for service request - args = request_object["args"] # get parameter field (args) - count = int(args["count"] ) # get parameter(s) as described in corresponding ROS srv-file - + request_object = json.loads(request) # parse string for service request + args = request_object["args"] # get parameter field (args) + count = int( + args["count"] + ) # get parameter(s) as described in corresponding ROS srv-file + message = "" # calculate service response - for i in range(0,count): - #message += str(chr(randint(32,126))) - message+= str(chr(randint(32,126))) - if i% 100000 == 0: + for i in range(0, count): + # message += str(chr(randint(32,126))) + message += str(chr(randint(32, 126))) + if i % 100000 == 0: print(count - i, "bytes left to generate") """ @@ -51,19 +54,22 @@ def calculate_service_response(request): use base64 encoding to avoid JSON-parsing problems! --> use .decode("base64","strict") at client side """ - message = message.encode('base64','strict') - service_response_data = { "data": message} # service response (as defined in srv-file) - - response_object = { "op": "service_response", - "id": request_object["id"], - "service": service_name, - "values": service_response_data # put service response in "data"-field of response object (in this case it's twice "data", because response value is also named data (in srv-file) - } + message = message.encode("base64", "strict") + service_response_data = { + "data": message + } # service response (as defined in srv-file) + + response_object = { + "op": "service_response", + "id": request_object["id"], + "service": service_name, + "values": service_response_data, # put service response in "data"-field of response object (in this case it's twice "data", because response value is also named data (in srv-file) + } response_message = json.dumps(response_object) return response_message -# ##################### service_calculation end ################################ +# ##################### service_calculation end ################################ # ##################### helper functions / and variables begin ################# @@ -72,30 +78,33 @@ def calculate_service_response(request): buffer = "" + def connect_tcp_socket(): - tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge + tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge tcp_sock.settimeout(tcp_socket_timeout) tcp_sock.connect((rosbridge_ip, rosbridge_port)) return tcp_sock -def advertise_service(): # advertise service - advertise_message_object = {"op":"advertise_service", - "type": service_type, - "service": service_name, - "fragment_size": receive_fragment_size, - "message_intervall": receive_message_intervall - } - advertise_message = json.dumps(advertise_message_object) + +def advertise_service(): # advertise service + advertise_message_object = { + "op": "advertise_service", + "type": service_type, + "service": service_name, + "fragment_size": receive_fragment_size, + "message_intervall": receive_message_intervall, + } + advertise_message = json.dumps(advertise_message_object) tcp_socket.send(str(advertise_message)) -def unadvertise_service(): # unadvertise service - unadvertise_message_object = {"op":"unadvertise_service", - "service": service_name - } - unadvertise_message = json.dumps(unadvertise_message_object) + +def unadvertise_service(): # unadvertise service + unadvertise_message_object = {"op": "unadvertise_service", "service": service_name} + unadvertise_message = json.dumps(unadvertise_message_object) tcp_socket.send(str(unadvertise_message)) -def wait_for_service_request(): # receive data from rosbridge + +def wait_for_service_request(): # receive data from rosbridge data = None global buffer @@ -103,53 +112,55 @@ def wait_for_service_request(): done = False global buffer while not done: - incoming = tcp_socket.recv(max_msg_length) # get data from socket - if incoming == '': + incoming = tcp_socket.recv(max_msg_length) # get data from socket + if incoming == "": print("connection closed by peer") sys.exit(1) - buffer = buffer + incoming # append data to buffer - try: # try to parse JSON from buffer + buffer = buffer + incoming # append data to buffer + try: # try to parse JSON from buffer data_object = json.loads(buffer) if data_object["op"] == "call_service": data = buffer done = True - return data # if parsing was successful --> return data string + return data # if parsing was successful --> return data string except Exception: - #print "direct_access error:" - #print(e) + # print "direct_access error:" + # print(e) pass - - #print "trying to defragment" - try: # opcode was not "call_service" -> try to defragment - result_string = buffer.split("}{") # split buffer into fragments and re-fill with curly brackets + + # print "trying to defragment" + try: # opcode was not "call_service" -> try to defragment + result_string = buffer.split( + "}{" + ) # split buffer into fragments and re-fill with curly brackets result = [] for fragment in result_string: if fragment[0] != "{": - fragment = "{"+fragment - if fragment[len(fragment)-1] != "}": + fragment = "{" + fragment + if fragment[len(fragment) - 1] != "}": fragment = fragment + "}" result.append(json.loads(fragment)) - try: # try to defragment when received all fragments + try: # try to defragment when received all fragments fragment_count = len(result) announced = int(result[0]["total"]) if fragment_count == announced: reconstructed = "" - sorted_result = [None] * fragment_count # sort fragments.. + sorted_result = [None] * fragment_count # sort fragments.. unsorted_result = [] for fragment in result: unsorted_result.append(fragment) sorted_result[int(fragment["num"])] = fragment - for fragment in sorted_result: # reconstruct from fragments + for fragment in sorted_result: # reconstruct from fragments reconstructed = reconstructed + fragment["data"] - #print "reconstructed", reconstructed - buffer = "" # empty buffer + # print "reconstructed", reconstructed + buffer = "" # empty buffer done = True print("reconstructed message from", len(result), "fragments") - #print reconstructed + # print reconstructed return reconstructed except Exception as e: print("not possible to defragment:", buffer) @@ -159,16 +170,20 @@ def wait_for_service_request(): print(e) pass except Exception: - #print "network-error(?):", e + # print "network-error(?):", e pass return data -def send_service_response(response): # send response to rosbridge + +def send_service_response(response): # send response to rosbridge tcp_socket.send(response) -def list_of_fragments(full_message, fragment_size): # create fragment messages for a huge message - message_id = randint(0,64000) # generate random message id - fragments = [] # generate list of data fragments + +def list_of_fragments( + full_message, fragment_size +): # create fragment messages for a huge message + message_id = randint(0, 64000) # generate random message id + fragments = [] # generate list of data fragments cursor = 0 while cursor < len(full_message): fragment_begin = cursor @@ -181,20 +196,32 @@ def list_of_fragments(full_message, fragment_size): fragment = full_message[fragment_begin:fragment_end] fragments.append(fragment) - fragmented_messages_list = [] # generate list of fragmented messages (including headers) + fragmented_messages_list = ( + [] + ) # generate list of fragmented messages (including headers) if len(fragments) > 1: - for count, fragment in enumerate(fragments): # iterate through list and have index counter - fragmented_message_object = {"op":"fragment", # create Python-object for each fragment message - "id": str(message_id), - "data": str(fragment), - "num": count, - "total": len(fragments) - } - fragmented_message = json.dumps(fragmented_message_object) # create JSON-object from python-object for each fragment message - fragmented_messages_list.append(fragmented_message) # append JSON-object to list of fragmented messages - else: # if only 1 fragment --> do not send as fragment, but as service_response + for count, fragment in enumerate( + fragments + ): # iterate through list and have index counter + fragmented_message_object = { + "op": "fragment", # create Python-object for each fragment message + "id": str(message_id), + "data": str(fragment), + "num": count, + "total": len(fragments), + } + fragmented_message = json.dumps( + fragmented_message_object + ) # create JSON-object from python-object for each fragment message + fragmented_messages_list.append( + fragmented_message + ) # append JSON-object to list of fragmented messages + else: # if only 1 fragment --> do not send as fragment, but as service_response fragmented_messages_list.append(str(fragment)) - return fragmented_messages_list # return list of 'ready-to-send' fragmented messages + return ( + fragmented_messages_list # return list of 'ready-to-send' fragmented messages + ) + # ##################### helper functions end ################################### @@ -203,35 +230,41 @@ def list_of_fragments(full_message, fragment_size): # should not need to be changed (but could be improved ) # # ############################################################################## -tcp_socket = connect_tcp_socket() # open tcp_socket -advertise_service() # advertise service in ROS (via rosbridge) +tcp_socket = connect_tcp_socket() # open tcp_socket +advertise_service() # advertise service in ROS (via rosbridge) print("service provider started and waiting for requests") -try: # allows to catch KeyboardInterrupt - while True: # loop forever (or until ctrl-c is pressed) +try: # allows to catch KeyboardInterrupt + while True: # loop forever (or until ctrl-c is pressed) data = None - try: # allows to catch any Exception (network, json, ..) - data = wait_for_service_request() # receive request from rosbridge - if data == '': # exit on empty string - break - elif data: # received service_request (or at least some data..) - response = calculate_service_response(data) # generate service_response - - print("response calculated, now splitting into fragments..") - fragment_list = list_of_fragments(response, send_fragment_size) # generate fragments to send to rosbridge - - print("sending", len(fragment_list), "messages as response") - for fragment in fragment_list: - #print "sending:" ,fragment - send_service_response(fragment) # send service_response to rosbridge (or fragments; just send any list entry) - time.sleep(send_fragment_delay) # (not needed if using patched rosbridge protocol.py) + try: # allows to catch any Exception (network, json, ..) + data = wait_for_service_request() # receive request from rosbridge + if data == "": # exit on empty string + break + elif data: # received service_request (or at least some data..) + response = calculate_service_response(data) # generate service_response + + print("response calculated, now splitting into fragments..") + fragment_list = list_of_fragments( + response, send_fragment_size + ) # generate fragments to send to rosbridge + + print("sending", len(fragment_list), "messages as response") + for fragment in fragment_list: + # print "sending:" ,fragment + send_service_response( + fragment + ) # send service_response to rosbridge (or fragments; just send any list entry) + time.sleep( + send_fragment_delay + ) # (not needed if using patched rosbridge protocol.py) except Exception as e: - print(e) - pass + print(e) + pass except KeyboardInterrupt: try: - unadvertise_service() # unadvertise service - tcp_socket.close() # close tcp_socket + unadvertise_service() # unadvertise service + tcp_socket.close() # close tcp_socket except Exception as e: print(e) - print("non-ros_service_server stopped because user pressed \"Ctrl-C\"") + print('non-ros_service_server stopped because user pressed "Ctrl-C"') diff --git a/rosbridge_library/test/internal/publishers/test_multi_publisher.py b/rosbridge_library/test/internal/publishers/test_multi_publisher.py index 5a20c6e27..ead677ae2 100755 --- a/rosbridge_library/test/internal/publishers/test_multi_publisher.py +++ b/rosbridge_library/test/internal/publishers/test_multi_publisher.py @@ -12,7 +12,6 @@ class TestMultiPublisher(unittest.TestCase): - def setUp(self): rospy.init_node("test_multi_publisher") @@ -20,7 +19,7 @@ def is_topic_published(self, topicname): return topicname in dict(rospy.get_published_topics()).keys() def test_register_multipublisher(self): - """ Register a publisher on a clean topic with a good msg type """ + """Register a publisher on a clean topic with a good msg type""" topic = "/test_register_multipublisher" msg_type = "std_msgs/String" @@ -29,7 +28,7 @@ def test_register_multipublisher(self): self.assertTrue(self.is_topic_published(topic)) def test_unregister_multipublisher(self): - """ Register and unregister a publisher on a clean topic with a good msg type """ + """Register and unregister a publisher on a clean topic with a good msg type""" topic = "/test_unregister_multipublisher" msg_type = "std_msgs/String" @@ -40,7 +39,7 @@ def test_unregister_multipublisher(self): self.assertFalse(self.is_topic_published(topic)) def test_register_client(self): - """ Adds a publisher then removes it. """ + """Adds a publisher then removes it.""" topic = "/test_register_client" msg_type = "std_msgs/String" client_id = "client1" @@ -55,7 +54,7 @@ def test_register_client(self): self.assertFalse(p.has_clients()) def test_register_multiple_clients(self): - """ Adds multiple publishers then removes them. """ + """Adds multiple publishers then removes them.""" topic = "/test_register_multiple_clients" msg_type = "std_msgs/String" @@ -75,12 +74,19 @@ def test_register_multiple_clients(self): def test_verify_type(self): topic = "/test_verify_type" msg_type = "std_msgs/String" - othertypes = ["geometry_msgs/Pose", "actionlib_msgs/GoalStatus", - "geometry_msgs/WrenchStamped", "stereo_msgs/DisparityImage", - "nav_msgs/OccupancyGrid", "geometry_msgs/Point32", - "trajectory_msgs/JointTrajectoryPoint", "diagnostic_msgs/KeyValue", - "visualization_msgs/InteractiveMarkerUpdate", "nav_msgs/GridCells", - "sensor_msgs/PointCloud2"] + othertypes = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] p = MultiPublisher(topic, msg_type) p.verify_type(msg_type) @@ -88,12 +94,13 @@ def test_verify_type(self): self.assertRaises(TypeConflictException, p.verify_type, othertype) def test_publish(self): - """ Make sure that publishing works """ + """Make sure that publishing works""" topic = "/test_publish" msg_type = "std_msgs/String" msg = {"data": "why halo thar"} received = {"msg": None} + def cb(msg): received["msg"] = msg @@ -106,7 +113,7 @@ def cb(msg): self.assertEqual(received["msg"].data, msg["data"]) def test_bad_publish(self): - """ Make sure that bad publishing fails """ + """Make sure that bad publishing fails""" topic = "/test_publish" msg_type = "std_msgs/String" msg = {"data": 3} @@ -115,7 +122,7 @@ def test_bad_publish(self): self.assertRaises(FieldTypeMismatchException, p.publish, msg) -PKG = 'rosbridge_library' -NAME = 'test_multi_publisher' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_multi_publisher" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestMultiPublisher) diff --git a/rosbridge_library/test/internal/publishers/test_multi_unregistering.py b/rosbridge_library/test/internal/publishers/test_multi_unregistering.py index 1cd682683..6c892b7bc 100755 --- a/rosbridge_library/test/internal/publishers/test_multi_unregistering.py +++ b/rosbridge_library/test/internal/publishers/test_multi_unregistering.py @@ -10,17 +10,17 @@ class TestMultiUnregistering(unittest.TestCase): - def setUp(self): rospy.init_node("test_multi_unregistering") def test_publish_once(self): - """ Make sure that publishing works """ + """Make sure that publishing works""" topic = "/test_publish_once" msg_type = "std_msgs/String" msg = {"data": "why halo thar"} received = {"msg": None} + def cb(msg): received["msg"] = msg @@ -33,12 +33,13 @@ def cb(msg): self.assertEqual(received["msg"].data, msg["data"]) def test_publish_twice(self): - """ Make sure that publishing works """ + """Make sure that publishing works""" topic = "/test_publish_twice" msg_type = "std_msgs/String" msg = {"data": "why halo thar"} received = {"msg": None} + def cb(msg): received["msg"] = msg @@ -79,7 +80,7 @@ def cb(msg): self.assertEqual(received["msg"].data, msg["data"]) -PKG = 'rosbridge_library' -NAME = 'test_multi_unregistering' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_multi_unregistering" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestMultiUnregistering) diff --git a/rosbridge_library/test/internal/publishers/test_publisher_manager.py b/rosbridge_library/test/internal/publishers/test_publisher_manager.py index 325fdabef..82f9d7887 100755 --- a/rosbridge_library/test/internal/publishers/test_publisher_manager.py +++ b/rosbridge_library/test/internal/publishers/test_publisher_manager.py @@ -6,13 +6,15 @@ from time import sleep from rosbridge_library.internal.publishers import manager -from rosbridge_library.internal.topics import TopicNotEstablishedException, TypeConflictException +from rosbridge_library.internal.topics import ( + TopicNotEstablishedException, + TypeConflictException, +) from rosbridge_library.internal.message_conversion import FieldTypeMismatchException from std_msgs.msg import String class TestPublisherManager(unittest.TestCase): - def setUp(self): rospy.init_node("test_publisher_manager") manager.unregister_timeout = 1.0 @@ -21,7 +23,7 @@ def is_topic_published(self, topicname): return topicname in dict(rospy.get_published_topics()).keys() def test_register_publisher(self): - """ Register a publisher on a clean topic with a good msg type """ + """Register a publisher on a clean topic with a good msg type""" topic = "/test_register_publisher" msg_type = "std_msgs/String" client = "client_test_register_publisher" @@ -36,7 +38,7 @@ def test_register_publisher(self): self.assertTrue(topic in manager.unregister_timers) self.assertTrue(topic in manager._publishers) self.assertTrue(self.is_topic_published(topic)) - sleep(manager.unregister_timeout*1.1) + sleep(manager.unregister_timeout * 1.1) self.assertFalse(topic in manager._publishers) self.assertFalse(self.is_topic_published(topic)) self.assertFalse(topic in manager.unregister_timers) @@ -62,7 +64,7 @@ def test_register_publisher_multiclient(self): self.assertTrue(topic in manager.unregister_timers) self.assertTrue(topic in manager._publishers) self.assertTrue(self.is_topic_published(topic)) - sleep(manager.unregister_timeout*1.1) + sleep(manager.unregister_timeout * 1.1) self.assertFalse(topic in manager._publishers) self.assertFalse(self.is_topic_published(topic)) self.assertFalse(topic in manager.unregister_timers) @@ -79,7 +81,9 @@ def test_register_publisher_conflicting_types(self): self.assertTrue(topic in manager._publishers) self.assertTrue(self.is_topic_published(topic)) - self.assertRaises(TypeConflictException, manager.register, "client2", topic, msg_type_bad) + self.assertRaises( + TypeConflictException, manager.register, "client2", topic, msg_type_bad + ) def test_register_multiple_publishers(self): topic1 = "/test_register_multiple_publishers1" @@ -111,7 +115,7 @@ def test_register_multiple_publishers(self): manager.unregister(client, topic2) self.assertTrue(topic2 in manager.unregister_timers) self.assertTrue(self.is_topic_published(topic2)) - sleep(manager.unregister_timeout*1.1) + sleep(manager.unregister_timeout * 1.1) self.assertFalse(topic1 in manager._publishers) self.assertFalse(self.is_topic_published(topic1)) self.assertFalse(topic2 in manager._publishers) @@ -167,7 +171,7 @@ def test_register_multiple_notopictype(self): manager.unregister(client2, topic) self.assertTrue(topic in manager.unregister_timers) self.assertTrue(topic in manager._publishers) - sleep(manager.unregister_timeout*1.1) + sleep(manager.unregister_timeout * 1.1) self.assertFalse(topic in manager._publishers) self.assertFalse(topic in manager.unregister_timers) self.assertFalse(self.is_topic_published(topic)) @@ -179,10 +183,12 @@ def test_publish_not_registered(self): self.assertFalse(topic in manager._publishers) self.assertFalse(self.is_topic_published(topic)) - self.assertRaises(TopicNotEstablishedException, manager.publish, client, topic, msg) + self.assertRaises( + TopicNotEstablishedException, manager.publish, client, topic, msg + ) def test_publisher_manager_publish(self): - """ Make sure that publishing works """ + """Make sure that publishing works""" topic = "/test_publisher_manager_publish" msg = {"data": "test publisher manager publish"} client = "client_test_publisher_manager_publish" @@ -199,17 +205,19 @@ def cb(msg): self.assertEqual(received["msg"].data, msg["data"]) def test_publisher_manager_bad_publish(self): - """ Make sure that bad publishing fails """ + """Make sure that bad publishing fails""" topic = "/test_publisher_manager_bad_publish" client = "client_test_publisher_manager_bad_publish" msg_type = "std_msgs/String" msg = {"data": 3} manager.register(client, topic, msg_type) - self.assertRaises(FieldTypeMismatchException, manager.publish, client, topic, msg) + self.assertRaises( + FieldTypeMismatchException, manager.publish, client, topic, msg + ) -PKG = 'rosbridge_library' -NAME = 'test_publisher_manager' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_publisher_manager" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestPublisherManager) diff --git a/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py b/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py index 2dfd08875..dce75f4f2 100755 --- a/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py +++ b/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py @@ -12,7 +12,6 @@ class TestMultiSubscriber(unittest.TestCase): - def setUp(self): rospy.init_node("test_multi_subscriber") @@ -23,7 +22,7 @@ def is_topic_subscribed(self, topicname): return topicname in dict(Master("test_multi_subscriber").getSystemState()[1]) def test_register_multisubscriber(self): - """ Register a subscriber on a clean topic with a good msg type """ + """Register a subscriber on a clean topic with a good msg type""" topic = "/test_register_multisubscriber" msg_type = "std_msgs/String" @@ -32,7 +31,7 @@ def test_register_multisubscriber(self): self.assertTrue(self.is_topic_subscribed(topic)) def test_unregister_multisubscriber(self): - """ Register and unregister a subscriber on a clean topic with a good msg type """ + """Register and unregister a subscriber on a clean topic with a good msg type""" topic = "/test_unregister_multisubscriber" msg_type = "std_msgs/String" @@ -45,12 +44,19 @@ def test_unregister_multisubscriber(self): def test_verify_type(self): topic = "/test_verify_type" msg_type = "std_msgs/String" - othertypes = ["geometry_msgs/Pose", "actionlib_msgs/GoalStatus", - "geometry_msgs/WrenchStamped", "stereo_msgs/DisparityImage", - "nav_msgs/OccupancyGrid", "geometry_msgs/Point32", - "trajectory_msgs/JointTrajectoryPoint", "diagnostic_msgs/KeyValue", - "visualization_msgs/InteractiveMarkerUpdate", "nav_msgs/GridCells", - "sensor_msgs/PointCloud2"] + othertypes = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] s = MultiSubscriber(topic, msg_type) s.verify_type(msg_type) @@ -178,7 +184,7 @@ def cb2(msg): self.assertEqual(msg.data, received["msg2"]["data"]) -PKG = 'rosbridge_library' -NAME = 'test_multi_subscriber' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_multi_subscriber" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestMultiSubscriber) diff --git a/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py b/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py index 1e499f04f..16c36ec82 100755 --- a/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py +++ b/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py @@ -7,12 +7,14 @@ from time import sleep from rosbridge_library.internal.subscribers import manager -from rosbridge_library.internal.topics import TopicNotEstablishedException, TypeConflictException +from rosbridge_library.internal.topics import ( + TopicNotEstablishedException, + TypeConflictException, +) from std_msgs.msg import String class TestSubscriberManager(unittest.TestCase): - def setUp(self): rospy.init_node("test_subscriber_manager") @@ -23,7 +25,7 @@ def is_topic_subscribed(self, topicname): return topicname in dict(Master("test_subscriber_manager").getSystemState()[1]) def test_subscribe(self): - """ Register a publisher on a clean topic with a good msg type """ + """Register a publisher on a clean topic with a good msg type""" topic = "/test_subscribe" msg_type = "std_msgs/String" client = "client_test_subscribe" @@ -71,7 +73,14 @@ def test_register_publisher_conflicting_types(self): self.assertTrue(topic in manager._subscribers) self.assertTrue(self.is_topic_subscribed(topic)) - self.assertRaises(TypeConflictException, manager.subscribe, "client2", topic, None, msg_type_bad) + self.assertRaises( + TypeConflictException, + manager.subscribe, + "client2", + topic, + None, + msg_type_bad, + ) def test_register_multiple_publishers(self): topic1 = "/test_register_multiple_publishers1" @@ -112,7 +121,9 @@ def test_register_no_msgtype(self): self.assertFalse(topic in manager._subscribers) self.assertFalse(self.is_topic_subscribed(topic)) - self.assertRaises(TopicNotEstablishedException, manager.subscribe, client, topic, None) + self.assertRaises( + TopicNotEstablishedException, manager.subscribe, client, topic, None + ) def test_register_infer_topictype(self): topic = "/test_register_infer_topictype" @@ -159,7 +170,9 @@ def test_subscribe_not_registered(self): self.assertFalse(topic in manager._subscribers) self.assertFalse(self.is_topic_subscribed(topic)) - self.assertRaises(TopicNotEstablishedException, manager.subscribe, client, topic, None) + self.assertRaises( + TopicNotEstablishedException, manager.subscribe, client, topic, None + ) def test_publisher_manager_publish(self): topic = "/test_publisher_manager_publish" @@ -182,7 +195,7 @@ def cb(msg): self.assertEqual(msg.data, received["msg"]["data"]) -PKG = 'rosbridge_library' -NAME = 'test_subscriber_manager' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_subscriber_manager" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestSubscriberManager) diff --git a/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py b/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py index 8ee61e149..a1f26a5dd 100755 --- a/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py +++ b/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py @@ -8,7 +8,6 @@ class TestMessageHandlers(unittest.TestCase): - def setUp(self): rospy.init_node("test_message_handlers") @@ -20,11 +19,15 @@ def test_default_message_handler(self): self.help_test_default(handler) def test_throttle_message_handler(self): - handler = subscribe.ThrottleMessageHandler(subscribe.MessageHandler(None, self.dummy_cb)) + handler = subscribe.ThrottleMessageHandler( + subscribe.MessageHandler(None, self.dummy_cb) + ) self.help_test_throttle(handler, 50) def test_queue_message_handler_passes_msgs(self): - handler = subscribe.QueueMessageHandler(subscribe.MessageHandler(None, self.dummy_cb)) + handler = subscribe.QueueMessageHandler( + subscribe.MessageHandler(None, self.dummy_cb) + ) self.help_test_queue(handler, 1000) handler.finish() @@ -93,6 +96,7 @@ def help_test_default(self, handler): def cb(msg): received["msg"] = msg + handler.publish = cb self.assertTrue(handler.time_remaining() == 0) @@ -106,8 +110,10 @@ def cb(msg): self.assertEqual(handler.time_remaining(), 0) received = {"msgs": []} + def cb(msg): received["msgs"].append(msg) + handler.publish = cb xs = list(range(10000)) for x in xs: @@ -140,6 +146,7 @@ def cb(msg): time.sleep(2.0 * handler.throttle_rate) received = {"msgs": []} + def cb(msg): received["msgs"].append(msg) @@ -210,7 +217,7 @@ def cb(msg): return handler -# Test that each transition works and is stable + # Test that each transition works and is stable def test_transitions(self): # MessageHandler.transition is stable handler = subscribe.MessageHandler(None, self.dummy_cb) @@ -331,7 +338,7 @@ def test_transition_functionality(self): # handler = self.help_test_throttle(handler, 50) -PKG = 'rosbridge_library' -NAME = 'test_message_handlers' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_message_handlers" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestMessageHandlers) diff --git a/rosbridge_library/test/internal/test_cbor_conversion.py b/rosbridge_library/test/internal/test_cbor_conversion.py index 6241aab67..05271356c 100755 --- a/rosbridge_library/test/internal/test_cbor_conversion.py +++ b/rosbridge_library/test/internal/test_cbor_conversion.py @@ -3,7 +3,10 @@ import unittest import struct -from rosbridge_library.internal.cbor_conversion import extract_cbor_values, TAGGED_ARRAY_FORMATS +from rosbridge_library.internal.cbor_conversion import ( + extract_cbor_values, + TAGGED_ARRAY_FORMATS, +) try: from cbor import Tag @@ -11,15 +14,32 @@ from rosbridge_library.util.cbor import Tag from std_msgs.msg import ( - Bool, String, - Int8, Int16, Int32, Int64, - UInt8, UInt16, UInt32, UInt64, - Float32, Float64, - Int8MultiArray, Int16MultiArray, Int32MultiArray, Int64MultiArray, - UInt8MultiArray, UInt16MultiArray, UInt32MultiArray, UInt64MultiArray, - Float32MultiArray, Float64MultiArray, - Time, Duration, - MultiArrayLayout, MultiArrayDimension, + Bool, + String, + Int8, + Int16, + Int32, + Int64, + UInt8, + UInt16, + UInt32, + UInt64, + Float32, + Float64, + Int8MultiArray, + Int16MultiArray, + Int32MultiArray, + Int64MultiArray, + UInt8MultiArray, + UInt16MultiArray, + UInt32MultiArray, + UInt64MultiArray, + Float32MultiArray, + Float64MultiArray, + Time, + Duration, + MultiArrayLayout, + MultiArrayDimension, ) @@ -28,107 +48,121 @@ def test_string(self): msg = String(data="foo") extracted = extract_cbor_values(msg) - self.assertEqual(extracted['data'], msg.data) - self.assertEqual(type(extracted['data']), str) + self.assertEqual(extracted["data"], msg.data) + self.assertEqual(type(extracted["data"]), str) def test_bool(self): for val in [True, False]: msg = Bool(data=val) extracted = extract_cbor_values(msg) - self.assertEqual(extracted['data'], msg.data, f'val={val}') - self.assertEqual(type(extracted['data']), bool, f'val={val}') + self.assertEqual(extracted["data"], msg.data, f"val={val}") + self.assertEqual(type(extracted["data"]), bool, f"val={val}") def test_numbers(self): for msg_type in [Int8, Int16, Int32, Int64]: msg = msg_type(data=-5) extracted = extract_cbor_values(msg) - self.assertEqual(extracted['data'], msg.data, f'type={msg_type}') - self.assertEqual(type(extracted['data']), int, f'type={msg_type}') + self.assertEqual(extracted["data"], msg.data, f"type={msg_type}") + self.assertEqual(type(extracted["data"]), int, f"type={msg_type}") for msg_type in [UInt8, UInt16, UInt32, UInt64]: msg = msg_type(data=5) extracted = extract_cbor_values(msg) - self.assertEqual(extracted['data'], msg.data, f'type={msg_type}') - self.assertEqual(type(extracted['data']), int, f'type={msg_type}') + self.assertEqual(extracted["data"], msg.data, f"type={msg_type}") + self.assertEqual(type(extracted["data"]), int, f"type={msg_type}") for msg_type in [Float32, Float64]: msg = msg_type(data=2.3) extracted = extract_cbor_values(msg) - self.assertEqual(extracted['data'], msg.data, f'type={msg_type}') - self.assertEqual(type(extracted['data']), float, f'type={msg_type}') + self.assertEqual(extracted["data"], msg.data, f"type={msg_type}") + self.assertEqual(type(extracted["data"]), float, f"type={msg_type}") def test_time(self): for msg_type in [Time, Duration]: msg = msg_type() extracted = extract_cbor_values(msg) - self.assertEqual(extracted['data']['secs'], msg.data.secs, f'type={msg_type}') - self.assertEqual(extracted['data']['nsecs'], msg.data.nsecs, f'type={msg_type}') - self.assertEqual(type(extracted['data']['secs']), int, f'type={msg_type}') - self.assertEqual(type(extracted['data']['nsecs']), int, f'type={msg_type}') + self.assertEqual( + extracted["data"]["secs"], msg.data.secs, f"type={msg_type}" + ) + self.assertEqual( + extracted["data"]["nsecs"], msg.data.nsecs, f"type={msg_type}" + ) + self.assertEqual(type(extracted["data"]["secs"]), int, f"type={msg_type}") + self.assertEqual(type(extracted["data"]["nsecs"]), int, f"type={msg_type}") def test_byte_array(self): msg = UInt8MultiArray(data=[0, 1, 2]) extracted = extract_cbor_values(msg) - data = extracted['data'] + data = extracted["data"] self.assertEqual(type(data), bytes) for i, val in enumerate(msg.data): self.assertEqual(data[i], val) def test_numeric_array(self): - for msg_type in [Int8MultiArray, Int16MultiArray, Int32MultiArray, Int64MultiArray, - UInt16MultiArray, UInt32MultiArray, UInt64MultiArray, - Float32MultiArray, Float64MultiArray]: + for msg_type in [ + Int8MultiArray, + Int16MultiArray, + Int32MultiArray, + Int64MultiArray, + UInt16MultiArray, + UInt32MultiArray, + UInt64MultiArray, + Float32MultiArray, + Float64MultiArray, + ]: msg = msg_type(data=[0, 1, 2]) extracted = extract_cbor_values(msg) - tag = extracted['data'] - self.assertEqual(type(tag), Tag, f'type={msg_type}') - self.assertEqual(type(tag.value), bytes, f'type={msg_type}') + tag = extracted["data"] + self.assertEqual(type(tag), Tag, f"type={msg_type}") + self.assertEqual(type(tag.value), bytes, f"type={msg_type}") # This is as consistent as the message defs.. array_type = msg._slot_types[1] expected_tag = TAGGED_ARRAY_FORMATS[array_type][0] - self.assertEqual(tag.tag, expected_tag, f'type={msg_type}') + self.assertEqual(tag.tag, expected_tag, f"type={msg_type}") fmt = TAGGED_ARRAY_FORMATS[array_type][1] fmt_to_length = fmt.format(len(msg.data)) unpacked = list(struct.unpack(fmt_to_length, tag.value)) - self.assertEqual(unpacked, msg.data, f'type={msg_type}') + self.assertEqual(unpacked, msg.data, f"type={msg_type}") def test_nested_messages(self): - msg = UInt8MultiArray(layout=MultiArrayLayout( - data_offset=5, - dim=[ - MultiArrayDimension( - label="foo", - size=4, - stride=4, - ), - MultiArrayDimension( - label="bar", - size=8, - stride=8, - ), - ] - )) + msg = UInt8MultiArray( + layout=MultiArrayLayout( + data_offset=5, + dim=[ + MultiArrayDimension( + label="foo", + size=4, + stride=4, + ), + MultiArrayDimension( + label="bar", + size=8, + stride=8, + ), + ], + ) + ) extracted = extract_cbor_values(msg) - ex_layout = extracted['layout'] + ex_layout = extracted["layout"] self.assertEqual(type(ex_layout), dict) - self.assertEqual(ex_layout['data_offset'], msg.layout.data_offset) - self.assertEqual(len(ex_layout['dim']), len(msg.layout.dim)) + self.assertEqual(ex_layout["data_offset"], msg.layout.data_offset) + self.assertEqual(len(ex_layout["dim"]), len(msg.layout.dim)) for i, val in enumerate(msg.layout.dim): - self.assertEqual(ex_layout['dim'][i]['label'], val.label) - self.assertEqual(ex_layout['dim'][i]['size'], val.size) - self.assertEqual(ex_layout['dim'][i]['stride'], val.stride) + self.assertEqual(ex_layout["dim"][i]["label"], val.label) + self.assertEqual(ex_layout["dim"][i]["size"], val.size) + self.assertEqual(ex_layout["dim"][i]["stride"], val.stride) def test_unicode_keys(self): msg = String(data="foo") @@ -139,7 +173,7 @@ def test_unicode_keys(self): self.assertEqual(type(key), str) -PKG = 'rosbridge_library' -NAME = 'test_cbor_conversion' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_cbor_conversion" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestCBORConversion) diff --git a/rosbridge_library/test/internal/test_compression.py b/rosbridge_library/test/internal/test_compression.py index b2ec7fc8e..36a4f5608 100755 --- a/rosbridge_library/test/internal/test_compression.py +++ b/rosbridge_library/test/internal/test_compression.py @@ -7,7 +7,6 @@ class TestCompression(unittest.TestCase): - def setUp(self): rospy.init_node("test_compression") @@ -25,8 +24,8 @@ def test_compress_decompress(self): decoded = pngcompression.decode(encoded) self.assertEqual(string, decoded) -PKG = 'rosbridge_library' -NAME = 'test_compression' -if __name__ == '__main__': - rostest.unitrun(PKG, NAME, TestCompression) +PKG = "rosbridge_library" +NAME = "test_compression" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestCompression) diff --git a/rosbridge_library/test/internal/test_message_conversion.py b/rosbridge_library/test/internal/test_message_conversion.py index 7da84d2be..54d8dbeca 100755 --- a/rosbridge_library/test/internal/test_message_conversion.py +++ b/rosbridge_library/test/internal/test_message_conversion.py @@ -12,13 +12,12 @@ class TestMessageConversion(unittest.TestCase): - def setUp(self): rospy.init_node("test_message_conversion") def validate_instance(self, inst1): - """ Serializes and deserializes the inst to typecheck and ensure that - instances are correct """ + """Serializes and deserializes the inst to typecheck and ensure that + instances are correct""" inst1._check_types() buff = BytesIO() inst1.serialize(buff) @@ -92,10 +91,12 @@ def test_float_primitives(self): c._to_inst(msg, rostype, rostype) def test_float_special_cases(self): - for msg in [1e9999999, -1e9999999, float('nan')]: + for msg in [1e9999999, -1e9999999, float("nan")]: for rostype in ["float32", "float64"]: self.assertEqual(c._from_inst(msg, rostype), None) - self.assertEqual(dumps({"data":c._from_inst(msg, rostype)}), "{\"data\": null}") + self.assertEqual( + dumps({"data": c._from_inst(msg, rostype)}), '{"data": null}' + ) def test_signed_int_base_msgs(self): int8s = range(-127, 128) @@ -120,15 +121,21 @@ def test_signed_int_base_msgs(self): self.do_primitive_test(int32, "std_msgs/Int64") self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Byte") self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Int8") - self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Int16") + self.assertRaises( + Exception, self.do_primitive_test, int32, "std_msgs/Int16" + ) int64s = [-9223372036854775807, 9223372036854775807] for int64 in int64s: self.do_primitive_test(int64, "std_msgs/Int64") self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Byte") self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Int8") - self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Int16") - self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Int32") + self.assertRaises( + Exception, self.do_primitive_test, int64, "std_msgs/Int16" + ) + self.assertRaises( + Exception, self.do_primitive_test, int64, "std_msgs/Int32" + ) def test_unsigned_int_base_msgs(self): int8s = range(0, 256) @@ -145,24 +152,40 @@ def test_unsigned_int_base_msgs(self): self.do_primitive_test(int16, "std_msgs/UInt32") self.do_primitive_test(int16, "std_msgs/UInt64") self.assertRaises(Exception, self.do_primitive_test, int16, "std_msgs/Char") - self.assertRaises(Exception, self.do_primitive_test, int16, "std_msgs/UInt8") + self.assertRaises( + Exception, self.do_primitive_test, int16, "std_msgs/UInt8" + ) int32s = [2147483647, 2147483648, 4294967295] for int32 in int32s: self.do_primitive_test(int32, "std_msgs/UInt32") self.do_primitive_test(int32, "std_msgs/UInt64") self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Char") - self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/UInt8") - self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/UInt16") - - int64s = [4294967296, 9223372036854775807, 9223372036854775808, - 18446744073709551615] + self.assertRaises( + Exception, self.do_primitive_test, int32, "std_msgs/UInt8" + ) + self.assertRaises( + Exception, self.do_primitive_test, int32, "std_msgs/UInt16" + ) + + int64s = [ + 4294967296, + 9223372036854775807, + 9223372036854775808, + 18446744073709551615, + ] for int64 in int64s: self.do_primitive_test(int64, "std_msgs/UInt64") self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Char") - self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/UInt8") - self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/UInt16") - self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/UInt32") + self.assertRaises( + Exception, self.do_primitive_test, int64, "std_msgs/UInt8" + ) + self.assertRaises( + Exception, self.do_primitive_test, int64, "std_msgs/UInt16" + ) + self.assertRaises( + Exception, self.do_primitive_test, int64, "std_msgs/UInt32" + ) def test_bool_base_msg(self): self.do_primitive_test(True, "std_msgs/Bool") @@ -204,7 +227,11 @@ def test_duration_msg(self): self.do_test(msg, "rosbridge_library/TestDurationArray") def test_header_msg(self): - msg = {"seq": 5, "stamp": {"secs": 12347, "nsecs": 322304}, "frame_id": "2394dnfnlcx;v[p234j]"} + msg = { + "seq": 5, + "stamp": {"secs": 12347, "nsecs": 322304}, + "frame_id": "2394dnfnlcx;v[p234j]", + } self.do_test(msg, "std_msgs/Header") msg = {"header": msg} @@ -217,12 +244,20 @@ def test_header_msg(self): self.do_test(msg, "rosbridge_library/TestHeaderArray") def test_assorted_msgs(self): - assortedmsgs = ["geometry_msgs/Pose", "actionlib_msgs/GoalStatus", - "geometry_msgs/WrenchStamped", "stereo_msgs/DisparityImage", - "nav_msgs/OccupancyGrid", "geometry_msgs/Point32", "std_msgs/String", - "trajectory_msgs/JointTrajectoryPoint", "diagnostic_msgs/KeyValue", - "visualization_msgs/InteractiveMarkerUpdate", "nav_msgs/GridCells", - "sensor_msgs/PointCloud2"] + assortedmsgs = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "std_msgs/String", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] for rostype in assortedmsgs: inst = ros_loader.get_message_instance(rostype) msg = c.extract_values(inst) @@ -249,7 +284,7 @@ def test_int8_msg(rostype, data): str_int8s = bytes(bytearray(int8s)) - b64str_int8s = standard_b64encode(str_int8s).decode('ascii') + b64str_int8s = standard_b64encode(str_int8s).decode("ascii") ret = test_int8_msg(rostype, b64str_int8s) self.assertEqual(ret, str_int8s) @@ -262,12 +297,12 @@ def test_int8_msg(rostype, data): str_int8s = bytes(bytearray(int8s)) - b64str_int8s = standard_b64encode(str_int8s).decode('ascii') + b64str_int8s = standard_b64encode(str_int8s).decode("ascii") ret = test_int8_msg(rostype, b64str_int8s) self.assertEqual(ret, str_int8s) -PKG = 'rosbridge_library' -NAME = 'test_message_conversion' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_message_conversion" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestMessageConversion) diff --git a/rosbridge_library/test/internal/test_outgoing_message.py b/rosbridge_library/test/internal/test_outgoing_message.py index 4795435cb..66caa4c9e 100755 --- a/rosbridge_library/test/internal/test_outgoing_message.py +++ b/rosbridge_library/test/internal/test_outgoing_message.py @@ -13,7 +13,7 @@ def test_json_values(self): outgoing = OutgoingMessage(msg) result = outgoing.get_json_values() - self.assertEqual(result['data'], msg.data) + self.assertEqual(result["data"], msg.data) again = outgoing.get_json_values() self.assertTrue(result is again) @@ -23,13 +23,13 @@ def test_cbor_values(self): outgoing = OutgoingMessage(msg) result = outgoing.get_cbor_values() - self.assertEqual(result['data'], msg.data) + self.assertEqual(result["data"], msg.data) again = outgoing.get_cbor_values() self.assertTrue(result is again) -PKG = 'rosbridge_library' -NAME = 'test_outgoing_message' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_outgoing_message" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestOutgoingMessage) diff --git a/rosbridge_library/test/internal/test_ros_loader.py b/rosbridge_library/test/internal/test_ros_loader.py index 26ccb9cd6..b63f9bcf9 100755 --- a/rosbridge_library/test/internal/test_ros_loader.py +++ b/rosbridge_library/test/internal/test_ros_loader.py @@ -7,42 +7,90 @@ class TestROSLoader(unittest.TestCase): - def setUp(self): rospy.init_node("test_ros_loader") def test_bad_msgnames(self): - bad = ["", "/", "//", "///", "////", "/////", "bad", "stillbad", - "not/better/still", "not//better//still", "not///better///still", - "better/", "better//", "better///", "/better", "//better", "///better", - r"this\isbad", "\\"] + bad = [ + "", + "/", + "//", + "///", + "////", + "/////", + "bad", + "stillbad", + "not/better/still", + "not//better//still", + "not///better///still", + "better/", + "better//", + "better///", + "/better", + "//better", + "///better", + r"this\isbad", + "\\", + ] for x in bad: - self.assertRaises(ros_loader.InvalidTypeStringException, - ros_loader.get_message_class, x) - self.assertRaises(ros_loader.InvalidTypeStringException, - ros_loader.get_message_instance, x) + self.assertRaises( + ros_loader.InvalidTypeStringException, ros_loader.get_message_class, x + ) + self.assertRaises( + ros_loader.InvalidTypeStringException, + ros_loader.get_message_instance, + x, + ) def test_irregular_msgnames(self): - irregular = ["std_msgs//String", "//std_msgs/String", - "/std_msgs//String", "/std_msgs/String", "//std_msgs//String", - "/std_msgs/String/", "//std_msgs//String//", "std_msgs/String/", - "std_msgs//String//"] + irregular = [ + "std_msgs//String", + "//std_msgs/String", + "/std_msgs//String", + "/std_msgs/String", + "//std_msgs//String", + "/std_msgs/String/", + "//std_msgs//String//", + "std_msgs/String/", + "std_msgs//String//", + ] for x in irregular: self.assertNotEqual(ros_loader.get_message_class(x), None) self.assertNotEqual(ros_loader.get_message_instance(x), None) def test_std_msgnames(self): - stdmsgs = ["std_msgs/Bool", "std_msgs/Byte", "std_msgs/ByteMultiArray", - "std_msgs/ColorRGBA", "std_msgs/Duration", "std_msgs/Empty", - "std_msgs/Float32", "std_msgs/Float32MultiArray", "std_msgs/Float64", - "std_msgs/Header", "std_msgs/Int16", "std_msgs/Int16MultiArray", - "std_msgs/Int32", "std_msgs/Int32MultiArray", "std_msgs/Int64", - "std_msgs/Int64MultiArray", "std_msgs/Int8", "std_msgs/Int8MultiArray", - "std_msgs/MultiArrayDimension", "std_msgs/MultiArrayLayout", - "std_msgs/String", "std_msgs/Time", "std_msgs/UInt16", - "std_msgs/UInt16MultiArray", "std_msgs/UInt32MultiArray", - "std_msgs/UInt64MultiArray", "std_msgs/UInt32", "std_msgs/UInt64", - "std_msgs/UInt8", "std_msgs/UInt8MultiArray"] + stdmsgs = [ + "std_msgs/Bool", + "std_msgs/Byte", + "std_msgs/ByteMultiArray", + "std_msgs/ColorRGBA", + "std_msgs/Duration", + "std_msgs/Empty", + "std_msgs/Float32", + "std_msgs/Float32MultiArray", + "std_msgs/Float64", + "std_msgs/Header", + "std_msgs/Int16", + "std_msgs/Int16MultiArray", + "std_msgs/Int32", + "std_msgs/Int32MultiArray", + "std_msgs/Int64", + "std_msgs/Int64MultiArray", + "std_msgs/Int8", + "std_msgs/Int8MultiArray", + "std_msgs/MultiArrayDimension", + "std_msgs/MultiArrayLayout", + "std_msgs/String", + "std_msgs/Time", + "std_msgs/UInt16", + "std_msgs/UInt16MultiArray", + "std_msgs/UInt32MultiArray", + "std_msgs/UInt64MultiArray", + "std_msgs/UInt32", + "std_msgs/UInt64", + "std_msgs/UInt8", + "std_msgs/UInt8MultiArray", + ] for x in stdmsgs: self.assertNotEqual(ros_loader.get_message_class(x), None) inst = ros_loader.get_message_instance(x) @@ -50,17 +98,38 @@ def test_std_msgnames(self): self.assertEqual(x, inst._type) def test_msg_cache(self): - stdmsgs = ["std_msgs/Bool", "std_msgs/Byte", "std_msgs/ByteMultiArray", - "std_msgs/ColorRGBA", "std_msgs/Duration", "std_msgs/Empty", - "std_msgs/Float32", "std_msgs/Float32MultiArray", "std_msgs/Float64", - "std_msgs/Header", "std_msgs/Int16", "std_msgs/Int16MultiArray", - "std_msgs/Int32", "std_msgs/Int32MultiArray", "std_msgs/Int64", - "std_msgs/Int64MultiArray", "std_msgs/Int8", "std_msgs/Int8MultiArray", - "std_msgs/MultiArrayDimension", "std_msgs/MultiArrayLayout", - "std_msgs/String", "std_msgs/Time", "std_msgs/UInt16", - "std_msgs/UInt16MultiArray", "std_msgs/UInt32MultiArray", - "std_msgs/UInt64MultiArray", "std_msgs/UInt32", "std_msgs/UInt64", - "std_msgs/UInt8", "std_msgs/UInt8MultiArray"] + stdmsgs = [ + "std_msgs/Bool", + "std_msgs/Byte", + "std_msgs/ByteMultiArray", + "std_msgs/ColorRGBA", + "std_msgs/Duration", + "std_msgs/Empty", + "std_msgs/Float32", + "std_msgs/Float32MultiArray", + "std_msgs/Float64", + "std_msgs/Header", + "std_msgs/Int16", + "std_msgs/Int16MultiArray", + "std_msgs/Int32", + "std_msgs/Int32MultiArray", + "std_msgs/Int64", + "std_msgs/Int64MultiArray", + "std_msgs/Int8", + "std_msgs/Int8MultiArray", + "std_msgs/MultiArrayDimension", + "std_msgs/MultiArrayLayout", + "std_msgs/String", + "std_msgs/Time", + "std_msgs/UInt16", + "std_msgs/UInt16MultiArray", + "std_msgs/UInt32MultiArray", + "std_msgs/UInt64MultiArray", + "std_msgs/UInt32", + "std_msgs/UInt64", + "std_msgs/UInt8", + "std_msgs/UInt8MultiArray", + ] for x in stdmsgs: self.assertNotEqual(ros_loader.get_message_class(x), None) inst = ros_loader.get_message_instance(x) @@ -69,12 +138,20 @@ def test_msg_cache(self): self.assertTrue(x in ros_loader._loaded_msgs) def test_assorted_msgnames(self): - assortedmsgs = ["geometry_msgs/Pose", "actionlib_msgs/GoalStatus", - "geometry_msgs/WrenchStamped", "stereo_msgs/DisparityImage", - "nav_msgs/OccupancyGrid", "geometry_msgs/Point32", "std_msgs/String", - "trajectory_msgs/JointTrajectoryPoint", "diagnostic_msgs/KeyValue", - "visualization_msgs/InteractiveMarkerUpdate", "nav_msgs/GridCells", - "sensor_msgs/PointCloud2"] + assortedmsgs = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "std_msgs/String", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] for x in assortedmsgs: self.assertNotEqual(ros_loader.get_message_class(x), None) inst = ros_loader.get_message_instance(x) @@ -82,64 +159,139 @@ def test_assorted_msgnames(self): self.assertEqual(x, inst._type) def test_invalid_msgnames_primitives(self): - invalid = ["bool", "int8", "uint8", "int16", "uint16", "int32", - "uint32", "int64", "uint64", "float32", "float64", "string", "time", - "duration"] + invalid = [ + "bool", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float32", + "float64", + "string", + "time", + "duration", + ] for x in invalid: - self.assertRaises(ros_loader.InvalidTypeStringException, - ros_loader.get_message_class, x) - self.assertRaises(ros_loader.InvalidTypeStringException, - ros_loader.get_message_instance, x) + self.assertRaises( + ros_loader.InvalidTypeStringException, ros_loader.get_message_class, x + ) + self.assertRaises( + ros_loader.InvalidTypeStringException, + ros_loader.get_message_instance, + x, + ) def test_nonexistent_packagenames(self): - nonexistent = ["wangle_msgs/Jam", "whistleblower_msgs/Document", - "sexual_harrassment_msgs/UnwantedAdvance", "coercion_msgs/Bribe", - "airconditioning_msgs/Cold", "pr2thoughts_msgs/Escape"] + nonexistent = [ + "wangle_msgs/Jam", + "whistleblower_msgs/Document", + "sexual_harrassment_msgs/UnwantedAdvance", + "coercion_msgs/Bribe", + "airconditioning_msgs/Cold", + "pr2thoughts_msgs/Escape", + ] for x in nonexistent: - self.assertRaises(ros_loader.InvalidPackageException, - ros_loader.get_message_class, x) - self.assertRaises(ros_loader.InvalidPackageException, - ros_loader.get_message_instance, x) + self.assertRaises( + ros_loader.InvalidPackageException, ros_loader.get_message_class, x + ) + self.assertRaises( + ros_loader.InvalidPackageException, ros_loader.get_message_instance, x + ) def test_packages_without_msgs(self): - no_msgs = ["roslib/Time", "roslib/Duration", "roslib/Header", - "std_srvs/ConflictedMsg", "topic_tools/MessageMessage"] + no_msgs = [ + "roslib/Time", + "roslib/Duration", + "roslib/Header", + "std_srvs/ConflictedMsg", + "topic_tools/MessageMessage", + ] for x in no_msgs: - self.assertRaises(ros_loader.InvalidModuleException, - ros_loader.get_message_class, x) - self.assertRaises(ros_loader.InvalidModuleException, - ros_loader.get_message_instance, x) + self.assertRaises( + ros_loader.InvalidModuleException, ros_loader.get_message_class, x + ) + self.assertRaises( + ros_loader.InvalidModuleException, ros_loader.get_message_instance, x + ) def test_nonexistent_msg_classnames(self): - nonexistent = ["roscpp/Time", "roscpp/Duration", "roscpp/Header", - "rospy/Time", "rospy/Duration", "rospy/Header", "std_msgs/Spool", - "geometry_msgs/Tetrahedron", "sensor_msgs/TelepathyUnit"] + nonexistent = [ + "roscpp/Time", + "roscpp/Duration", + "roscpp/Header", + "rospy/Time", + "rospy/Duration", + "rospy/Header", + "std_msgs/Spool", + "geometry_msgs/Tetrahedron", + "sensor_msgs/TelepathyUnit", + ] for x in nonexistent: - self.assertRaises(ros_loader.InvalidClassException, - ros_loader.get_message_class, x) - self.assertRaises(ros_loader.InvalidClassException, - ros_loader.get_message_instance, x) + self.assertRaises( + ros_loader.InvalidClassException, ros_loader.get_message_class, x + ) + self.assertRaises( + ros_loader.InvalidClassException, ros_loader.get_message_instance, x + ) def test_bad_servicenames(self): - bad = ["", "/", "//", "///", "////", "/////", "bad", "stillbad", - "not/better/still", "not//better//still", "not///better///still", - "better/", "better//", "better///", "/better", "//better", "///better", - r"this\isbad", "\\"] + bad = [ + "", + "/", + "//", + "///", + "////", + "/////", + "bad", + "stillbad", + "not/better/still", + "not//better//still", + "not///better///still", + "better/", + "better//", + "better///", + "/better", + "//better", + "///better", + r"this\isbad", + "\\", + ] for x in bad: - self.assertRaises(ros_loader.InvalidTypeStringException, - ros_loader.get_service_class, x) - self.assertRaises(ros_loader.InvalidTypeStringException, - ros_loader.get_service_instance, x) - self.assertRaises(ros_loader.InvalidTypeStringException, - ros_loader.get_service_request_instance, x) - self.assertRaises(ros_loader.InvalidTypeStringException, - ros_loader.get_service_response_instance, x) + self.assertRaises( + ros_loader.InvalidTypeStringException, ros_loader.get_service_class, x + ) + self.assertRaises( + ros_loader.InvalidTypeStringException, + ros_loader.get_service_instance, + x, + ) + self.assertRaises( + ros_loader.InvalidTypeStringException, + ros_loader.get_service_request_instance, + x, + ) + self.assertRaises( + ros_loader.InvalidTypeStringException, + ros_loader.get_service_response_instance, + x, + ) def test_irregular_servicenames(self): - irregular = ["roscpp//GetLoggers", "/roscpp/GetLoggers/", - "/roscpp/GetLoggers", "//roscpp/GetLoggers", "/roscpp//GetLoggers", - "roscpp/GetLoggers//", "/roscpp/GetLoggers//", "roscpp/GetLoggers/", - "roscpp//GetLoggers//"] + irregular = [ + "roscpp//GetLoggers", + "/roscpp/GetLoggers/", + "/roscpp/GetLoggers", + "//roscpp/GetLoggers", + "/roscpp//GetLoggers", + "roscpp/GetLoggers//", + "/roscpp/GetLoggers//", + "roscpp/GetLoggers/", + "roscpp//GetLoggers//", + ] for x in irregular: self.assertNotEqual(ros_loader.get_service_class(x), None) self.assertNotEqual(ros_loader.get_service_instance(x), None) @@ -147,11 +299,19 @@ def test_irregular_servicenames(self): self.assertNotEqual(ros_loader.get_service_response_instance(x), None) def test_common_servicenames(self): - common = ["roscpp/GetLoggers", "roscpp/SetLoggerLevel", - "std_srvs/Empty", "nav_msgs/GetMap", "nav_msgs/GetPlan", - "sensor_msgs/SetCameraInfo", "topic_tools/MuxAdd", - "topic_tools/MuxSelect", "tf2_msgs/FrameGraph", - "rospy_tutorials/BadTwoInts", "rospy_tutorials/AddTwoInts"] + common = [ + "roscpp/GetLoggers", + "roscpp/SetLoggerLevel", + "std_srvs/Empty", + "nav_msgs/GetMap", + "nav_msgs/GetPlan", + "sensor_msgs/SetCameraInfo", + "topic_tools/MuxAdd", + "topic_tools/MuxSelect", + "tf2_msgs/FrameGraph", + "rospy_tutorials/BadTwoInts", + "rospy_tutorials/AddTwoInts", + ] for x in common: self.assertNotEqual(ros_loader.get_service_class(x), None) self.assertNotEqual(ros_loader.get_service_instance(x), None) @@ -160,11 +320,19 @@ def test_common_servicenames(self): self.assertEqual(x, ros_loader.get_service_instance(x)._type) def test_srv_cache(self): - common = ["roscpp/GetLoggers", "roscpp/SetLoggerLevel", - "std_srvs/Empty", "nav_msgs/GetMap", "nav_msgs/GetPlan", - "sensor_msgs/SetCameraInfo", "topic_tools/MuxAdd", - "topic_tools/MuxSelect", "tf2_msgs/FrameGraph", - "rospy_tutorials/BadTwoInts", "rospy_tutorials/AddTwoInts"] + common = [ + "roscpp/GetLoggers", + "roscpp/SetLoggerLevel", + "std_srvs/Empty", + "nav_msgs/GetMap", + "nav_msgs/GetPlan", + "sensor_msgs/SetCameraInfo", + "topic_tools/MuxAdd", + "topic_tools/MuxSelect", + "tf2_msgs/FrameGraph", + "rospy_tutorials/BadTwoInts", + "rospy_tutorials/AddTwoInts", + ] for x in common: self.assertNotEqual(ros_loader.get_service_class(x), None) self.assertNotEqual(ros_loader.get_service_instance(x), None) @@ -173,47 +341,78 @@ def test_srv_cache(self): self.assertTrue(x in ros_loader._loaded_srvs) def test_packages_without_srvs(self): - no_msgs = ["roslib/A", "roslib/B", "roslib/C", - "std_msgs/CuriousSrv"] + no_msgs = ["roslib/A", "roslib/B", "roslib/C", "std_msgs/CuriousSrv"] for x in no_msgs: - self.assertRaises(ros_loader.InvalidModuleException, - ros_loader.get_service_class, x) - self.assertRaises(ros_loader.InvalidModuleException, - ros_loader.get_service_instance, x) - self.assertRaises(ros_loader.InvalidModuleException, - ros_loader.get_service_request_instance, x) - self.assertRaises(ros_loader.InvalidModuleException, - ros_loader.get_service_response_instance, x) + self.assertRaises( + ros_loader.InvalidModuleException, ros_loader.get_service_class, x + ) + self.assertRaises( + ros_loader.InvalidModuleException, ros_loader.get_service_instance, x + ) + self.assertRaises( + ros_loader.InvalidModuleException, + ros_loader.get_service_request_instance, + x, + ) + self.assertRaises( + ros_loader.InvalidModuleException, + ros_loader.get_service_response_instance, + x, + ) def test_nonexistent_service_packagenames(self): - nonexistent = ["butler_srvs/FetchDrink", "money_srvs/MoreMoney", - "snoopdogg_srvs/SipOnGinAndJuice", "revenge_srvs/BackStab"] + nonexistent = [ + "butler_srvs/FetchDrink", + "money_srvs/MoreMoney", + "snoopdogg_srvs/SipOnGinAndJuice", + "revenge_srvs/BackStab", + ] for x in nonexistent: - self.assertRaises(ros_loader.InvalidPackageException, - ros_loader.get_service_class, x) - self.assertRaises(ros_loader.InvalidPackageException, - ros_loader.get_service_instance, x) - self.assertRaises(ros_loader.InvalidPackageException, - ros_loader.get_service_request_instance, x) - self.assertRaises(ros_loader.InvalidPackageException, - ros_loader.get_service_response_instance, x) + self.assertRaises( + ros_loader.InvalidPackageException, ros_loader.get_service_class, x + ) + self.assertRaises( + ros_loader.InvalidPackageException, ros_loader.get_service_instance, x + ) + self.assertRaises( + ros_loader.InvalidPackageException, + ros_loader.get_service_request_instance, + x, + ) + self.assertRaises( + ros_loader.InvalidPackageException, + ros_loader.get_service_response_instance, + x, + ) def test_nonexistent_service_classnames(self): - nonexistent = ["std_srvs/KillAllHumans", "std_srvs/Full", - "rospy_tutorials/SubtractTwoInts", "nav_msgs/LoseMap", - "topic_tools/TellMeWhatThisTopicIsActuallyAbout"] + nonexistent = [ + "std_srvs/KillAllHumans", + "std_srvs/Full", + "rospy_tutorials/SubtractTwoInts", + "nav_msgs/LoseMap", + "topic_tools/TellMeWhatThisTopicIsActuallyAbout", + ] for x in nonexistent: - self.assertRaises(ros_loader.InvalidClassException, - ros_loader.get_service_class, x) - self.assertRaises(ros_loader.InvalidClassException, - ros_loader.get_service_instance, x) - self.assertRaises(ros_loader.InvalidClassException, - ros_loader.get_service_request_instance, x) - self.assertRaises(ros_loader.InvalidClassException, - ros_loader.get_service_response_instance, x) - -PKG = 'rosbridge_library' -NAME = 'test_ros_loader' -if __name__ == '__main__': - rostest.unitrun(PKG, NAME, TestROSLoader) + self.assertRaises( + ros_loader.InvalidClassException, ros_loader.get_service_class, x + ) + self.assertRaises( + ros_loader.InvalidClassException, ros_loader.get_service_instance, x + ) + self.assertRaises( + ros_loader.InvalidClassException, + ros_loader.get_service_request_instance, + x, + ) + self.assertRaises( + ros_loader.InvalidClassException, + ros_loader.get_service_response_instance, + x, + ) + +PKG = "rosbridge_library" +NAME = "test_ros_loader" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestROSLoader) diff --git a/rosbridge_library/test/internal/test_services.py b/rosbridge_library/test/internal/test_services.py index 103e04ddb..fd0ca5c5f 100755 --- a/rosbridge_library/test/internal/test_services.py +++ b/rosbridge_library/test/internal/test_services.py @@ -31,7 +31,6 @@ def populate_random_args(d): class ServiceTester: - def __init__(self, name, srv_type): self.name = name self.srvClass = ros_loader.get_service_class(srv_type) @@ -77,7 +76,6 @@ def validate(self, equality_function): class TestServices(unittest.TestCase): - def setUp(self): rospy.init_node("test_services") @@ -105,24 +103,39 @@ def test_populate_request_args(self): cls = ros_loader.get_service_class("rosbridge_library/" + srv_type) for args in [[], {}, None]: # Should throw no exceptions - services.args_to_service_request_instance("", cls._request_class(), args) + services.args_to_service_request_instance( + "", cls._request_class(), args + ) # Test msgs with data message for srv_type in ["TestRequestOnly", "TestRequestAndResponse"]: cls = ros_loader.get_service_class("rosbridge_library/" + srv_type) for args in [[3], {"data": 3}]: # Should throw no exceptions - services.args_to_service_request_instance("", cls._request_class(), args) - self.assertRaises(FieldTypeMismatchException, services.args_to_service_request_instance, "", cls._request_class(), ["hello"]) + services.args_to_service_request_instance( + "", cls._request_class(), args + ) + self.assertRaises( + FieldTypeMismatchException, + services.args_to_service_request_instance, + "", + cls._request_class(), + ["hello"], + ) # Test message with multiple fields - cls = ros_loader.get_service_class("rosbridge_library/TestMultipleRequestFields") - for args in [[3, 3.5, "hello", False], {"int": 3, "float": 3.5, "string": "hello", "bool": False}]: + cls = ros_loader.get_service_class( + "rosbridge_library/TestMultipleRequestFields" + ) + for args in [ + [3, 3.5, "hello", False], + {"int": 3, "float": 3.5, "string": "hello", "bool": False}, + ]: # Should throw no exceptions services.args_to_service_request_instance("", cls._request_class(), args) def test_service_call(self): - """ Test a simple getloggers service call """ + """Test a simple getloggers service call""" # First, call the service the 'proper' way p = rospy.ServiceProxy(rospy.get_name() + "/get_loggers", GetLoggers) p.wait_for_service(0.5) @@ -135,7 +148,7 @@ def test_service_call(self): self.assertEqual(x.level, y["level"]) def test_service_caller(self): - """ Same as test_service_call but via the thread caller """ + """Same as test_service_call but via the thread caller""" # First, call the service the 'proper' way p = rospy.ServiceProxy(rospy.get_name() + "/get_loggers", GetLoggers) p.wait_for_service(0.5) @@ -150,7 +163,9 @@ def error(): raise Exception() # Now, call using the services - services.ServiceCaller(rospy.get_name() + "/get_loggers", None, success, error).start() + services.ServiceCaller( + rospy.get_name() + "/get_loggers", None, success, error + ).start() time.sleep(0.5) @@ -159,16 +174,27 @@ def error(): self.assertEqual(x.level, y["level"]) def test_service_tester(self): - t = ServiceTester("/test_service_tester", "rosbridge_library/TestRequestAndResponse") + t = ServiceTester( + "/test_service_tester", "rosbridge_library/TestRequestAndResponse" + ) t.start() time.sleep(1.0) t.validate(self.msgs_equal) def test_service_tester_alltypes(self): ts = [] - for srv in ["TestResponseOnly", "TestEmpty", "TestRequestAndResponse", "TestRequestOnly", - "TestMultipleResponseFields", "TestMultipleRequestFields", "TestArrayRequest"]: - t = ServiceTester("/test_service_tester_alltypes_" + srv, "rosbridge_library/" + srv) + for srv in [ + "TestResponseOnly", + "TestEmpty", + "TestRequestAndResponse", + "TestRequestOnly", + "TestMultipleResponseFields", + "TestMultipleRequestFields", + "TestArrayRequest", + ]: + t = ServiceTester( + "/test_service_tester_alltypes_" + srv, "rosbridge_library/" + srv + ) t.start() ts.append(t) @@ -178,11 +204,19 @@ def test_service_tester_alltypes(self): t.validate(self.msgs_equal) def test_random_service_types(self): - common = ["roscpp/GetLoggers", "roscpp/SetLoggerLevel", - "std_srvs/Empty", "nav_msgs/GetMap", "nav_msgs/GetPlan", - "sensor_msgs/SetCameraInfo", "topic_tools/MuxAdd", - "topic_tools/MuxSelect", "tf2_msgs/FrameGraph", - "rospy_tutorials/BadTwoInts", "rospy_tutorials/AddTwoInts"] + common = [ + "roscpp/GetLoggers", + "roscpp/SetLoggerLevel", + "std_srvs/Empty", + "nav_msgs/GetMap", + "nav_msgs/GetPlan", + "sensor_msgs/SetCameraInfo", + "topic_tools/MuxAdd", + "topic_tools/MuxSelect", + "tf2_msgs/FrameGraph", + "rospy_tutorials/BadTwoInts", + "rospy_tutorials/AddTwoInts", + ] ts = [] for srv in common: t = ServiceTester("/test_random_service_types/" + srv, srv) @@ -195,7 +229,7 @@ def test_random_service_types(self): t.validate(self.msgs_equal) -PKG = 'rosbridge_library' -NAME = 'test_services' -if __name__ == '__main__': +PKG = "rosbridge_library" +NAME = "test_services" +if __name__ == "__main__": rostest.unitrun(PKG, NAME, TestServices) diff --git a/rosbridge_server/scripts/rosbridge_tcp.py b/rosbridge_server/scripts/rosbridge_tcp.py index 3496671a9..52e3473c2 100755 --- a/rosbridge_server/scripts/rosbridge_tcp.py +++ b/rosbridge_server/scripts/rosbridge_tcp.py @@ -22,13 +22,14 @@ import sys import time -#TODO: take care of socket timeouts and make sure to close sockets after killing program to release network ports +# TODO: take care of socket timeouts and make sure to close sockets after killing program to release network ports -#TODO: add new parameters to websocket version! those of rosbridge_tcp.py might not be needed, but the others should work well when adding them to .._websocket.py +# TODO: add new parameters to websocket version! those of rosbridge_tcp.py might not be needed, but the others should work well when adding them to .._websocket.py def shutdown_hook(server): - server.shutdown() + server.shutdown() + if __name__ == "__main__": loaded = False @@ -49,40 +50,57 @@ def shutdown_hook(server): BEGIN... """ -#TODO: ensure types get cast correctly after getting from parameter server -#TODO: check if ROS parameter server uses None string for 'None-value' or Null or something else, then change code accordingly + # TODO: ensure types get cast correctly after getting from parameter server + # TODO: check if ROS parameter server uses None string for 'None-value' or Null or something else, then change code accordingly # update parameters from parameter server or use default value ( second parameter of get_param ) - port = get_param('~port', 9090) - host = get_param('~host', '') - incoming_buffer = get_param('~incoming_buffer', RosbridgeTcpSocket.incoming_buffer) - socket_timeout = get_param('~socket_timeout', RosbridgeTcpSocket.socket_timeout) - retry_startup_delay = get_param('~retry_startup_delay', 5.0) # seconds - fragment_timeout = get_param('~fragment_timeout', RosbridgeTcpSocket.fragment_timeout) - delay_between_messages = get_param('~delay_between_messages', RosbridgeTcpSocket.delay_between_messages) - max_message_size = get_param('~max_message_size', RosbridgeTcpSocket.max_message_size) - unregister_timeout = get_param('~unregister_timeout', RosbridgeTcpSocket.unregister_timeout) - bson_only_mode = get_param('~bson_only_mode', False) + port = get_param("~port", 9090) + host = get_param("~host", "") + incoming_buffer = get_param( + "~incoming_buffer", RosbridgeTcpSocket.incoming_buffer + ) + socket_timeout = get_param( + "~socket_timeout", RosbridgeTcpSocket.socket_timeout + ) + retry_startup_delay = get_param("~retry_startup_delay", 5.0) # seconds + fragment_timeout = get_param( + "~fragment_timeout", RosbridgeTcpSocket.fragment_timeout + ) + delay_between_messages = get_param( + "~delay_between_messages", RosbridgeTcpSocket.delay_between_messages + ) + max_message_size = get_param( + "~max_message_size", RosbridgeTcpSocket.max_message_size + ) + unregister_timeout = get_param( + "~unregister_timeout", RosbridgeTcpSocket.unregister_timeout + ) + bson_only_mode = get_param("~bson_only_mode", False) if max_message_size == "None": max_message_size = None # Get the glob strings and parse them as arrays. RosbridgeTcpSocket.topics_glob = [ - element.strip().strip("'") - for element in get_param('~topics_glob', '')[1:-1].split(',') - if len(element.strip().strip("'")) > 0] + element.strip().strip("'") + for element in get_param("~topics_glob", "")[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] RosbridgeTcpSocket.services_glob = [ - element.strip().strip("'") - for element in get_param('~services_glob', '')[1:-1].split(',') - if len(element.strip().strip("'")) > 0] + element.strip().strip("'") + for element in get_param("~services_glob", "")[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] RosbridgeTcpSocket.params_glob = [ - element.strip().strip("'") - for element in get_param('~params_glob', '')[1:-1].split(',') - if len(element.strip().strip("'")) > 0] - + element.strip().strip("'") + for element in get_param("~params_glob", "")[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] + # Publisher for number of connected clients - RosbridgeTcpSocket.client_count_pub = Publisher('client_count', Int32, queue_size=10, latch=True) + RosbridgeTcpSocket.client_count_pub = Publisher( + "client_count", Int32, queue_size=10, latch=True + ) RosbridgeTcpSocket.client_count_pub.publish(0) # update parameters if provided via commandline @@ -152,7 +170,9 @@ def shutdown_hook(server): else: max_message_size = int(value) else: - print("--max_message_size argument provided without a value. (can be None or )") + print( + "--max_message_size argument provided without a value. (can be None or )" + ) sys.exit(-1) if "--unregister_timeout" in sys.argv: @@ -172,7 +192,6 @@ def shutdown_hook(server): RosbridgeTcpSocket.unregister_timeout = unregister_timeout RosbridgeTcpSocket.bson_only_mode = bson_only_mode - if "--topics_glob" in sys.argv: idx = sys.argv.index("--topics_glob") + 1 if idx < len(sys.argv): @@ -180,9 +199,14 @@ def shutdown_hook(server): if value == "None": RosbridgeTcpSocket.topics_glob = [] else: - RosbridgeTcpSocket.topics_glob = [element.strip().strip("'") for element in value[1:-1].split(',')] + RosbridgeTcpSocket.topics_glob = [ + element.strip().strip("'") + for element in value[1:-1].split(",") + ] else: - print("--topics_glob argument provided without a value. (can be None or a list)") + print( + "--topics_glob argument provided without a value. (can be None or a list)" + ) sys.exit(-1) if "--services_glob" in sys.argv: @@ -192,9 +216,14 @@ def shutdown_hook(server): if value == "None": RosbridgeTcpSocket.services_glob = [] else: - RosbridgeTcpSocket.services_glob = [element.strip().strip("'") for element in value[1:-1].split(',')] + RosbridgeTcpSocket.services_glob = [ + element.strip().strip("'") + for element in value[1:-1].split(",") + ] else: - print("--services_glob argument provided without a value. (can be None or a list)") + print( + "--services_glob argument provided without a value. (can be None or a list)" + ) sys.exit(-1) if "--params_glob" in sys.argv: @@ -204,9 +233,14 @@ def shutdown_hook(server): if value == "None": RosbridgeTcpSocket.params_glob = [] else: - RosbridgeTcpSocket.params_glob = [element.strip().strip("'") for element in value[1:-1].split(',')] + RosbridgeTcpSocket.params_glob = [ + element.strip().strip("'") + for element in value[1:-1].split(",") + ] else: - print("--params_glob argument provided without a value. (can be None or a list)") + print( + "--params_glob argument provided without a value. (can be None or a list)" + ) sys.exit(-1) if "--bson_only_mode" in sys.argv: @@ -227,7 +261,6 @@ def shutdown_hook(server): ...END (parameter handling) """ - # Server host is a tuple ('host', port) # empty string for host makes server listen on all available interfaces SocketServer.ThreadingTCPServer.allow_reuse_address = True diff --git a/rosbridge_server/scripts/rosbridge_udp.py b/rosbridge_server/scripts/rosbridge_udp.py index 57c79112c..eb82ca4e6 100755 --- a/rosbridge_server/scripts/rosbridge_udp.py +++ b/rosbridge_server/scripts/rosbridge_udp.py @@ -35,7 +35,7 @@ import sys from twisted.internet import reactor -from rosbridge_server import RosbridgeUdpSocket,RosbridgeUdpFactory +from rosbridge_server import RosbridgeUdpSocket, RosbridgeUdpFactory from rosbridge_library.capabilities.advertise import Advertise from rosbridge_library.capabilities.publish import Publish @@ -46,52 +46,63 @@ from std_msgs.msg import Int32 + def shutdown_hook(): reactor.stop() + if __name__ == "__main__": rospy.init_node("rosbridge_websocket") - rospy.on_shutdown(shutdown_hook) # register shutdown hook to stop the server + rospy.on_shutdown(shutdown_hook) # register shutdown hook to stop the server ################################################## # Parameter handling # ################################################## - # get RosbridgeProtocol parameters - RosbridgeUdpSocket.fragment_timeout = rospy.get_param('~fragment_timeout', - RosbridgeUdpSocket.fragment_timeout) - RosbridgeUdpSocket.delay_between_messages = rospy.get_param('~delay_between_messages', - RosbridgeUdpSocket.delay_between_messages) - RosbridgeUdpSocket.max_message_size = rospy.get_param('~max_message_size', - RosbridgeUdpSocket.max_message_size) - RosbridgeUdpSocket.unregister_timeout = rospy.get_param('~unregister_timeout', - RosbridgeUdpSocket.unregister_timeout) + # get RosbridgeProtocol parameters + RosbridgeUdpSocket.fragment_timeout = rospy.get_param( + "~fragment_timeout", RosbridgeUdpSocket.fragment_timeout + ) + RosbridgeUdpSocket.delay_between_messages = rospy.get_param( + "~delay_between_messages", RosbridgeUdpSocket.delay_between_messages + ) + RosbridgeUdpSocket.max_message_size = rospy.get_param( + "~max_message_size", RosbridgeUdpSocket.max_message_size + ) + RosbridgeUdpSocket.unregister_timeout = rospy.get_param( + "~unregister_timeout", RosbridgeUdpSocket.unregister_timeout + ) if RosbridgeUdpSocket.max_message_size == "None": RosbridgeUdpSocket.max_message_size = None # Get the glob strings and parse them as arrays. RosbridgeUdpSocket.topics_glob = [ element.strip().strip("'") - for element in rospy.get_param('~topics_glob', '')[1:-1].split(',') - if len(element.strip().strip("'")) > 0] + for element in rospy.get_param("~topics_glob", "")[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] RosbridgeUdpSocket.services_glob = [ element.strip().strip("'") - for element in rospy.get_param('~services_glob', '')[1:-1].split(',') - if len(element.strip().strip("'")) > 0] + for element in rospy.get_param("~services_glob", "")[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] RosbridgeUdpSocket.params_glob = [ element.strip().strip("'") - for element in rospy.get_param('~params_glob', '')[1:-1].split(',') - if len(element.strip().strip("'")) > 0] + for element in rospy.get_param("~params_glob", "")[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] # if authentication should be used - RosbridgeUdpSocket.authenticate = rospy.get_param('~authenticate', False) - port = rospy.get_param('~port', 9090) - interface = rospy.get_param('~interface', "") + RosbridgeUdpSocket.authenticate = rospy.get_param("~authenticate", False) + port = rospy.get_param("~port", 9090) + interface = rospy.get_param("~interface", "") # Publisher for number of connected clients - RosbridgeUdpSocket.client_count_pub = rospy.Publisher('client_count', Int32, queue_size=10, latch=True) + RosbridgeUdpSocket.client_count_pub = rospy.Publisher( + "client_count", Int32, queue_size=10, latch=True + ) RosbridgeUdpSocket.client_count_pub.publish(0) if "--port" in sys.argv: - idx = sys.argv.index("--port")+1 + idx = sys.argv.index("--port") + 1 if idx < len(sys.argv): port = int(sys.argv[idx]) else: @@ -99,7 +110,7 @@ def shutdown_hook(): sys.exit(-1) if "--interface" in sys.argv: - idx = sys.argv.index("--interface")+1 + idx = sys.argv.index("--interface") + 1 if idx < len(sys.argv): interface = int(sys.argv[idx]) else: @@ -131,7 +142,9 @@ def shutdown_hook(): else: RosbridgeUdpSocket.max_message_size = int(value) else: - print("--max_message_size argument provided without a value. (can be None or )") + print( + "--max_message_size argument provided without a value. (can be None or )" + ) sys.exit(-1) if "--unregister_timeout" in sys.argv: @@ -149,9 +162,13 @@ def shutdown_hook(): if value == "None": RosbridgeUdpSocket.topics_glob = [] else: - RosbridgeUdpSocket.topics_glob = [element.strip().strip("'") for element in value[1:-1].split(',')] + RosbridgeUdpSocket.topics_glob = [ + element.strip().strip("'") for element in value[1:-1].split(",") + ] else: - print("--topics_glob argument provided without a value. (can be None or a list)") + print( + "--topics_glob argument provided without a value. (can be None or a list)" + ) sys.exit(-1) if "--services_glob" in sys.argv: @@ -161,9 +178,13 @@ def shutdown_hook(): if value == "None": RosbridgeUdpSocket.services_glob = [] else: - RosbridgeUdpSocket.services_glob = [element.strip().strip("'") for element in value[1:-1].split(',')] + RosbridgeUdpSocket.services_glob = [ + element.strip().strip("'") for element in value[1:-1].split(",") + ] else: - print("--services_glob argument provided without a value. (can be None or a list)") + print( + "--services_glob argument provided without a value. (can be None or a list)" + ) sys.exit(-1) if "--params_glob" in sys.argv: @@ -173,9 +194,13 @@ def shutdown_hook(): if value == "None": RosbridgeUdpSocket.params_glob = [] else: - RosbridgeUdpSocket.params_glob = [element.strip().strip("'") for element in value[1:-1].split(',')] + RosbridgeUdpSocket.params_glob = [ + element.strip().strip("'") for element in value[1:-1].split(",") + ] else: - print("--params_glob argument provided without a value. (can be None or a list)") + print( + "--params_glob argument provided without a value. (can be None or a list)" + ) sys.exit(-1) # To be able to access the list of topics and services, you must be able to access the rosapi services. diff --git a/rosbridge_server/scripts/rosbridge_websocket.py b/rosbridge_server/scripts/rosbridge_websocket.py index 9424fd330..e56359014 100755 --- a/rosbridge_server/scripts/rosbridge_websocket.py +++ b/rosbridge_server/scripts/rosbridge_websocket.py @@ -55,56 +55,71 @@ from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService from rosbridge_library.capabilities.call_service import CallService + def start_hook(): IOLoop.instance().start() + def shutdown_hook(): IOLoop.instance().stop() class RosbridgeWebsocketNode(Node): def __init__(self): - super().__init__('rosbridge_websocket') + super().__init__("rosbridge_websocket") RosbridgeWebSocket.node_handle = self ################################################## # Parameter handling # ################################################## - retry_startup_delay = self.declare_parameter('retry_startup_delay', 2.0).value # seconds. + retry_startup_delay = self.declare_parameter( + "retry_startup_delay", 2.0 + ).value # seconds. RosbridgeWebSocket.use_compression = self.declare_parameter( - 'use_compression', False).value + "use_compression", False + ).value # get RosbridgeProtocol parameters RosbridgeWebSocket.fragment_timeout = self.declare_parameter( - 'fragment_timeout', RosbridgeWebSocket.fragment_timeout).value + "fragment_timeout", RosbridgeWebSocket.fragment_timeout + ).value RosbridgeWebSocket.delay_between_messages = self.declare_parameter( - 'delay_between_messages', RosbridgeWebSocket.delay_between_messages).value + "delay_between_messages", RosbridgeWebSocket.delay_between_messages + ).value RosbridgeWebSocket.max_message_size = self.declare_parameter( - 'max_message_size', RosbridgeWebSocket.max_message_size).value + "max_message_size", RosbridgeWebSocket.max_message_size + ).value RosbridgeWebSocket.unregister_timeout = self.declare_parameter( - 'unregister_timeout', RosbridgeWebSocket.unregister_timeout).value + "unregister_timeout", RosbridgeWebSocket.unregister_timeout + ).value - bson_only_mode = self.declare_parameter('bson_only_mode', False).value + bson_only_mode = self.declare_parameter("bson_only_mode", False).value # get tornado application parameters tornado_settings = {} - tornado_settings['websocket_ping_interval'] = float(self.declare_parameter('websocket_ping_interval', 0).value) - tornado_settings['websocket_ping_timeout'] = float(self.declare_parameter('websocket_ping_timeout', 30).value) + tornado_settings["websocket_ping_interval"] = float( + self.declare_parameter("websocket_ping_interval", 0).value + ) + tornado_settings["websocket_ping_timeout"] = float( + self.declare_parameter("websocket_ping_timeout", 30).value + ) # SSL options - certfile = self.declare_parameter('certfile').value - keyfile = self.declare_parameter('keyfile').value + certfile = self.declare_parameter("certfile").value + keyfile = self.declare_parameter("keyfile").value # if authentication should be used - RosbridgeWebSocket.authenticate = self.declare_parameter('authenticate', False).value + RosbridgeWebSocket.authenticate = self.declare_parameter( + "authenticate", False + ).value - port = self.declare_parameter('port', 9090).value + port = self.declare_parameter("port", 9090).value - address = self.declare_parameter('address', '').value + address = self.declare_parameter("address", "").value RosbridgeWebSocket.client_manager = ClientManager(self) @@ -112,35 +127,39 @@ def __init__(self): # QoS profile with transient local durability (latched topic in ROS 1). client_count_qos_profile = QoSProfile( depth=10, - durability=QoSDurabilityPolicy.RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL + durability=QoSDurabilityPolicy.RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL, ) - RosbridgeWebSocket.client_count_pub = self.create_publisher(Int32, 'client_count', - qos_profile=client_count_qos_profile) + RosbridgeWebSocket.client_count_pub = self.create_publisher( + Int32, "client_count", qos_profile=client_count_qos_profile + ) RosbridgeWebSocket.client_count_pub.publish(Int32(data=0)) # Get the glob strings and parse them as arrays. - topics_glob = self.declare_parameter('topics_glob', '').value + topics_glob = self.declare_parameter("topics_glob", "").value - services_glob = self.declare_parameter('services_glob', '').value + services_glob = self.declare_parameter("services_glob", "").value - params_glob = self.declare_parameter('params_glob', '').value + params_glob = self.declare_parameter("params_glob", "").value RosbridgeWebSocket.topics_glob = [ element.strip().strip("'") - for element in topics_glob[1:-1].split(',') - if len(element.strip().strip("'")) > 0] + for element in topics_glob[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] RosbridgeWebSocket.services_glob = [ element.strip().strip("'") - for element in services_glob[1:-1].split(',') - if len(element.strip().strip("'")) > 0] + for element in services_glob[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] RosbridgeWebSocket.params_glob = [ element.strip().strip("'") - for element in params_glob[1:-1].split(',') - if len(element.strip().strip("'")) > 0] + for element in params_glob[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] if "--port" in sys.argv: - idx = sys.argv.index("--port")+1 + idx = sys.argv.index("--port") + 1 if idx < len(sys.argv): port = int(sys.argv[idx]) else: @@ -148,7 +167,7 @@ def __init__(self): sys.exit(-1) if "--address" in sys.argv: - idx = sys.argv.index("--address")+1 + idx = sys.argv.index("--address") + 1 if idx < len(sys.argv): address = int(sys.argv[idx]) else: @@ -185,7 +204,9 @@ def __init__(self): value = sys.argv[idx] RosbridgeWebSocket.max_message_size = int(value) else: - print("--max_message_size argument provided without a value. (can be )") + print( + "--max_message_size argument provided without a value. (can be )" + ) sys.exit(-1) if "--unregister_timeout" in sys.argv: @@ -203,9 +224,13 @@ def __init__(self): if value == "None": RosbridgeWebSocket.topics_glob = [] else: - RosbridgeWebSocket.topics_glob = [element.strip().strip("'") for element in value[1:-1].split(',')] + RosbridgeWebSocket.topics_glob = [ + element.strip().strip("'") for element in value[1:-1].split(",") + ] else: - print("--topics_glob argument provided without a value. (can be None or a list)") + print( + "--topics_glob argument provided without a value. (can be None or a list)" + ) sys.exit(-1) if "--services_glob" in sys.argv: @@ -215,9 +240,13 @@ def __init__(self): if value == "None": RosbridgeWebSocket.services_glob = [] else: - RosbridgeWebSocket.services_glob = [element.strip().strip("'") for element in value[1:-1].split(',')] + RosbridgeWebSocket.services_glob = [ + element.strip().strip("'") for element in value[1:-1].split(",") + ] else: - print("--services_glob argument provided without a value. (can be None or a list)") + print( + "--services_glob argument provided without a value. (can be None or a list)" + ) sys.exit(-1) if "--params_glob" in sys.argv: @@ -227,9 +256,13 @@ def __init__(self): if value == "None": RosbridgeWebSocket.params_glob = [] else: - RosbridgeWebSocket.params_glob = [element.strip().strip("'") for element in value[1:-1].split(',')] + RosbridgeWebSocket.params_glob = [ + element.strip().strip("'") for element in value[1:-1].split(",") + ] else: - print("--params_glob argument provided without a value. (can be None or a list)") + print( + "--params_glob argument provided without a value. (can be None or a list)" + ) sys.exit(-1) if ("--bson_only_mode" in sys.argv) or bson_only_mode: @@ -238,7 +271,7 @@ def __init__(self): if "--websocket_ping_interval" in sys.argv: idx = sys.argv.index("--websocket_ping_interval") + 1 if idx < len(sys.argv): - tornado_settings['websocket_ping_interval'] = float(sys.argv[idx]) + tornado_settings["websocket_ping_interval"] = float(sys.argv[idx]) else: print("--websocket_ping_interval argument provided without a value.") sys.exit(-1) @@ -246,7 +279,7 @@ def __init__(self): if "--websocket_ping_timeout" in sys.argv: idx = sys.argv.index("--websocket_ping_timeout") + 1 if idx < len(sys.argv): - tornado_settings['websocket_ping_timeout'] = float(sys.argv[idx]) + tornado_settings["websocket_ping_timeout"] = float(sys.argv[idx]) else: print("--websocket_ping_timeout argument provided without a value.") sys.exit(-1) @@ -266,27 +299,33 @@ def __init__(self): # Done with parameter handling # ################################################## - application = Application([(r"/", RosbridgeWebSocket), (r"", RosbridgeWebSocket)], **tornado_settings) + application = Application( + [(r"/", RosbridgeWebSocket), (r"", RosbridgeWebSocket)], **tornado_settings + ) connected = False while not connected and self.context.ok(): try: ssl_options = None if certfile is not None and keyfile is not None: - ssl_options = { "certfile": certfile, "keyfile": keyfile } + ssl_options = {"certfile": certfile, "keyfile": keyfile} sockets = bind_sockets(port, address) actual_port = sockets[0].getsockname()[1] server = HTTPServer(application, ssl_options=ssl_options) server.add_sockets(sockets) self.declare_parameter("actual_port", actual_port) - self.get_logger().info(f"Rosbridge WebSocket server started on port {actual_port}") + self.get_logger().info( + f"Rosbridge WebSocket server started on port {actual_port}" + ) connected = True except OSError as e: self.get_logger().warn( "Unable to start server: {} " - "Retrying in {}s.".format(e, retry_startup_delay)) + "Retrying in {}s.".format(e, retry_startup_delay) + ) time.sleep(retry_startup_delay) + def main(args=None): if args is None: args = sys.argv @@ -294,7 +333,9 @@ def main(args=None): rclpy.init(args=args) rosbridge_websocket_node = RosbridgeWebsocketNode() - spin_callback = PeriodicCallback(lambda: rclpy.spin_once(rosbridge_websocket_node, timeout_sec=0.01), 1) + spin_callback = PeriodicCallback( + lambda: rclpy.spin_once(rosbridge_websocket_node, timeout_sec=0.01), 1 + ) spin_callback.start() start_hook() @@ -302,5 +343,6 @@ def main(args=None): rclpy.shutdown() shutdown_hook() # shutdown hook to stop the server -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/rosbridge_server/src/rosbridge_server/client_mananger.py b/rosbridge_server/src/rosbridge_server/client_mananger.py index 4af23acb0..70331cbd2 100644 --- a/rosbridge_server/src/rosbridge_server/client_mananger.py +++ b/rosbridge_server/src/rosbridge_server/client_mananger.py @@ -41,15 +41,19 @@ class ClientManager: def __init__(self, node_handle): - qos = QoSProfile(depth=1, - durability=QoSDurabilityPolicy.RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL) + qos = QoSProfile( + depth=1, + durability=QoSDurabilityPolicy.RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL, + ) # Publisher for number of connected clients self._client_count_pub = node_handle.create_publisher( - Int32, 'client_count', qos_profile=qos) + Int32, "client_count", qos_profile=qos + ) # Publisher for connected clients self._conn_clients_pub = node_handle.create_publisher( - ConnectedClients, 'connected_clients', qos_profile=qos) + ConnectedClients, "connected_clients", qos_profile=qos + ) self._lock = threading.Lock() self._client_count = 0 diff --git a/rosbridge_server/src/rosbridge_server/tcp_handler.py b/rosbridge_server/src/rosbridge_server/tcp_handler.py index c31872771..6ff8ed8a5 100755 --- a/rosbridge_server/src/rosbridge_server/tcp_handler.py +++ b/rosbridge_server/src/rosbridge_server/tcp_handler.py @@ -7,6 +7,7 @@ except ImportError: import socketserver as SocketServer + class RosbridgeTcpSocket(SocketServer.BaseRequestHandler): """ TCP Socket server for rosbridge @@ -19,15 +20,15 @@ class RosbridgeTcpSocket(SocketServer.BaseRequestHandler): client_count_pub = None # list of parameters - incoming_buffer = 65536 # bytes - socket_timeout = 10 # seconds + incoming_buffer = 65536 # bytes + socket_timeout = 10 # seconds # The following are passed on to RosbridgeProtocol # defragmentation.py: - fragment_timeout = 600 # seconds + fragment_timeout = 600 # seconds # protocol.py: - delay_between_messages = 0 # seconds - max_message_size = None # bytes - unregister_timeout = 10.0 # seconds + delay_between_messages = 0 # seconds + max_message_size = None # bytes + unregister_timeout = 10.0 # seconds bson_only_mode = False def setup(self): @@ -37,7 +38,7 @@ def setup(self): "delay_between_messages": cls.delay_between_messages, "max_message_size": cls.max_message_size, "unregister_timeout": cls.unregister_timeout, - "bson_only_mode": cls.bson_only_mode + "bson_only_mode": cls.bson_only_mode, } try: @@ -47,14 +48,16 @@ def setup(self): cls.clients_connected += 1 if cls.client_count_pub: cls.client_count_pub.publish(cls.clients_connected) - self.protocol.log("info", "connected. " + str(cls.clients_connected) + " client total.") + self.protocol.log( + "info", "connected. " + str(cls.clients_connected) + " client total." + ) except Exception as exc: rospy.logerr("Unable to accept incoming connection. Reason: %s", str(exc)) - def recvall(self,n): + def recvall(self, n): # http://stackoverflow.com/questions/17667903/python-socket-receive-large-amount-of-data # Helper function to recv n bytes or return None if EOF is hit - data = '' + data = "" while len(data) < n: packet = self.request.recv(n - len(data)) if not packet: @@ -68,14 +71,16 @@ def recv_bson(self): raw_msglen = self.recvall(BSON_LENGTH_IN_BYTES) if not raw_msglen: return None - msglen = struct.unpack('i', raw_msglen)[0] + msglen = struct.unpack("i", raw_msglen)[0] # Retrieve the rest of the message data = self.recvall(msglen - BSON_LENGTH_IN_BYTES) if data is None: return None - data = raw_msglen + data # Prefix the data with the message length that has already been received. - # The message length is part of BSONs message format + data = ( + raw_msglen + data + ) # Prefix the data with the message length that has already been received. + # The message length is part of BSONs message format # Exit on empty message if len(data) == 0: @@ -92,22 +97,25 @@ def handle(self): self.request.settimeout(cls.socket_timeout) while True: try: - if self.bson_only_mode: - if self.recv_bson() is None: - break - continue - - # non-BSON handling - data = self.request.recv(cls.incoming_buffer) - # Exit on empty string - if data.strip() == '': - break - elif len(data.strip()) > 0: - self.protocol.incoming(data.strip('')) - else: - pass + if self.bson_only_mode: + if self.recv_bson() is None: + break + continue + + # non-BSON handling + data = self.request.recv(cls.incoming_buffer) + # Exit on empty string + if data.strip() == "": + break + elif len(data.strip()) > 0: + self.protocol.incoming(data.strip("")) + else: + pass except Exception: - self.protocol.log("debug", "socket connection timed out! (ignore warning if client is only listening..)") + self.protocol.log( + "debug", + "socket connection timed out! (ignore warning if client is only listening..)", + ) def finish(self): """ @@ -118,7 +126,9 @@ def finish(self): self.protocol.finish() if cls.client_count_pub: cls.client_count_pub.publish(cls.clients_connected) - self.protocol.log("info", "disconnected. " + str(cls.clients_connected) + " client total." ) + self.protocol.log( + "info", "disconnected. " + str(cls.clients_connected) + " client total." + ) def send_message(self, message=None): """ diff --git a/rosbridge_server/src/rosbridge_server/udp_handler.py b/rosbridge_server/src/rosbridge_server/udp_handler.py index e60cd11d0..beb4a6391 100644 --- a/rosbridge_server/src/rosbridge_server/udp_handler.py +++ b/rosbridge_server/src/rosbridge_server/udp_handler.py @@ -4,15 +4,18 @@ from twisted.internet.protocol import DatagramProtocol + class RosbridgeUdpFactory(DatagramProtocol): def startProtocol(self): self.socks = dict() + def datagramReceived(self, message, source_addr): (host, port) = source_addr endpoint = host.__str__() + port.__str__() if endpoint in self.socks: self.socks[endpoint].datagramReceived(message) else: + def writefunc(msg): self.transport.write(msg, (host, port)) @@ -20,6 +23,7 @@ def writefunc(msg): self.socks[endpoint].startProtocol() self.socks[endpoint].datagramReceived(message) + class RosbridgeUdpSocket: client_id_seed = 0 clients_connected = 0 @@ -27,13 +31,13 @@ class RosbridgeUdpSocket: # The following parameters are passed on to RosbridgeProtocol # defragmentation.py: - fragment_timeout = 600 # seconds + fragment_timeout = 600 # seconds # protocol.py: - delay_between_messages = 0 # seconds - max_message_size = None # bytes - unregister_timeout = 10.0 # seconds + delay_between_messages = 0 # seconds + max_message_size = None # bytes + unregister_timeout = 10.0 # seconds - def __init__(self,write): + def __init__(self, write): self.write = write def startProtocol(self): @@ -42,7 +46,7 @@ def startProtocol(self): "fragment_timeout": cls.fragment_timeout, "delay_between_messages": cls.delay_between_messages, "max_message_size": cls.max_message_size, - "unregister_timeout": cls.unregister_timeout + "unregister_timeout": cls.unregister_timeout, } try: self.protocol = RosbridgeProtocol(cls.client_id_seed, parameters=parameters) @@ -65,8 +69,10 @@ def stopProtocol(self): if cls.client_count_pub: cls.client_count_pub.publish(cls.clients_connected) rospy.loginfo("Client disconnected. %d clients total.", cls.clients_connected) + def send_message(self, message): binary = isinstance(message, bson.BSON) self.write(message) + def check_origin(self, origin): return False diff --git a/rosbridge_server/src/rosbridge_server/websocket_handler.py b/rosbridge_server/src/rosbridge_server/websocket_handler.py index 96f90b145..f550c7a70 100755 --- a/rosbridge_server/src/rosbridge_server/websocket_handler.py +++ b/rosbridge_server/src/rosbridge_server/websocket_handler.py @@ -49,11 +49,12 @@ def _log_exception(): """Log the most recent exception to ROS.""" exc = traceback.format_exception(*sys.exc_info()) - RosbridgeWebSocket.node_handle.get_logger().error(''.join(exc)) + RosbridgeWebSocket.node_handle.get_logger().error("".join(exc)) def log_exceptions(f): """Decorator for logging exceptions to ROS.""" + @wraps(f) def wrapper(*args, **kwargs): try: @@ -61,6 +62,7 @@ def wrapper(*args, **kwargs): except Exception: _log_exception() raise + return wrapper @@ -71,15 +73,14 @@ class RosbridgeWebSocket(WebSocketHandler): # The following are passed on to RosbridgeProtocol # defragmentation.py: - fragment_timeout = 600 # seconds + fragment_timeout = 600 # seconds # protocol.py: - delay_between_messages = 0 # seconds - max_message_size = 10000000 # bytes - unregister_timeout = 10.0 # seconds + delay_between_messages = 0 # seconds + max_message_size = 10000000 # bytes + unregister_timeout = 10.0 # seconds bson_only_mode = False node_handle = None - @log_exceptions def open(self): cls = self.__class__ @@ -88,10 +89,12 @@ def open(self): "delay_between_messages": cls.delay_between_messages, "max_message_size": cls.max_message_size, "unregister_timeout": cls.unregister_timeout, - "bson_only_mode": cls.bson_only_mode + "bson_only_mode": cls.bson_only_mode, } try: - self.protocol = RosbridgeProtocol(cls.client_id_seed, cls.node_handle, parameters=parameters) + self.protocol = RosbridgeProtocol( + cls.client_id_seed, cls.node_handle, parameters=parameters + ) self.protocol.outgoing = self.send_message self.set_nodelay(True) self._write_lock = threading.RLock() @@ -101,14 +104,18 @@ def open(self): if cls.client_manager: cls.client_manager.add_client(self.client_id, self.request.remote_ip) except Exception as exc: - cls.node_handle.get_logger().error(f"Unable to accept incoming connection. Reason: {exc}") + cls.node_handle.get_logger().error( + f"Unable to accept incoming connection. Reason: {exc}" + ) - cls.node_handle.get_logger().info(f"Client connected. {cls.clients_connected} clients total.") + cls.node_handle.get_logger().info( + f"Client connected. {cls.clients_connected} clients total." + ) @log_exceptions def on_message(self, message): if isinstance(message, bytes): - message = message.decode('utf-8') + message = message.decode("utf-8") self.protocol.incoming(message) @log_exceptions @@ -118,7 +125,9 @@ def on_close(self): self.protocol.finish() if cls.client_manager: cls.client_manager.remove_client(self.client_id, self.request.remote_ip) - cls.node_handle.get_logger().info(f"Client disconnected. {cls.clients_connected} clients total.") + cls.node_handle.get_logger().info( + f"Client disconnected. {cls.clients_connected} clients total." + ) def send_message(self, message): if isinstance(message, bson.BSON): @@ -130,7 +139,9 @@ def send_message(self, message): binary = False with self._write_lock: - IOLoop.instance().add_callback(partial(self.prewrite_message, message, binary)) + IOLoop.instance().add_callback( + partial(self.prewrite_message, message, binary) + ) @coroutine def prewrite_message(self, message, binary): @@ -143,17 +154,21 @@ def prewrite_message(self, message, binary): # When closing, self.write_message() return None even if it's an undocument output. # Consider it as WebSocketClosedError # For tornado versions <4.3.0 self.write_message() does not have a return value - if future is None and tornado_version_info >= (4,3,0,0): + if future is None and tornado_version_info >= (4, 3, 0, 0): raise WebSocketClosedError yield future except WebSocketClosedError: - cls.node_handle.get_logger().warn('WebSocketClosedError: Tried to write to a closed websocket', - throttle_duration_sec=1.0) + cls.node_handle.get_logger().warn( + "WebSocketClosedError: Tried to write to a closed websocket", + throttle_duration_sec=1.0, + ) raise except StreamClosedError: - cls.node_handle.get_logger().warn('StreamClosedError: Tried to write to a closed stream', - throttle_duration_sec=1.0) + cls.node_handle.get_logger().warn( + "StreamClosedError: Tried to write to a closed stream", + throttle_duration_sec=1.0, + ) raise except BadYieldError: # Tornado <4.5.0 doesn't like its own yield and raises BadYieldError. From c1e01c6b9285820b00ef36ba3c700ede96e5744d Mon Sep 17 00:00:00 2001 From: Kenji Miyake Date: Sat, 25 Sep 2021 03:08:49 +0900 Subject: [PATCH 3/7] Apply pre-commit to other files Signed-off-by: Kenji Miyake --- AUTHORS.md | 2 +- CHANGELOG.md | 3 +- LICENSE | 6 +- ROSBRIDGE_PROTOCOL.md | 26 +-- rosapi/README.md | 2 +- rosapi/scripts/rosapi_node | 197 +++++++++++------- rosapi/srv/DeleteParam.srv | 2 +- rosapi/srv/GetActionServers.srv | 2 +- rosapi/srv/GetParam.srv | 2 +- rosapi/srv/GetParamNames.srv | 2 +- rosapi/srv/GetTime.srv | 2 +- rosapi/srv/HasParam.srv | 2 +- rosapi/srv/MessageDetails.srv | 2 +- rosapi/srv/NodeDetails.srv | 2 +- rosapi/srv/Nodes.srv | 2 +- rosapi/srv/Publishers.srv | 2 +- rosapi/srv/SearchParam.srv | 2 +- rosapi/srv/ServiceHost.srv | 2 +- rosapi/srv/ServiceNode.srv | 2 +- rosapi/srv/ServiceProviders.srv | 2 +- rosapi/srv/ServiceRequestDetails.srv | 2 +- rosapi/srv/ServiceResponseDetails.srv | 2 +- rosapi/srv/ServiceType.srv | 2 +- rosapi/srv/Services.srv | 2 +- rosapi/srv/ServicesForType.srv | 2 +- rosapi/srv/SetParam.srv | 2 +- rosapi/srv/Subscribers.srv | 2 +- rosapi/srv/TopicType.srv | 2 +- rosapi/srv/Topics.srv | 2 +- rosapi/srv/TopicsForType.srv | 2 +- rosbridge_library/msg/TestChar.msg | 2 +- rosbridge_library/msg/TestDurationArray.msg | 2 +- rosbridge_library/msg/TestHeader.msg | 2 +- rosbridge_library/msg/TestHeaderArray.msg | 2 +- rosbridge_library/msg/TestHeaderTwo.msg | 2 +- rosbridge_library/msg/TestTimeArray.msg | 2 +- rosbridge_library/msg/TestUInt8.msg | 2 +- rosbridge_library/srv/TestArrayRequest.srv | 4 +- rosbridge_library/srv/TestEmpty.srv | 2 +- .../srv/TestMultipleRequestFields.srv | 2 +- .../srv/TestMultipleResponseFields.srv | 2 +- .../srv/TestRequestAndResponse.srv | 2 +- rosbridge_library/srv/TestRequestOnly.srv | 4 +- rosbridge_library/srv/TestResponseOnly.srv | 4 +- rosbridge_library/test/test_all.test | 1 - 45 files changed, 184 insertions(+), 135 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 7603f8820..fd1196c0f 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -11,4 +11,4 @@ Contributors * Brandon Alexander (baalexander@gmail.com) * David Bertram (davidbertram@gmx.de) * Matthias Gruhler (matthias.gruhler@ipa.fraunhofer.de) - * Travis Prosser (travisprosser@gmail.com) + * Travis Prosser (travisprosser@gmail.com) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed3b2170c..37a3140d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ DEVEL * more natural json for call service result (OTL) * Add service call fail handling (OTL) -2013-07-16 - **0.5.0** +2013-07-16 - **0.5.0** * Adds travis CI script (rctoris) * current authentication op code added (rctoris) * Removes global bin installation (jihoonl) @@ -45,4 +45,3 @@ DEVEL * Fixes "int is not iterable" bug (baalexander) * Catkinizes tests (baalexander) * Catkinizes packages (baalexander) - diff --git a/LICENSE b/LICENSE index ea5f1d4ec..322ef66be 100644 --- a/LICENSE +++ b/LICENSE @@ -13,9 +13,9 @@ are met: copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Robert Bosch LLC, Willow Garage Inc., - Worcester Polytechnic Institute, Yujin Robot nor the names of its - contributors may be used to endorse or promote products derived + * Neither the name of Robert Bosch LLC, Willow Garage Inc., + Worcester Polytechnic Institute, Yujin Robot nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS diff --git a/ROSBRIDGE_PROTOCOL.md b/ROSBRIDGE_PROTOCOL.md index 32b867486..d7a1408f6 100644 --- a/ROSBRIDGE_PROTOCOL.md +++ b/ROSBRIDGE_PROTOCOL.md @@ -261,7 +261,7 @@ message is dropped. Optional authentication information can be passed via the rosbridge protocol to authenticate a client connection. This information should come from some -trusted third-party authenticator. +trusted third-party authenticator. Authentication is based on the MAC (message authentication code) scheme. The key to using MAC is that it does not tie users to a single "user database." @@ -272,13 +272,13 @@ It simply requires some trusted third-party to provide the hash-keys. To send authentication credentials, use the auth command. ```json -{ "op": "auth", - "mac": , - "client": , - "dest": , - "rand": , - "t": , - "level": , +{ "op": "auth", + "mac": , + "client": , + "dest": , + "rand": , + "t": , + "level": , "end": } ``` @@ -292,15 +292,15 @@ To send authentication credentials, use the auth command. * **end** – end time of the client's session * Any server that enabled authentication should wait for - this request to come in first before accepting any other + this request to come in first before accepting any other `op` code from the client. - * Once the request comes in, it would verify the information + * Once the request comes in, it would verify the information (in a ROS system, using `rosauth`; however, the verification - method is not tied to ROS). + method is not tied to ROS). * If the authentication is good, the connection would be kept and rosbridge would function as normal. If the authentication - is bad, the connection would be severed. - * In the case that authentication is not enabled on the server, + is bad, the connection would be severed. + * In the case that authentication is not enabled on the server, this `op` code can be ignored. ### 3.4 ROS messages diff --git a/rosapi/README.md b/rosapi/README.md index 98a5fac64..1244fc675 100644 --- a/rosapi/README.md +++ b/rosapi/README.md @@ -6,7 +6,7 @@ rosapi * `~topics_glob` (string, default '') * `~services_glob` (string, default '') * `~params_glob` (string, default '') - + ```Note: By default the rosapi calls for details about topics, services, and parameters will return nothing. You must specify a list of allowed resources.``` Each of the glob parameters may contain an array of one or more match patterns. Resources that match any of the specified patterns will be returned by calls to the rosapi services. diff --git a/rosapi/scripts/rosapi_node b/rosapi/scripts/rosapi_node index accef32aa..5011c457c 100755 --- a/rosapi/scripts/rosapi_node +++ b/rosapi/scripts/rosapi_node @@ -44,47 +44,71 @@ from rosapi.msg import * class Rosapi(Node): - NAME = 'rosapi' + NAME = "rosapi" def __init__(self): super().__init__(self.NAME) - self.declare_parameter('topics_glob', '[*]') - self.declare_parameter('services_glob', '[*]') - self.declare_parameter('params_glob', '[*]') + self.declare_parameter("topics_glob", "[*]") + self.declare_parameter("services_glob", "[*]") + self.declare_parameter("params_glob", "[*]") self.globs = self.get_globs() self.register_services() # Initialises the ROS node def register_services(self): proxy.init(self) - if self.get_namespace() == '/': + if self.get_namespace() == "/": full_name = self.get_namespace() + self.get_name() else: - full_name = self.get_namespace() + '/' + self.get_name() + full_name = self.get_namespace() + "/" + self.get_name() params.init(full_name) - self.create_service(Topics, '/rosapi/topics', self.get_topics) - self.create_service(TopicsForType, '/rosapi/topics_for_type', self.get_topics_for_type) - self.create_service(TopicsAndRawTypes, '/rosapi/topics_and_raw_types', self.get_topics_and_raw_types) - self.create_service(Services, '/rosapi/services', self.get_services) - self.create_service(ServicesForType, '/rosapi/services_for_type', self.get_services_for_type) - self.create_service(Nodes, '/rosapi/nodes', self.get_nodes) - self.create_service(NodeDetails, '/rosapi/node_details', self.get_node_details) - self.create_service(GetActionServers, '/rosapi/action_servers', self.get_action_servers) - self.create_service(TopicType, '/rosapi/topic_type', self.get_topic_type) - self.create_service(ServiceType, '/rosapi/service_type', self.get_service_type) - self.create_service(Publishers, '/rosapi/publishers', self.get_publishers) - self.create_service(Subscribers, '/rosapi/subscribers', self.get_subscribers) - self.create_service(ServiceProviders, '/rosapi/service_providers', self.get_service_providers) - self.create_service(ServiceNode, '/rosapi/service_node', self.get_service_node) - self.create_service(MessageDetails, '/rosapi/message_details', self.get_message_details) - self.create_service(ServiceRequestDetails, '/rosapi/service_request_details', self.get_service_request_details) - self.create_service(ServiceResponseDetails, '/rosapi/service_response_details', self.get_service_response_details) - self.create_service(SetParam, '/rosapi/set_param', self.set_param) - self.create_service(GetParam, '/rosapi/get_param', self.get_param) - self.create_service(HasParam, '/rosapi/has_param', self.has_param) - self.create_service(DeleteParam, '/rosapi/delete_param', self.delete_param) - self.create_service(GetParamNames, '/rosapi/get_param_names', self.get_param_names) - self.create_service(GetTime, '/rosapi/get_time', self.get_time) + self.create_service(Topics, "/rosapi/topics", self.get_topics) + self.create_service( + TopicsForType, "/rosapi/topics_for_type", self.get_topics_for_type + ) + self.create_service( + TopicsAndRawTypes, + "/rosapi/topics_and_raw_types", + self.get_topics_and_raw_types, + ) + self.create_service(Services, "/rosapi/services", self.get_services) + self.create_service( + ServicesForType, "/rosapi/services_for_type", self.get_services_for_type + ) + self.create_service(Nodes, "/rosapi/nodes", self.get_nodes) + self.create_service(NodeDetails, "/rosapi/node_details", self.get_node_details) + self.create_service( + GetActionServers, "/rosapi/action_servers", self.get_action_servers + ) + self.create_service(TopicType, "/rosapi/topic_type", self.get_topic_type) + self.create_service(ServiceType, "/rosapi/service_type", self.get_service_type) + self.create_service(Publishers, "/rosapi/publishers", self.get_publishers) + self.create_service(Subscribers, "/rosapi/subscribers", self.get_subscribers) + self.create_service( + ServiceProviders, "/rosapi/service_providers", self.get_service_providers + ) + self.create_service(ServiceNode, "/rosapi/service_node", self.get_service_node) + self.create_service( + MessageDetails, "/rosapi/message_details", self.get_message_details + ) + self.create_service( + ServiceRequestDetails, + "/rosapi/service_request_details", + self.get_service_request_details, + ) + self.create_service( + ServiceResponseDetails, + "/rosapi/service_response_details", + self.get_service_response_details, + ) + self.create_service(SetParam, "/rosapi/set_param", self.set_param) + self.create_service(GetParam, "/rosapi/get_param", self.get_param) + self.create_service(HasParam, "/rosapi/has_param", self.has_param) + self.create_service(DeleteParam, "/rosapi/delete_param", self.delete_param) + self.create_service( + GetParamNames, "/rosapi/get_param_names", self.get_param_names + ) + self.create_service(GetTime, "/rosapi/get_time", self.get_time) # TODO(@jubeira): Implement missing services: # rospy.Service('/rosapi/service_host', ServiceHost, get_service_host) @@ -93,108 +117,123 @@ class Rosapi(Node): def get_globs(self): return glob_helper.get_globs(self) - def get_topics(self, request, response): - """ Called by the rosapi/Topics service. Returns a list of all the topics being published. """ + """Called by the rosapi/Topics service. Returns a list of all the topics being published.""" response.topics, response.types = proxy.get_topics_and_types(self.globs.topics) return response - def get_topics_for_type(self, request, response): - """ Called by the rosapi/TopicsForType service. Returns a list of all the topics that are publishing a given type """ + """Called by the rosapi/TopicsForType service. Returns a list of all the topics that are publishing a given type""" response.topics = proxy.get_topics_for_type(request.type, self.globs.topics) return response - def get_topics_and_raw_types(self, request, response): - """ Called by the rosapi/TopicsAndRawTypes service. Returns a list of all the topics being published, and their - raw types, similar to `gendeps --cat`. """ + """Called by the rosapi/TopicsAndRawTypes service. Returns a list of all the topics being published, and their + raw types, similar to `gendeps --cat`.""" response.topics, response.types = proxy.get_topics_and_types(self.globs.topics) - response.typedefs_full_text = [objectutils.get_typedef_full_text(type) for type in response.types] + response.typedefs_full_text = [ + objectutils.get_typedef_full_text(type) for type in response.types + ] return response def get_services(self, request, response): - """ Called by the rosapi/Services service. Returns a list of all the services being advertised. """ + """Called by the rosapi/Services service. Returns a list of all the services being advertised.""" response.services = proxy.get_services(self.globs.services) return response def get_services_for_type(self, request, response): - """ Called by the rosapi/ServicesForType service. Returns a list of all the services that are publishing a given type """ - response.services = proxy.get_services_for_type(request.type, self.globs.services) + """Called by the rosapi/ServicesForType service. Returns a list of all the services that are publishing a given type""" + response.services = proxy.get_services_for_type( + request.type, self.globs.services + ) return response def get_nodes(self, request, response): - """ Called by the rosapi/Nodes service. Returns a list of all the nodes that are registered """ + """Called by the rosapi/Nodes service. Returns a list of all the nodes that are registered""" response.nodes = proxy.get_nodes() return response def get_node_details(self, request, response): - """ Called by the rosapi/Nodes service. Returns a node description """ - response.subscribing, response.publishing, response.services = proxy.get_node_info(request.node) + """Called by the rosapi/Nodes service. Returns a node description""" + ( + response.subscribing, + response.publishing, + response.services, + ) = proxy.get_node_info(request.node) return response def get_action_servers(self, request, response): - """ Called by the rosapi/GetActionServers service. Returns a list of action servers based on actions standard topics """ + """Called by the rosapi/GetActionServers service. Returns a list of action servers based on actions standard topics""" topics = proxy.get_topics(self.globs.topics, include_hidden=True) response.action_servers = proxy.filter_action_servers(topics) return response def get_topic_type(self, request, response): - """ Called by the rosapi/TopicType service. Given the name of a topic, returns the name of the type of that topic. + """Called by the rosapi/TopicType service. Given the name of a topic, returns the name of the type of that topic. Request class has one field, 'topic', which is a string value (the name of the topic) Response class has one field, 'type', which is a string value (the type of the topic) - If the topic does not exist, an empty string is returned. """ + If the topic does not exist, an empty string is returned.""" response.type = proxy.get_topic_type(request.topic, self.globs.topics) return response def get_service_type(self, request, response): - """ Called by the rosapi/ServiceType service. Given the name of a service, returns the type of that service + """Called by the rosapi/ServiceType service. Given the name of a service, returns the type of that service Request class has one field, 'service', which is a string value (the name of the service) Response class has one field, 'type', which is a string value (the type of the service) - If the service does not exist, an empty string is returned. """ + If the service does not exist, an empty string is returned.""" response.type = proxy.get_service_type(request.service, self.globs.services) return response def get_publishers(self, request, response): - """ Called by the rosapi/Publishers service. Given the name of a topic, returns a list of node names - that are publishing on that topic. """ + """Called by the rosapi/Publishers service. Given the name of a topic, returns a list of node names + that are publishing on that topic.""" response.publishers = proxy.get_publishers(request.topic, self.globs.topics) return response def get_subscribers(self, request, response): - """ Called by the rosapi/Subscribers service. Given the name of a topic, returns a list of node names - that are subscribing to that topic. """ + """Called by the rosapi/Subscribers service. Given the name of a topic, returns a list of node names + that are subscribing to that topic.""" response.subscribers = proxy.get_subscribers(request.topic, self.globs.topics) return response def get_service_providers(self, request, response): - """ Called by the rosapi/ServiceProviders service. Given the name of a topic, returns a list of node names - that are advertising that service type """ - response.providers = proxy.get_service_providers(request.service, self.globs.services) + """Called by the rosapi/ServiceProviders service. Given the name of a topic, returns a list of node names + that are advertising that service type""" + response.providers = proxy.get_service_providers( + request.service, self.globs.services + ) return response def get_service_node(self, request, response): - """ Called by the rosapi/ServiceNode service. Given the name of a service, returns the name of the node - that is providing that service. """ + """Called by the rosapi/ServiceNode service. Given the name of a service, returns the name of the node + that is providing that service.""" response.node = proxy.get_service_node(request.service, self.globs.services) return response def get_message_details(self, request, response): - """ Called by the rosapi/MessageDetails service. Given the name of a message type, returns the TypeDef + """Called by the rosapi/MessageDetails service. Given the name of a message type, returns the TypeDef for that type.""" - response.typedefs = [dict_to_typedef(d) for d in objectutils.get_typedef_recursive(request.type)] + response.typedefs = [ + dict_to_typedef(d) for d in objectutils.get_typedef_recursive(request.type) + ] return response def get_service_request_details(self, request, response): - """ Called by the rosapi/ServiceRequestDetails service. Given the name of a service type, returns the TypeDef - for the request message of that service type. """ - response.typedefs = [dict_to_typedef(d) for d in objectutils.get_service_request_typedef_recursive(request.type)] + """Called by the rosapi/ServiceRequestDetails service. Given the name of a service type, returns the TypeDef + for the request message of that service type.""" + response.typedefs = [ + dict_to_typedef(d) + for d in objectutils.get_service_request_typedef_recursive(request.type) + ] return response def get_service_response_details(self, request, response): - """ Called by the rosapi/ServiceResponseDetails service. Given the name of a service type, returns the TypeDef - for the response message of that service type. """ - response.typedefs = [dict_to_typedef(d) for d in objectutils.get_service_response_typedef_recursive(request.type)] + """Called by the rosapi/ServiceResponseDetails service. Given the name of a service type, returns the TypeDef + for the response message of that service type.""" + response.typedefs = [ + dict_to_typedef(d) + for d in objectutils.get_service_response_typedef_recursive(request.type) + ] return response def set_param(self, request, response): @@ -208,7 +247,9 @@ class Rosapi(Node): def get_param(self, request, response): try: node_name, param_name = self._get_node_and_param_name(request.name) - response.value = params.get_param(node_name, param_name, request.default_value, self.globs.params) + response.value = params.get_param( + node_name, param_name, request.default_value, self.globs.params + ) except ValueError: self._print_malformed_param_name_warning(request.name) return response @@ -234,22 +275,31 @@ class Rosapi(Node): return response def _get_node_and_param_name(self, param): - return tuple(param.split(':')) + return tuple(param.split(":")) def _print_malformed_param_name_warning(self, param_name): - self.get_logger().warn('Malformed parameter name: {}; expecting :'.format(param_name)) + self.get_logger().warn( + "Malformed parameter name: {}; expecting :".format( + param_name + ) + ) + # TODO(@jubeira): make all of these methods of the node and port them. # Note(@jubeira): there is no equivalent for this in ROS2 so far. The service doesn't seem to e used anywhere in rosbridge. def get_service_host(request): - """ Called by the rosapi/ServiceNode service. Given the name of a service, returns the name of the machine - that is hosting that service. """ + """Called by the rosapi/ServiceNode service. Given the name of a service, returns the name of the machine + that is hosting that service.""" return ServiceHostResponse(proxy.get_service_host(request.service)) + # Note(@jubeira): rclpy does not have an equivalent for this. To be checked if this service is necessary or not. def search_param(request): - return SearchParamResponse(rosapi.params.search_param(request.name, rosapi.glob_helper.params)) + return SearchParamResponse( + rosapi.params.search_param(request.name, rosapi.glob_helper.params) + ) + def dict_to_typedef(typedefdict): typedef = TypeDef() @@ -266,7 +316,7 @@ def dict_to_typedef(typedefdict): def main(args=None): if args is None: args = sys.argv - + rclpy.init(args=args) rosapi_node = Rosapi() rclpy.spin(rosapi_node) @@ -274,5 +324,6 @@ def main(args=None): node.destroy_node() rclpy.shutdown() -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/rosapi/srv/DeleteParam.srv b/rosapi/srv/DeleteParam.srv index 1da96270a..22a97d597 100644 --- a/rosapi/srv/DeleteParam.srv +++ b/rosapi/srv/DeleteParam.srv @@ -1,2 +1,2 @@ string name ---- \ No newline at end of file +--- diff --git a/rosapi/srv/GetActionServers.srv b/rosapi/srv/GetActionServers.srv index 2965d95df..5a835e04b 100644 --- a/rosapi/srv/GetActionServers.srv +++ b/rosapi/srv/GetActionServers.srv @@ -1,3 +1,3 @@ --- -string[] action_servers \ No newline at end of file +string[] action_servers diff --git a/rosapi/srv/GetParam.srv b/rosapi/srv/GetParam.srv index f990926ea..cdbf3fd17 100644 --- a/rosapi/srv/GetParam.srv +++ b/rosapi/srv/GetParam.srv @@ -1,4 +1,4 @@ string name string default_value --- -string value \ No newline at end of file +string value diff --git a/rosapi/srv/GetParamNames.srv b/rosapi/srv/GetParamNames.srv index c52d403f0..536ee0c90 100644 --- a/rosapi/srv/GetParamNames.srv +++ b/rosapi/srv/GetParamNames.srv @@ -1,2 +1,2 @@ --- -string[] names \ No newline at end of file +string[] names diff --git a/rosapi/srv/GetTime.srv b/rosapi/srv/GetTime.srv index daa4c34b3..285ad7443 100644 --- a/rosapi/srv/GetTime.srv +++ b/rosapi/srv/GetTime.srv @@ -1,2 +1,2 @@ --- -builtin_interfaces/Time time \ No newline at end of file +builtin_interfaces/Time time diff --git a/rosapi/srv/HasParam.srv b/rosapi/srv/HasParam.srv index 97208275f..210c81eab 100644 --- a/rosapi/srv/HasParam.srv +++ b/rosapi/srv/HasParam.srv @@ -1,3 +1,3 @@ string name --- -bool exists \ No newline at end of file +bool exists diff --git a/rosapi/srv/MessageDetails.srv b/rosapi/srv/MessageDetails.srv index 449058429..722449676 100644 --- a/rosapi/srv/MessageDetails.srv +++ b/rosapi/srv/MessageDetails.srv @@ -1,3 +1,3 @@ string type --- -TypeDef[] typedefs \ No newline at end of file +TypeDef[] typedefs diff --git a/rosapi/srv/NodeDetails.srv b/rosapi/srv/NodeDetails.srv index 0f123ca46..7de5d39a4 100644 --- a/rosapi/srv/NodeDetails.srv +++ b/rosapi/srv/NodeDetails.srv @@ -2,4 +2,4 @@ string node --- string[] subscribing string[] publishing -string[] services \ No newline at end of file +string[] services diff --git a/rosapi/srv/Nodes.srv b/rosapi/srv/Nodes.srv index 3e6588319..3be5a63d1 100644 --- a/rosapi/srv/Nodes.srv +++ b/rosapi/srv/Nodes.srv @@ -1,3 +1,3 @@ --- -string[] nodes \ No newline at end of file +string[] nodes diff --git a/rosapi/srv/Publishers.srv b/rosapi/srv/Publishers.srv index 2e870b291..baaa8e434 100644 --- a/rosapi/srv/Publishers.srv +++ b/rosapi/srv/Publishers.srv @@ -1,3 +1,3 @@ string topic --- -string[] publishers \ No newline at end of file +string[] publishers diff --git a/rosapi/srv/SearchParam.srv b/rosapi/srv/SearchParam.srv index 22a85a393..59d1a48ef 100644 --- a/rosapi/srv/SearchParam.srv +++ b/rosapi/srv/SearchParam.srv @@ -1,3 +1,3 @@ string name --- -string global_name \ No newline at end of file +string global_name diff --git a/rosapi/srv/ServiceHost.srv b/rosapi/srv/ServiceHost.srv index 4d8d2b034..e5a055b61 100644 --- a/rosapi/srv/ServiceHost.srv +++ b/rosapi/srv/ServiceHost.srv @@ -1,3 +1,3 @@ string service --- -string host \ No newline at end of file +string host diff --git a/rosapi/srv/ServiceNode.srv b/rosapi/srv/ServiceNode.srv index 7d1ca6d9d..ac516bd22 100644 --- a/rosapi/srv/ServiceNode.srv +++ b/rosapi/srv/ServiceNode.srv @@ -1,3 +1,3 @@ string service --- -string node \ No newline at end of file +string node diff --git a/rosapi/srv/ServiceProviders.srv b/rosapi/srv/ServiceProviders.srv index b27e09016..789dc0d4c 100644 --- a/rosapi/srv/ServiceProviders.srv +++ b/rosapi/srv/ServiceProviders.srv @@ -1,3 +1,3 @@ string service --- -string[] providers \ No newline at end of file +string[] providers diff --git a/rosapi/srv/ServiceRequestDetails.srv b/rosapi/srv/ServiceRequestDetails.srv index 449058429..722449676 100644 --- a/rosapi/srv/ServiceRequestDetails.srv +++ b/rosapi/srv/ServiceRequestDetails.srv @@ -1,3 +1,3 @@ string type --- -TypeDef[] typedefs \ No newline at end of file +TypeDef[] typedefs diff --git a/rosapi/srv/ServiceResponseDetails.srv b/rosapi/srv/ServiceResponseDetails.srv index 449058429..722449676 100644 --- a/rosapi/srv/ServiceResponseDetails.srv +++ b/rosapi/srv/ServiceResponseDetails.srv @@ -1,3 +1,3 @@ string type --- -TypeDef[] typedefs \ No newline at end of file +TypeDef[] typedefs diff --git a/rosapi/srv/ServiceType.srv b/rosapi/srv/ServiceType.srv index ef9b76ec9..4c7e2ecaf 100644 --- a/rosapi/srv/ServiceType.srv +++ b/rosapi/srv/ServiceType.srv @@ -1,3 +1,3 @@ string service --- -string type \ No newline at end of file +string type diff --git a/rosapi/srv/Services.srv b/rosapi/srv/Services.srv index de84a3df6..5c44b4719 100644 --- a/rosapi/srv/Services.srv +++ b/rosapi/srv/Services.srv @@ -1,3 +1,3 @@ --- -string[] services \ No newline at end of file +string[] services diff --git a/rosapi/srv/ServicesForType.srv b/rosapi/srv/ServicesForType.srv index 02c88a15b..74085b0d3 100644 --- a/rosapi/srv/ServicesForType.srv +++ b/rosapi/srv/ServicesForType.srv @@ -1,3 +1,3 @@ string type --- -string[] services \ No newline at end of file +string[] services diff --git a/rosapi/srv/SetParam.srv b/rosapi/srv/SetParam.srv index 4f0fdb3b9..426e15cec 100644 --- a/rosapi/srv/SetParam.srv +++ b/rosapi/srv/SetParam.srv @@ -1,3 +1,3 @@ string name string value ---- \ No newline at end of file +--- diff --git a/rosapi/srv/Subscribers.srv b/rosapi/srv/Subscribers.srv index 2999d602d..cd893b4c9 100644 --- a/rosapi/srv/Subscribers.srv +++ b/rosapi/srv/Subscribers.srv @@ -1,3 +1,3 @@ string topic --- -string[] subscribers \ No newline at end of file +string[] subscribers diff --git a/rosapi/srv/TopicType.srv b/rosapi/srv/TopicType.srv index 8744d1f77..e08657a28 100644 --- a/rosapi/srv/TopicType.srv +++ b/rosapi/srv/TopicType.srv @@ -1,3 +1,3 @@ string topic --- -string type \ No newline at end of file +string type diff --git a/rosapi/srv/Topics.srv b/rosapi/srv/Topics.srv index 7a321a479..32765ea15 100644 --- a/rosapi/srv/Topics.srv +++ b/rosapi/srv/Topics.srv @@ -1,4 +1,4 @@ --- string[] topics -string[] types \ No newline at end of file +string[] types diff --git a/rosapi/srv/TopicsForType.srv b/rosapi/srv/TopicsForType.srv index 531a481e7..4afeaed32 100644 --- a/rosapi/srv/TopicsForType.srv +++ b/rosapi/srv/TopicsForType.srv @@ -1,3 +1,3 @@ string type --- -string[] topics \ No newline at end of file +string[] topics diff --git a/rosbridge_library/msg/TestChar.msg b/rosbridge_library/msg/TestChar.msg index 7aa8eba73..2ca013ff2 100644 --- a/rosbridge_library/msg/TestChar.msg +++ b/rosbridge_library/msg/TestChar.msg @@ -1 +1 @@ -char[] data \ No newline at end of file +char[] data diff --git a/rosbridge_library/msg/TestDurationArray.msg b/rosbridge_library/msg/TestDurationArray.msg index 20418c3e2..79581a2f1 100644 --- a/rosbridge_library/msg/TestDurationArray.msg +++ b/rosbridge_library/msg/TestDurationArray.msg @@ -1 +1 @@ -builtin_interfaces/Duration[] durations \ No newline at end of file +builtin_interfaces/Duration[] durations diff --git a/rosbridge_library/msg/TestHeader.msg b/rosbridge_library/msg/TestHeader.msg index 54c29d3f4..e3dee5e9c 100644 --- a/rosbridge_library/msg/TestHeader.msg +++ b/rosbridge_library/msg/TestHeader.msg @@ -1 +1 @@ -std_msgs/Header header \ No newline at end of file +std_msgs/Header header diff --git a/rosbridge_library/msg/TestHeaderArray.msg b/rosbridge_library/msg/TestHeaderArray.msg index d2d1845dc..0b6a85894 100644 --- a/rosbridge_library/msg/TestHeaderArray.msg +++ b/rosbridge_library/msg/TestHeaderArray.msg @@ -1 +1 @@ -std_msgs/Header[] header \ No newline at end of file +std_msgs/Header[] header diff --git a/rosbridge_library/msg/TestHeaderTwo.msg b/rosbridge_library/msg/TestHeaderTwo.msg index 54c29d3f4..e3dee5e9c 100644 --- a/rosbridge_library/msg/TestHeaderTwo.msg +++ b/rosbridge_library/msg/TestHeaderTwo.msg @@ -1 +1 @@ -std_msgs/Header header \ No newline at end of file +std_msgs/Header header diff --git a/rosbridge_library/msg/TestTimeArray.msg b/rosbridge_library/msg/TestTimeArray.msg index d66b397d9..a805a061a 100644 --- a/rosbridge_library/msg/TestTimeArray.msg +++ b/rosbridge_library/msg/TestTimeArray.msg @@ -1 +1 @@ -builtin_interfaces/Time[] times \ No newline at end of file +builtin_interfaces/Time[] times diff --git a/rosbridge_library/msg/TestUInt8.msg b/rosbridge_library/msg/TestUInt8.msg index 17350525d..dd2331bbe 100644 --- a/rosbridge_library/msg/TestUInt8.msg +++ b/rosbridge_library/msg/TestUInt8.msg @@ -1 +1 @@ -uint8[] data \ No newline at end of file +uint8[] data diff --git a/rosbridge_library/srv/TestArrayRequest.srv b/rosbridge_library/srv/TestArrayRequest.srv index 5efcdd322..25dcfcfe7 100644 --- a/rosbridge_library/srv/TestArrayRequest.srv +++ b/rosbridge_library/srv/TestArrayRequest.srv @@ -1,2 +1,2 @@ -int32[] int_values ---- \ No newline at end of file +int32[] int_values +--- diff --git a/rosbridge_library/srv/TestEmpty.srv b/rosbridge_library/srv/TestEmpty.srv index 73b314ff7..ed97d539c 100644 --- a/rosbridge_library/srv/TestEmpty.srv +++ b/rosbridge_library/srv/TestEmpty.srv @@ -1 +1 @@ ---- \ No newline at end of file +--- diff --git a/rosbridge_library/srv/TestMultipleRequestFields.srv b/rosbridge_library/srv/TestMultipleRequestFields.srv index d04306a1d..30ad12308 100644 --- a/rosbridge_library/srv/TestMultipleRequestFields.srv +++ b/rosbridge_library/srv/TestMultipleRequestFields.srv @@ -2,4 +2,4 @@ int32 int_value float32 float_value string string bool bool_value ---- \ No newline at end of file +--- diff --git a/rosbridge_library/srv/TestMultipleResponseFields.srv b/rosbridge_library/srv/TestMultipleResponseFields.srv index 6f743b8f9..78c777e8b 100644 --- a/rosbridge_library/srv/TestMultipleResponseFields.srv +++ b/rosbridge_library/srv/TestMultipleResponseFields.srv @@ -2,4 +2,4 @@ int32 int_value float32 float_value string string -bool bool_value \ No newline at end of file +bool bool_value diff --git a/rosbridge_library/srv/TestRequestAndResponse.srv b/rosbridge_library/srv/TestRequestAndResponse.srv index 7e8ddc8fb..f71ac402f 100644 --- a/rosbridge_library/srv/TestRequestAndResponse.srv +++ b/rosbridge_library/srv/TestRequestAndResponse.srv @@ -1,3 +1,3 @@ int32 data --- -int32 data \ No newline at end of file +int32 data diff --git a/rosbridge_library/srv/TestRequestOnly.srv b/rosbridge_library/srv/TestRequestOnly.srv index 78b05cf64..1b25cca17 100644 --- a/rosbridge_library/srv/TestRequestOnly.srv +++ b/rosbridge_library/srv/TestRequestOnly.srv @@ -1,2 +1,2 @@ -int32 data ---- \ No newline at end of file +int32 data +--- diff --git a/rosbridge_library/srv/TestResponseOnly.srv b/rosbridge_library/srv/TestResponseOnly.srv index 38597ecf2..91b71a0c7 100644 --- a/rosbridge_library/srv/TestResponseOnly.srv +++ b/rosbridge_library/srv/TestResponseOnly.srv @@ -1,2 +1,2 @@ ---- -int32 data \ No newline at end of file +--- +int32 data diff --git a/rosbridge_library/test/test_all.test b/rosbridge_library/test/test_all.test index f4b054288..270e16875 100644 --- a/rosbridge_library/test/test_all.test +++ b/rosbridge_library/test/test_all.test @@ -2,4 +2,3 @@ - From 1238d76732f9a52fccafbc98a5dbb129b435a5b5 Mon Sep 17 00:00:00 2001 From: Kenji Miyake Date: Sat, 25 Sep 2021 03:16:24 +0900 Subject: [PATCH 4/7] Add isort Signed-off-by: Kenji Miyake --- .pre-commit-config.yaml | 6 ++++++ setup.cfg | 3 +++ 2 files changed, 9 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ef4064acc..59f1b8718 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,3 +38,9 @@ repos: rev: 21.9b0 hooks: - id: black + + - repo: https://github.com/pycqa/isort + rev: 5.8.0 + hooks: + - id: isort + name: isort (python) diff --git a/setup.cfg b/setup.cfg index 77879a209..f5ad3af0f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,3 +7,6 @@ max-complexity = 36 max-line-length = 228 select = C,E262,E266,E4,E5,E7,E9,F4,F5,F6,F7,F81,F82,F83,F9,W1,W6 show-source = True + +[isort] +profile=black From a7baaefd34bc110424e9c6cde400b924e08feb47 Mon Sep 17 00:00:00 2001 From: Kenji Miyake Date: Sat, 25 Sep 2021 03:16:28 +0900 Subject: [PATCH 5/7] Apply isort Signed-off-by: Kenji Miyake --- rosapi/scripts/rosapi_node | 4 +-- rosapi/src/rosapi/glob_helper.py | 3 +- rosapi/src/rosapi/objectutils.py | 3 +- rosapi/src/rosapi/params.py | 6 ++-- rosapi/src/rosapi/proxy.py | 2 +- rosapi/src/rosapi/stringify_field_types.py | 2 +- .../capabilities/advertise.py | 1 + .../capabilities/advertise_service.py | 6 ++-- .../capabilities/call_service.py | 1 + .../capabilities/defragmentation.py | 5 +-- .../capabilities/fragmentation.py | 3 +- .../rosbridge_library/capabilities/publish.py | 1 + .../capabilities/service_response.py | 2 +- .../capabilities/subscribe.py | 5 +-- .../capabilities/unadvertise_service.py | 1 + .../src/rosbridge_library/capability.py | 6 ++-- .../internal/message_conversion.py | 14 ++++---- .../internal/outgoing_message.py | 2 +- .../internal/pngcompression.py | 7 ++-- .../rosbridge_library/internal/publishers.py | 5 +-- .../rosbridge_library/internal/services.py | 13 ++++--- .../rosbridge_library/internal/subscribers.py | 6 ++-- .../internal/subscription_modifiers.py | 2 +- .../src/rosbridge_library/protocol.py | 2 +- .../rosbridge_library/rosbridge_protocol.py | 14 ++++---- .../src/rosbridge_library/util/cbor.py | 2 -- .../test/capabilities/test_advertise.py | 15 ++++---- .../test/capabilities/test_call_service.py | 16 ++++----- .../test/capabilities/test_publish.py | 12 +++---- .../capabilities/test_service_capabilities.py | 11 +++--- .../test/capabilities/test_subscribe.py | 13 ++++--- ...test_non-ros_service_client_complex-srv.py | 2 +- ...test_non-ros_service_server_complex-srv.py | 4 +-- .../test_non-ros_service_client_fragmented.py | 2 +- .../test_non-ros_service_server_fragmented.py | 4 +-- .../publishers/test_multi_publisher.py | 9 +++-- .../publishers/test_multi_unregistering.py | 7 ++-- .../publishers/test_publisher_manager.py | 7 ++-- .../subscribers/test_multi_subscriber.py | 9 +++-- .../subscribers/test_subscriber_manager.py | 7 ++-- .../test_subscription_modifiers.py | 6 ++-- .../test/internal/test_cbor_conversion.py | 36 +++++++++---------- .../test/internal/test_compression.py | 4 +-- .../test/internal/test_message_conversion.py | 9 +++-- .../test/internal/test_outgoing_message.py | 1 - .../test/internal/test_ros_loader.py | 4 +-- .../test/internal/test_services.py | 11 +++--- rosbridge_server/scripts/rosbridge_tcp.py | 14 ++++---- rosbridge_server/scripts/rosbridge_udp.py | 13 ++++--- .../scripts/rosbridge_websocket.py | 23 ++++++------ .../src/rosbridge_server/__init__.py | 2 +- .../src/rosbridge_server/client_mananger.py | 4 +-- .../src/rosbridge_server/tcp_handler.py | 3 +- .../src/rosbridge_server/udp_handler.py | 1 - .../src/rosbridge_server/websocket_handler.py | 9 +++-- rosbridge_server/test/websocket/smoke.test.py | 9 +++-- 56 files changed, 189 insertions(+), 196 deletions(-) diff --git a/rosapi/scripts/rosapi_node b/rosapi/scripts/rosapi_node index 5011c457c..50b33a9e5 100755 --- a/rosapi/scripts/rosapi_node +++ b/rosapi/scripts/rosapi_node @@ -37,9 +37,9 @@ import rclpy from rclpy.clock import Clock, ClockType from rclpy.node import Node -from rosapi import glob_helper, proxy, objectutils, params -from rosapi.srv import * +from rosapi import glob_helper, objectutils, params, proxy from rosapi.msg import * +from rosapi.srv import * class Rosapi(Node): diff --git a/rosapi/src/rosapi/glob_helper.py b/rosapi/src/rosapi/glob_helper.py index 0e52e39db..04a04ecbc 100644 --- a/rosapi/src/rosapi/glob_helper.py +++ b/rosapi/src/rosapi/glob_helper.py @@ -1,7 +1,8 @@ #!/usr/bin/env python -from collections import namedtuple import fnmatch +from collections import namedtuple + from rcl_interfaces.msg import ParameterType Globs = namedtuple("Globs", ["topics", "services", "params"]) diff --git a/rosapi/src/rosapi/objectutils.py b/rosapi/src/rosapi/objectutils.py index 0f825e4e1..1944c5336 100644 --- a/rosapi/src/rosapi/objectutils.py +++ b/rosapi/src/rosapi/objectutils.py @@ -31,9 +31,10 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. +import inspect + from rosapi.stringify_field_types import stringify_field_types from rosbridge_library.internal import ros_loader -import inspect # Keep track of atomic types and special types atomics = [ diff --git a/rosapi/src/rosapi/params.py b/rosapi/src/rosapi/params.py index f7015b25b..597e7246b 100644 --- a/rosapi/src/rosapi/params.py +++ b/rosapi/src/rosapi/params.py @@ -31,18 +31,16 @@ # POSSIBILITY OF SUCH DAMAGE. import fnmatch -from json import loads, dumps import threading +from json import dumps, loads +import rclpy from rcl_interfaces.msg import Parameter, ParameterType, ParameterValue from rcl_interfaces.srv import ListParameters -import rclpy from ros2node.api import get_absolute_node_name from ros2param.api import call_get_parameters, call_set_parameters, get_parameter_value - from rosapi.proxy import get_nodes - """ Methods to interact with the param server. Values have to be passed as JSON in order to facilitate dynamically typed SRV messages """ diff --git a/rosapi/src/rosapi/proxy.py b/rosapi/src/rosapi/proxy.py index ec10a64d4..f7a23795c 100644 --- a/rosapi/src/rosapi/proxy.py +++ b/rosapi/src/rosapi/proxy.py @@ -40,7 +40,7 @@ from ros2service.api import get_service_names, get_service_names_and_types from ros2topic.api import get_topic_names, get_topic_names_and_types -from .glob_helper import filter_globs, any_match +from .glob_helper import any_match, filter_globs _node = None diff --git a/rosapi/src/rosapi/stringify_field_types.py b/rosapi/src/rosapi/stringify_field_types.py index f6b280d6e..10d4288ec 100644 --- a/rosapi/src/rosapi/stringify_field_types.py +++ b/rosapi/src/rosapi/stringify_field_types.py @@ -1,5 +1,5 @@ -from rosidl_runtime_py import get_interface_path from rosidl_adapter.parser import parse_message_string +from rosidl_runtime_py import get_interface_path def stringify_field_types(root_type): diff --git a/rosbridge_library/src/rosbridge_library/capabilities/advertise.py b/rosbridge_library/src/rosbridge_library/capabilities/advertise.py index a3660da80..f3f95b854 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/advertise.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/advertise.py @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. import fnmatch + from rosbridge_library.capability import Capability from rosbridge_library.internal.publishers import manager diff --git a/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py b/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py index ed4f99a4b..de38f4edf 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py @@ -1,10 +1,10 @@ import fnmatch -from threading import Lock import time +from threading import Lock -from rosbridge_library.internal.ros_loader import get_service_class -from rosbridge_library.internal import message_conversion from rosbridge_library.capability import Capability +from rosbridge_library.internal import message_conversion +from rosbridge_library.internal.ros_loader import get_service_class class AdvertisedServiceHandler: diff --git a/rosbridge_library/src/rosbridge_library/capabilities/call_service.py b/rosbridge_library/src/rosbridge_library/capabilities/call_service.py index ddfc71e84..e8c0dd443 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/call_service.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/call_service.py @@ -32,6 +32,7 @@ import fnmatch from functools import partial + from rosbridge_library.capability import Capability from rosbridge_library.internal.services import ServiceCaller diff --git a/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py b/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py index 6b7e7452f..1d309ccd2 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py @@ -1,6 +1,7 @@ -from rosbridge_library.capability import Capability -from datetime import datetime import threading +from datetime import datetime + +from rosbridge_library.capability import Capability class ReceivedFragments: diff --git a/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py b/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py index da376cc8f..cd2294bec 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py @@ -30,9 +30,10 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from rosbridge_library.capability import Capability import math +from rosbridge_library.capability import Capability + class Fragmentation(Capability): """The Fragmentation capability doesn't define any incoming operation diff --git a/rosbridge_library/src/rosbridge_library/capabilities/publish.py b/rosbridge_library/src/rosbridge_library/capabilities/publish.py index fdd44febc..6efadb06b 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/publish.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/publish.py @@ -32,6 +32,7 @@ # POSSIBILITY OF SUCH DAMAGE. import fnmatch + from rosbridge_library.capability import Capability from rosbridge_library.internal.publishers import manager diff --git a/rosbridge_library/src/rosbridge_library/capabilities/service_response.py b/rosbridge_library/src/rosbridge_library/capabilities/service_response.py index e7ebb6809..96cacfcd4 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/service_response.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/service_response.py @@ -1,5 +1,5 @@ from rosbridge_library.capability import Capability -from rosbridge_library.internal import ros_loader, message_conversion +from rosbridge_library.internal import message_conversion, ros_loader class ServiceResponse(Capability): diff --git a/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py b/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py index efb9d7dfd..598a639ff 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py @@ -31,12 +31,13 @@ # POSSIBILITY OF SUCH DAMAGE. import fnmatch -from threading import Lock from functools import partial +from threading import Lock + from rosbridge_library.capability import Capability +from rosbridge_library.internal.pngcompression import encode as encode_png from rosbridge_library.internal.subscribers import manager from rosbridge_library.internal.subscription_modifiers import MessageHandler -from rosbridge_library.internal.pngcompression import encode as encode_png try: from cbor import dumps as encode_cbor diff --git a/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py b/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py index 0790a05c6..1f28fb346 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py @@ -1,4 +1,5 @@ import fnmatch + from rosbridge_library.capability import Capability diff --git a/rosbridge_library/src/rosbridge_library/capability.py b/rosbridge_library/src/rosbridge_library/capability.py index 0fe0cc73a..5415b719e 100644 --- a/rosbridge_library/src/rosbridge_library/capability.py +++ b/rosbridge_library/src/rosbridge_library/capability.py @@ -30,8 +30,10 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from rosbridge_library.internal.exceptions import InvalidArgumentException -from rosbridge_library.internal.exceptions import MissingArgumentException +from rosbridge_library.internal.exceptions import ( + InvalidArgumentException, + MissingArgumentException, +) class Capability: diff --git a/rosbridge_library/src/rosbridge_library/internal/message_conversion.py b/rosbridge_library/src/rosbridge_library/internal/message_conversion.py index adff2c1a1..4417068c6 100644 --- a/rosbridge_library/src/rosbridge_library/internal/message_conversion.py +++ b/rosbridge_library/src/rosbridge_library/internal/message_conversion.py @@ -31,18 +31,16 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -import rclpy -from rclpy.clock import ROSClock -import numpy as np import array - -from rcl_interfaces.msg import Parameter -from rosbridge_library.internal import ros_loader - import math import re -from base64 import standard_b64encode, standard_b64decode +from base64 import standard_b64decode, standard_b64encode +import numpy as np +import rclpy +from rcl_interfaces.msg import Parameter +from rclpy.clock import ROSClock +from rosbridge_library.internal import ros_loader from rosbridge_library.util import bson try: diff --git a/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py b/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py index 2ee306d5f..22902df30 100644 --- a/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py +++ b/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py @@ -1,7 +1,7 @@ +from rosbridge_library.internal.cbor_conversion import extract_cbor_values from rosbridge_library.internal.message_conversion import ( extract_values as extract_json_values, ) -from rosbridge_library.internal.cbor_conversion import extract_cbor_values class OutgoingMessage: diff --git a/rosbridge_library/src/rosbridge_library/internal/pngcompression.py b/rosbridge_library/src/rosbridge_library/internal/pngcompression.py index 9ed4b1c7a..a705fdd8e 100644 --- a/rosbridge_library/src/rosbridge_library/internal/pngcompression.py +++ b/rosbridge_library/src/rosbridge_library/internal/pngcompression.py @@ -30,10 +30,11 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from PIL import Image -from base64 import standard_b64encode, standard_b64decode +from base64 import standard_b64decode, standard_b64encode from io import StringIO -from math import floor, ceil, sqrt +from math import ceil, floor, sqrt + +from PIL import Image def encode(string): diff --git a/rosbridge_library/src/rosbridge_library/internal/publishers.py b/rosbridge_library/src/rosbridge_library/internal/publishers.py index 025fb311e..9507486f5 100644 --- a/rosbridge_library/src/rosbridge_library/internal/publishers.py +++ b/rosbridge_library/src/rosbridge_library/internal/publishers.py @@ -32,9 +32,10 @@ # POSSIBILITY OF SUCH DAMAGE. from threading import Timer + from rclpy.duration import Duration -from rclpy.qos import QoSProfile, QoSDurabilityPolicy -from rosbridge_library.internal import ros_loader, message_conversion +from rclpy.qos import QoSDurabilityPolicy, QoSProfile +from rosbridge_library.internal import message_conversion, ros_loader from rosbridge_library.internal.message_conversion import msg_class_type_repr from rosbridge_library.internal.topics import ( TopicNotEstablishedException, diff --git a/rosbridge_library/src/rosbridge_library/internal/services.py b/rosbridge_library/src/rosbridge_library/internal/services.py index 30bac0b39..2d52261b4 100644 --- a/rosbridge_library/src/rosbridge_library/internal/services.py +++ b/rosbridge_library/src/rosbridge_library/internal/services.py @@ -31,12 +31,17 @@ # POSSIBILITY OF SUCH DAMAGE. from threading import Thread + from rclpy import spin_until_future_complete from rclpy.expand_topic_name import expand_topic_name -from rosbridge_library.internal.ros_loader import get_service_class -from rosbridge_library.internal.ros_loader import get_service_request_instance -from rosbridge_library.internal.message_conversion import populate_instance -from rosbridge_library.internal.message_conversion import extract_values +from rosbridge_library.internal.message_conversion import ( + extract_values, + populate_instance, +) +from rosbridge_library.internal.ros_loader import ( + get_service_class, + get_service_request_instance, +) class InvalidServiceException(Exception): diff --git a/rosbridge_library/src/rosbridge_library/internal/subscribers.py b/rosbridge_library/src/rosbridge_library/internal/subscribers.py index f6a308a25..c8a26ce6d 100644 --- a/rosbridge_library/src/rosbridge_library/internal/subscribers.py +++ b/rosbridge_library/src/rosbridge_library/internal/subscribers.py @@ -35,9 +35,11 @@ from rosbridge_library.internal import ros_loader from rosbridge_library.internal.message_conversion import msg_class_type_repr -from rosbridge_library.internal.topics import TopicNotEstablishedException -from rosbridge_library.internal.topics import TypeConflictException from rosbridge_library.internal.outgoing_message import OutgoingMessage +from rosbridge_library.internal.topics import ( + TopicNotEstablishedException, + TypeConflictException, +) """ Manages and interfaces with ROS Subscriber objects. A single subscriber is shared between multiple clients diff --git a/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py b/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py index fdd01e8af..3f6c4a0e1 100644 --- a/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py +++ b/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py @@ -30,7 +30,7 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from threading import Thread, Condition +from threading import Condition, Thread from time import time """ Sits between incoming messages from a subscription, and the outgoing diff --git a/rosbridge_library/src/rosbridge_library/protocol.py b/rosbridge_library/src/rosbridge_library/protocol.py index 595781914..dd431ccd4 100644 --- a/rosbridge_library/src/rosbridge_library/protocol.py +++ b/rosbridge_library/src/rosbridge_library/protocol.py @@ -33,7 +33,7 @@ import time from rosbridge_library.capabilities.fragmentation import Fragmentation -from rosbridge_library.util import json, bson +from rosbridge_library.util import bson, json def is_number(s): diff --git a/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py b/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py index ed0f0c27a..f8dca1b8b 100644 --- a/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py +++ b/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py @@ -30,19 +30,19 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from rosbridge_library.protocol import Protocol -from rosbridge_library.capabilities.call_service import CallService from rosbridge_library.capabilities.advertise import Advertise -from rosbridge_library.capabilities.publish import Publish -from rosbridge_library.capabilities.subscribe import Subscribe - -# imports for defragmentation -from rosbridge_library.capabilities.defragmentation import Defragment # imports for external service_server from rosbridge_library.capabilities.advertise_service import AdvertiseService +from rosbridge_library.capabilities.call_service import CallService + +# imports for defragmentation +from rosbridge_library.capabilities.defragmentation import Defragment +from rosbridge_library.capabilities.publish import Publish from rosbridge_library.capabilities.service_response import ServiceResponse +from rosbridge_library.capabilities.subscribe import Subscribe from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService +from rosbridge_library.protocol import Protocol class RosbridgeProtocol(Protocol): diff --git a/rosbridge_library/src/rosbridge_library/util/cbor.py b/rosbridge_library/src/rosbridge_library/util/cbor.py index ce67adcf3..656fc7c4e 100644 --- a/rosbridge_library/src/rosbridge_library/util/cbor.py +++ b/rosbridge_library/src/rosbridge_library/util/cbor.py @@ -17,10 +17,8 @@ import datetime import re import struct - from io import BytesIO - CBOR_TYPE_MASK = 0xE0 # top 3 bits CBOR_INFO_BITS = 0x1F # low 5 bits diff --git a/rosbridge_library/test/capabilities/test_advertise.py b/rosbridge_library/test/capabilities/test_advertise.py index 267601acc..8e859ffeb 100755 --- a/rosbridge_library/test/capabilities/test_advertise.py +++ b/rosbridge_library/test/capabilities/test_advertise.py @@ -1,19 +1,18 @@ #!/usr/bin/env python -import rospy -import rostest import unittest +from json import dumps, loads from time import sleep -from rosbridge_library.protocol import Protocol +import rospy +import rostest +from rosbridge_library.capabilities.advertise import Advertise +from rosbridge_library.internal import ros_loader +from rosbridge_library.internal.publishers import manager from rosbridge_library.protocol import ( InvalidArgumentException, MissingArgumentException, + Protocol, ) -from rosbridge_library.capabilities.advertise import Advertise -from rosbridge_library.internal.publishers import manager -from rosbridge_library.internal import ros_loader - -from json import loads, dumps class TestAdvertise(unittest.TestCase): diff --git a/rosbridge_library/test/capabilities/test_call_service.py b/rosbridge_library/test/capabilities/test_call_service.py index c5b903eed..e3398d8c7 100755 --- a/rosbridge_library/test/capabilities/test_call_service.py +++ b/rosbridge_library/test/capabilities/test_call_service.py @@ -1,20 +1,18 @@ #!/usr/bin/env python -import rospy -import rostest -import unittest import time +import unittest +from json import dumps, loads -from roscpp.srv import GetLoggers - -from json import loads, dumps -from std_srvs.srv import SetBool - +import rospy +import rostest from rosbridge_library.capabilities.call_service import CallService -from rosbridge_library.protocol import Protocol from rosbridge_library.protocol import ( InvalidArgumentException, MissingArgumentException, + Protocol, ) +from roscpp.srv import GetLoggers +from std_srvs.srv import SetBool class TestCallService(unittest.TestCase): diff --git a/rosbridge_library/test/capabilities/test_publish.py b/rosbridge_library/test/capabilities/test_publish.py index 117eda458..3e43a6b7a 100755 --- a/rosbridge_library/test/capabilities/test_publish.py +++ b/rosbridge_library/test/capabilities/test_publish.py @@ -1,20 +1,18 @@ #!/usr/bin/env python -import rospy -import rostest import unittest +from json import dumps, loads from time import sleep -from rosbridge_library.protocol import Protocol +import rospy +import rostest +from rosbridge_library.capabilities.publish import Publish from rosbridge_library.protocol import ( InvalidArgumentException, MissingArgumentException, + Protocol, ) -from rosbridge_library.capabilities.publish import Publish - from std_msgs.msg import String -from json import dumps, loads - class TestAdvertise(unittest.TestCase): def setUp(self): diff --git a/rosbridge_library/test/capabilities/test_service_capabilities.py b/rosbridge_library/test/capabilities/test_service_capabilities.py index 26793aea6..892c7c6ae 100755 --- a/rosbridge_library/test/capabilities/test_service_capabilities.py +++ b/rosbridge_library/test/capabilities/test_service_capabilities.py @@ -1,18 +1,17 @@ #!/usr/bin/env python -import rospy -import rostest import unittest +from json import dumps, loads -from json import loads, dumps - +import rospy +import rostest from rosbridge_library.capabilities.advertise_service import AdvertiseService -from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService from rosbridge_library.capabilities.call_service import CallService from rosbridge_library.capabilities.service_response import ServiceResponse -from rosbridge_library.protocol import Protocol +from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService from rosbridge_library.protocol import ( InvalidArgumentException, MissingArgumentException, + Protocol, ) diff --git a/rosbridge_library/test/capabilities/test_subscribe.py b/rosbridge_library/test/capabilities/test_subscribe.py index 628536a3a..2c48713d3 100755 --- a/rosbridge_library/test/capabilities/test_subscribe.py +++ b/rosbridge_library/test/capabilities/test_subscribe.py @@ -1,18 +1,17 @@ #!/usr/bin/env python -import rospy -import rostest -import unittest import time +import unittest +from json import dumps, loads -from json import loads, dumps -from std_msgs.msg import String - +import rospy +import rostest from rosbridge_library.capabilities import subscribe -from rosbridge_library.protocol import Protocol from rosbridge_library.protocol import ( InvalidArgumentException, MissingArgumentException, + Protocol, ) +from std_msgs.msg import String class TestSubscribe(unittest.TestCase): diff --git a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py index 859f3c9e8..96107dc89 100755 --- a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py +++ b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py @@ -1,7 +1,7 @@ #!/usr/bin/python import socket -from rosbridge_library.util import json +from rosbridge_library.util import json # ##################### variables begin ######################################## # these parameters should be changed to match the actual environment # diff --git a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py index 209e7d2e0..1a0e157b9 100755 --- a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py +++ b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py @@ -1,10 +1,10 @@ #!/usr/bin/python -import sys import socket +import sys import time from random import randint -from rosbridge_library.util import json +from rosbridge_library.util import json # ##################### variables begin ######################################## # these parameters should be changed to match the actual environment # diff --git a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py index baddd7a00..688cfa01f 100755 --- a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py +++ b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py @@ -1,7 +1,7 @@ #!/usr/bin/python import socket -from rosbridge_library.util import json +from rosbridge_library.util import json # ##################### variables begin ######################################## # these parameters should be changed to match the actual environment # diff --git a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py index 0a058d6bf..2ed08b254 100755 --- a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py +++ b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py @@ -1,10 +1,10 @@ #!/usr/bin/python -import sys import socket +import sys import time from random import randint -from rosbridge_library.util import json +from rosbridge_library.util import json # ##################### variables begin ######################################## # these parameters should be changed to match the actual environment # diff --git a/rosbridge_library/test/internal/publishers/test_multi_publisher.py b/rosbridge_library/test/internal/publishers/test_multi_publisher.py index ead677ae2..aad200196 100755 --- a/rosbridge_library/test/internal/publishers/test_multi_publisher.py +++ b/rosbridge_library/test/internal/publishers/test_multi_publisher.py @@ -1,14 +1,13 @@ #!/usr/bin/env python -import rospy -import rostest import unittest - from time import sleep -from rosbridge_library.internal.publishers import MultiPublisher -from rosbridge_library.internal.topics import TypeConflictException +import rospy +import rostest from rosbridge_library.internal import ros_loader from rosbridge_library.internal.message_conversion import FieldTypeMismatchException +from rosbridge_library.internal.publishers import MultiPublisher +from rosbridge_library.internal.topics import TypeConflictException class TestMultiPublisher(unittest.TestCase): diff --git a/rosbridge_library/test/internal/publishers/test_multi_unregistering.py b/rosbridge_library/test/internal/publishers/test_multi_unregistering.py index 6c892b7bc..896b1bf68 100755 --- a/rosbridge_library/test/internal/publishers/test_multi_unregistering.py +++ b/rosbridge_library/test/internal/publishers/test_multi_unregistering.py @@ -1,12 +1,11 @@ #!/usr/bin/env python -import rospy -import rostest import unittest - from time import sleep -from rosbridge_library.internal.publishers import MultiPublisher +import rospy +import rostest from rosbridge_library.internal import ros_loader +from rosbridge_library.internal.publishers import MultiPublisher class TestMultiUnregistering(unittest.TestCase): diff --git a/rosbridge_library/test/internal/publishers/test_publisher_manager.py b/rosbridge_library/test/internal/publishers/test_publisher_manager.py index 82f9d7887..fd653913a 100755 --- a/rosbridge_library/test/internal/publishers/test_publisher_manager.py +++ b/rosbridge_library/test/internal/publishers/test_publisher_manager.py @@ -1,16 +1,15 @@ #!/usr/bin/env python -import rospy -import rostest import unittest - from time import sleep +import rospy +import rostest +from rosbridge_library.internal.message_conversion import FieldTypeMismatchException from rosbridge_library.internal.publishers import manager from rosbridge_library.internal.topics import ( TopicNotEstablishedException, TypeConflictException, ) -from rosbridge_library.internal.message_conversion import FieldTypeMismatchException from std_msgs.msg import String diff --git a/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py b/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py index dce75f4f2..915b92f93 100755 --- a/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py +++ b/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py @@ -1,14 +1,13 @@ #!/usr/bin/env python -import rospy -import rostest import unittest -from rosgraph import Master - from time import sleep +import rospy +import rostest from rosbridge_library.internal.subscribers import MultiSubscriber from rosbridge_library.internal.topics import TypeConflictException -from std_msgs.msg import String, Int32 +from rosgraph import Master +from std_msgs.msg import Int32, String class TestMultiSubscriber(unittest.TestCase): diff --git a/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py b/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py index 16c36ec82..7034c9bb2 100755 --- a/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py +++ b/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py @@ -1,16 +1,15 @@ #!/usr/bin/env python -import rospy -import rostest import unittest -from rosgraph import Master - from time import sleep +import rospy +import rostest from rosbridge_library.internal.subscribers import manager from rosbridge_library.internal.topics import ( TopicNotEstablishedException, TypeConflictException, ) +from rosgraph import Master from std_msgs.msg import String diff --git a/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py b/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py index a1f26a5dd..bf1d4412e 100755 --- a/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py +++ b/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py @@ -1,9 +1,9 @@ #!/usr/bin/env python -import rospy -import rostest -import unittest import time +import unittest +import rospy +import rostest from rosbridge_library.internal import subscription_modifiers as subscribe diff --git a/rosbridge_library/test/internal/test_cbor_conversion.py b/rosbridge_library/test/internal/test_cbor_conversion.py index 05271356c..a59788c31 100755 --- a/rosbridge_library/test/internal/test_cbor_conversion.py +++ b/rosbridge_library/test/internal/test_cbor_conversion.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 -import rostest +import struct import unittest -import struct +import rostest from rosbridge_library.internal.cbor_conversion import ( - extract_cbor_values, TAGGED_ARRAY_FORMATS, + extract_cbor_values, ) try: @@ -15,31 +15,31 @@ from std_msgs.msg import ( Bool, - String, - Int8, - Int16, - Int32, - Int64, - UInt8, - UInt16, - UInt32, - UInt64, + Duration, Float32, + Float32MultiArray, Float64, + Float64MultiArray, + Int8, Int8MultiArray, + Int16, Int16MultiArray, + Int32, Int32MultiArray, + Int64, Int64MultiArray, + MultiArrayDimension, + MultiArrayLayout, + String, + Time, + UInt8, UInt8MultiArray, + UInt16, UInt16MultiArray, + UInt32, UInt32MultiArray, + UInt64, UInt64MultiArray, - Float32MultiArray, - Float64MultiArray, - Time, - Duration, - MultiArrayLayout, - MultiArrayDimension, ) diff --git a/rosbridge_library/test/internal/test_compression.py b/rosbridge_library/test/internal/test_compression.py index 36a4f5608..7e5ebfcfb 100755 --- a/rosbridge_library/test/internal/test_compression.py +++ b/rosbridge_library/test/internal/test_compression.py @@ -1,8 +1,8 @@ #!/usr/bin/env python -import rospy -import rostest import unittest +import rospy +import rostest from rosbridge_library.internal import pngcompression diff --git a/rosbridge_library/test/internal/test_message_conversion.py b/rosbridge_library/test/internal/test_message_conversion.py index 54d8dbeca..9868fd34a 100755 --- a/rosbridge_library/test/internal/test_message_conversion.py +++ b/rosbridge_library/test/internal/test_message_conversion.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 -import rospy -import rostest import unittest -from json import loads, dumps - +from base64 import standard_b64encode from io import BytesIO +from json import dumps, loads +import rospy +import rostest from rosbridge_library.internal import message_conversion as c from rosbridge_library.internal import ros_loader -from base64 import standard_b64encode class TestMessageConversion(unittest.TestCase): diff --git a/rosbridge_library/test/internal/test_outgoing_message.py b/rosbridge_library/test/internal/test_outgoing_message.py index 66caa4c9e..08d6cf601 100755 --- a/rosbridge_library/test/internal/test_outgoing_message.py +++ b/rosbridge_library/test/internal/test_outgoing_message.py @@ -2,7 +2,6 @@ import unittest import rostest - from rosbridge_library.internal.outgoing_message import OutgoingMessage from std_msgs.msg import String diff --git a/rosbridge_library/test/internal/test_ros_loader.py b/rosbridge_library/test/internal/test_ros_loader.py index b63f9bcf9..768bf0af1 100755 --- a/rosbridge_library/test/internal/test_ros_loader.py +++ b/rosbridge_library/test/internal/test_ros_loader.py @@ -1,8 +1,8 @@ #!/usr/bin/env python -import rospy -import rostest import unittest +import rospy +import rostest from rosbridge_library.internal import ros_loader diff --git a/rosbridge_library/test/internal/test_services.py b/rosbridge_library/test/internal/test_services.py index fd0ca5c5f..90990ac18 100755 --- a/rosbridge_library/test/internal/test_services.py +++ b/rosbridge_library/test/internal/test_services.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 -import rospy -import rostest -import unittest -import time import random +import time +import unittest -from rosbridge_library.internal import services, ros_loader +import rospy +import rostest from rosbridge_library.internal import message_conversion as c +from rosbridge_library.internal import ros_loader, services from rosbridge_library.internal.message_conversion import FieldTypeMismatchException - from roscpp.srv import GetLoggers diff --git a/rosbridge_server/scripts/rosbridge_tcp.py b/rosbridge_server/scripts/rosbridge_tcp.py index 52e3473c2..b265d5d84 100755 --- a/rosbridge_server/scripts/rosbridge_tcp.py +++ b/rosbridge_server/scripts/rosbridge_tcp.py @@ -1,19 +1,19 @@ #!/usr/bin/env python -from rospy import init_node, get_param, loginfo, on_shutdown, Publisher -from rosbridge_server import RosbridgeTcpSocket +from functools import partial +from signal import SIG_DFL, SIGINT, signal from rosbridge_library.capabilities.advertise import Advertise +from rosbridge_library.capabilities.advertise_service import AdvertiseService +from rosbridge_library.capabilities.call_service import CallService from rosbridge_library.capabilities.publish import Publish from rosbridge_library.capabilities.subscribe import Subscribe -from rosbridge_library.capabilities.advertise_service import AdvertiseService from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService -from rosbridge_library.capabilities.call_service import CallService - -from functools import partial -from signal import signal, SIGINT, SIG_DFL +from rospy import Publisher, get_param, init_node, loginfo, on_shutdown from std_msgs.msg import Int32 +from rosbridge_server import RosbridgeTcpSocket + try: import SocketServer except ImportError: diff --git a/rosbridge_server/scripts/rosbridge_udp.py b/rosbridge_server/scripts/rosbridge_udp.py index eb82ca4e6..18b5c7b23 100755 --- a/rosbridge_server/scripts/rosbridge_udp.py +++ b/rosbridge_server/scripts/rosbridge_udp.py @@ -31,20 +31,19 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -import rospy import sys -from twisted.internet import reactor -from rosbridge_server import RosbridgeUdpSocket, RosbridgeUdpFactory - +import rospy from rosbridge_library.capabilities.advertise import Advertise +from rosbridge_library.capabilities.advertise_service import AdvertiseService +from rosbridge_library.capabilities.call_service import CallService from rosbridge_library.capabilities.publish import Publish from rosbridge_library.capabilities.subscribe import Subscribe -from rosbridge_library.capabilities.advertise_service import AdvertiseService from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService -from rosbridge_library.capabilities.call_service import CallService - from std_msgs.msg import Int32 +from twisted.internet import reactor + +from rosbridge_server import RosbridgeUdpFactory, RosbridgeUdpSocket def shutdown_hook(): diff --git a/rosbridge_server/scripts/rosbridge_websocket.py b/rosbridge_server/scripts/rosbridge_websocket.py index e56359014..f1e80fb48 100755 --- a/rosbridge_server/scripts/rosbridge_websocket.py +++ b/rosbridge_server/scripts/rosbridge_websocket.py @@ -35,25 +35,22 @@ import sys import time -from tornado.httpserver import HTTPServer -from tornado.ioloop import IOLoop -from tornado.ioloop import PeriodicCallback -from tornado.netutil import bind_sockets -from tornado.web import Application - import rclpy from rclpy.node import Node -from rclpy.qos import QoSProfile, QoSDurabilityPolicy -from std_msgs.msg import Int32 - -from rosbridge_server import RosbridgeWebSocket, ClientManager - +from rclpy.qos import QoSDurabilityPolicy, QoSProfile from rosbridge_library.capabilities.advertise import Advertise +from rosbridge_library.capabilities.advertise_service import AdvertiseService +from rosbridge_library.capabilities.call_service import CallService from rosbridge_library.capabilities.publish import Publish from rosbridge_library.capabilities.subscribe import Subscribe -from rosbridge_library.capabilities.advertise_service import AdvertiseService from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService -from rosbridge_library.capabilities.call_service import CallService +from std_msgs.msg import Int32 +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop, PeriodicCallback +from tornado.netutil import bind_sockets +from tornado.web import Application + +from rosbridge_server import ClientManager, RosbridgeWebSocket def start_hook(): diff --git a/rosbridge_server/src/rosbridge_server/__init__.py b/rosbridge_server/src/rosbridge_server/__init__.py index 4a70df2c4..611f94f09 100644 --- a/rosbridge_server/src/rosbridge_server/__init__.py +++ b/rosbridge_server/src/rosbridge_server/__init__.py @@ -1,5 +1,5 @@ -from .websocket_handler import RosbridgeWebSocket # noqa: F401 from .client_mananger import ClientManager # noqa: F401 +from .websocket_handler import RosbridgeWebSocket # noqa: F401 # TODO(@jubeira): add imports again once the modules are ported to ROS2. # from .tcp_handler import RosbridgeTcpSocket diff --git a/rosbridge_server/src/rosbridge_server/client_mananger.py b/rosbridge_server/src/rosbridge_server/client_mananger.py index 70331cbd2..60bb86ebf 100644 --- a/rosbridge_server/src/rosbridge_server/client_mananger.py +++ b/rosbridge_server/src/rosbridge_server/client_mananger.py @@ -33,10 +33,10 @@ import threading from rclpy.clock import ROSClock -from rclpy.qos import QoSProfile, QoSDurabilityPolicy +from rclpy.qos import QoSDurabilityPolicy, QoSProfile +from std_msgs.msg import Int32 from rosbridge_msgs.msg import ConnectedClient, ConnectedClients -from std_msgs.msg import Int32 class ClientManager: diff --git a/rosbridge_server/src/rosbridge_server/tcp_handler.py b/rosbridge_server/src/rosbridge_server/tcp_handler.py index 6ff8ed8a5..95e77d439 100755 --- a/rosbridge_server/src/rosbridge_server/tcp_handler.py +++ b/rosbridge_server/src/rosbridge_server/tcp_handler.py @@ -1,5 +1,6 @@ -import rospy import struct + +import rospy from rosbridge_library.rosbridge_protocol import RosbridgeProtocol try: diff --git a/rosbridge_server/src/rosbridge_server/udp_handler.py b/rosbridge_server/src/rosbridge_server/udp_handler.py index beb4a6391..a9fedc761 100644 --- a/rosbridge_server/src/rosbridge_server/udp_handler.py +++ b/rosbridge_server/src/rosbridge_server/udp_handler.py @@ -1,7 +1,6 @@ import rospy from rosbridge_library.rosbridge_protocol import RosbridgeProtocol from rosbridge_library.util import bson - from twisted.internet.protocol import DatagramProtocol diff --git a/rosbridge_server/src/rosbridge_server/websocket_handler.py b/rosbridge_server/src/rosbridge_server/websocket_handler.py index f550c7a70..b3e0b7d19 100755 --- a/rosbridge_server/src/rosbridge_server/websocket_handler.py +++ b/rosbridge_server/src/rosbridge_server/websocket_handler.py @@ -36,14 +36,13 @@ import uuid from functools import partial, wraps +from rosbridge_library.rosbridge_protocol import RosbridgeProtocol +from rosbridge_library.util import bson from tornado import version_info as tornado_version_info +from tornado.gen import BadYieldError, coroutine from tornado.ioloop import IOLoop from tornado.iostream import StreamClosedError -from tornado.websocket import WebSocketHandler, WebSocketClosedError -from tornado.gen import coroutine, BadYieldError - -from rosbridge_library.rosbridge_protocol import RosbridgeProtocol -from rosbridge_library.util import bson +from tornado.websocket import WebSocketClosedError, WebSocketHandler def _log_exception(): diff --git a/rosbridge_server/test/websocket/smoke.test.py b/rosbridge_server/test/websocket/smoke.test.py index 412efd9a9..62c6e144f 100644 --- a/rosbridge_server/test/websocket/smoke.test.py +++ b/rosbridge_server/test/websocket/smoke.test.py @@ -3,20 +3,19 @@ import sys import unittest -from autobahn.twisted.websocket import WebSocketClientFactory, WebSocketClientProtocol -from twisted.internet import reactor -from twisted.internet.endpoints import TCP4ClientEndpoint -from twisted.python import log - import launch import launch.actions import launch_ros import launch_ros.actions import rclpy import rclpy.task +from autobahn.twisted.websocket import WebSocketClientFactory, WebSocketClientProtocol from rcl_interfaces.srv import GetParameters from rclpy.executors import SingleThreadedExecutor from std_msgs.msg import String +from twisted.internet import reactor +from twisted.internet.endpoints import TCP4ClientEndpoint +from twisted.python import log log.startLogging(sys.stderr) From 46f807838dd5f8c0ad696376a92416bb65ab9646 Mon Sep 17 00:00:00 2001 From: Kenji Miyake Date: Sat, 25 Sep 2021 16:23:41 +0900 Subject: [PATCH 6/7] Add spaces Signed-off-by: Kenji Miyake --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index f5ad3af0f..d2d4816b9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,4 +9,4 @@ select = C,E262,E266,E4,E5,E7,E9,F4,F5,F6,F7,F81,F82,F83,F9,W1,W6 show-source = True [isort] -profile=black +profile = black From 2ffae1ea6ac3e53265ae9468775c535ee7b2f171 Mon Sep 17 00:00:00 2001 From: Kenji Miyake Date: Sat, 25 Sep 2021 16:24:48 +0900 Subject: [PATCH 7/7] Change line-length Signed-off-by: Kenji Miyake --- .pre-commit-config.yaml | 1 + rosapi/scripts/rosapi_node | 32 ++++---------- rosapi/src/rosapi/glob_helper.py | 4 +- rosapi/src/rosapi/objectutils.py | 4 +- rosapi/src/rosapi/params.py | 36 ++++----------- rosapi/src/rosapi/proxy.py | 16 ++----- .../capabilities/advertise.py | 36 ++++----------- .../capabilities/advertise_service.py | 16 ++----- .../capabilities/call_service.py | 19 +++----- .../capabilities/defragmentation.py | 12 ++--- .../rosbridge_library/capabilities/publish.py | 4 +- .../capabilities/service_response.py | 4 +- .../capabilities/subscribe.py | 43 +++++------------- .../capabilities/unadvertise_service.py | 13 ++---- .../internal/message_conversion.py | 12 ++--- .../rosbridge_library/internal/publishers.py | 20 +++------ .../rosbridge_library/internal/services.py | 8 +--- .../rosbridge_library/internal/subscribers.py | 20 +++------ .../internal/subscription_modifiers.py | 4 +- .../src/rosbridge_library/internal/topics.py | 3 +- .../src/rosbridge_library/protocol.py | 16 ++----- .../src/rosbridge_library/util/cbor.py | 4 +- .../test/capabilities/test_advertise.py | 12 ++--- .../test/capabilities/test_call_service.py | 4 +- .../capabilities/test_service_capabilities.py | 44 +++++-------------- .../test/capabilities/test_subscribe.py | 8 +--- ...test_non-ros_service_client_complex-srv.py | 8 +--- ...test_non-ros_service_server_complex-srv.py | 16 ++----- .../test_non-ros_service_client_fragmented.py | 12 ++--- .../test_non-ros_service_server_fragmented.py | 24 +++------- .../publishers/test_publisher_manager.py | 12 ++--- .../subscribers/test_subscriber_manager.py | 8 +--- .../test_subscription_modifiers.py | 8 +--- .../test/internal/test_cbor_conversion.py | 8 +--- .../test/internal/test_message_conversion.py | 40 +++++------------ .../test/internal/test_ros_loader.py | 40 +++++------------ .../test/internal/test_services.py | 24 +++------- rosbridge_server/scripts/rosbridge_tcp.py | 25 +++-------- rosbridge_server/scripts/rosbridge_udp.py | 12 ++--- .../scripts/rosbridge_websocket.py | 35 ++++----------- .../src/rosbridge_server/tcp_handler.py | 8 +--- .../src/rosbridge_server/websocket_handler.py | 4 +- rosbridge_server/test/websocket/smoke.test.py | 16 ++----- 43 files changed, 177 insertions(+), 518 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 59f1b8718..4536bd18d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,6 +38,7 @@ repos: rev: 21.9b0 hooks: - id: black + args: ["--line-length=100"] - repo: https://github.com/pycqa/isort rev: 5.8.0 diff --git a/rosapi/scripts/rosapi_node b/rosapi/scripts/rosapi_node index 50b33a9e5..0a731d72f 100755 --- a/rosapi/scripts/rosapi_node +++ b/rosapi/scripts/rosapi_node @@ -63,9 +63,7 @@ class Rosapi(Node): full_name = self.get_namespace() + "/" + self.get_name() params.init(full_name) self.create_service(Topics, "/rosapi/topics", self.get_topics) - self.create_service( - TopicsForType, "/rosapi/topics_for_type", self.get_topics_for_type - ) + self.create_service(TopicsForType, "/rosapi/topics_for_type", self.get_topics_for_type) self.create_service( TopicsAndRawTypes, "/rosapi/topics_and_raw_types", @@ -77,9 +75,7 @@ class Rosapi(Node): ) self.create_service(Nodes, "/rosapi/nodes", self.get_nodes) self.create_service(NodeDetails, "/rosapi/node_details", self.get_node_details) - self.create_service( - GetActionServers, "/rosapi/action_servers", self.get_action_servers - ) + self.create_service(GetActionServers, "/rosapi/action_servers", self.get_action_servers) self.create_service(TopicType, "/rosapi/topic_type", self.get_topic_type) self.create_service(ServiceType, "/rosapi/service_type", self.get_service_type) self.create_service(Publishers, "/rosapi/publishers", self.get_publishers) @@ -88,9 +84,7 @@ class Rosapi(Node): ServiceProviders, "/rosapi/service_providers", self.get_service_providers ) self.create_service(ServiceNode, "/rosapi/service_node", self.get_service_node) - self.create_service( - MessageDetails, "/rosapi/message_details", self.get_message_details - ) + self.create_service(MessageDetails, "/rosapi/message_details", self.get_message_details) self.create_service( ServiceRequestDetails, "/rosapi/service_request_details", @@ -105,9 +99,7 @@ class Rosapi(Node): self.create_service(GetParam, "/rosapi/get_param", self.get_param) self.create_service(HasParam, "/rosapi/has_param", self.has_param) self.create_service(DeleteParam, "/rosapi/delete_param", self.delete_param) - self.create_service( - GetParamNames, "/rosapi/get_param_names", self.get_param_names - ) + self.create_service(GetParamNames, "/rosapi/get_param_names", self.get_param_names) self.create_service(GetTime, "/rosapi/get_time", self.get_time) # TODO(@jubeira): Implement missing services: @@ -143,9 +135,7 @@ class Rosapi(Node): def get_services_for_type(self, request, response): """Called by the rosapi/ServicesForType service. Returns a list of all the services that are publishing a given type""" - response.services = proxy.get_services_for_type( - request.type, self.globs.services - ) + response.services = proxy.get_services_for_type(request.type, self.globs.services) return response def get_nodes(self, request, response): @@ -199,9 +189,7 @@ class Rosapi(Node): def get_service_providers(self, request, response): """Called by the rosapi/ServiceProviders service. Given the name of a topic, returns a list of node names that are advertising that service type""" - response.providers = proxy.get_service_providers( - request.service, self.globs.services - ) + response.providers = proxy.get_service_providers(request.service, self.globs.services) return response def get_service_node(self, request, response): @@ -279,9 +267,7 @@ class Rosapi(Node): def _print_malformed_param_name_warning(self, param_name): self.get_logger().warn( - "Malformed parameter name: {}; expecting :".format( - param_name - ) + "Malformed parameter name: {}; expecting :".format(param_name) ) @@ -296,9 +282,7 @@ def get_service_host(request): # Note(@jubeira): rclpy does not have an equivalent for this. To be checked if this service is necessary or not. def search_param(request): - return SearchParamResponse( - rosapi.params.search_param(request.name, rosapi.glob_helper.params) - ) + return SearchParamResponse(rosapi.params.search_param(request.name, rosapi.glob_helper.params)) def dict_to_typedef(typedefdict): diff --git a/rosapi/src/rosapi/glob_helper.py b/rosapi/src/rosapi/glob_helper.py index 04a04ecbc..e62883016 100644 --- a/rosapi/src/rosapi/glob_helper.py +++ b/rosapi/src/rosapi/glob_helper.py @@ -38,7 +38,5 @@ def filter_globs(globs, full_list): def any_match(query, globs): return ( - globs is None - or len(globs) == 0 - or any(fnmatch.fnmatch(str(query), glob) for glob in globs) + globs is None or len(globs) == 0 or any(fnmatch.fnmatch(str(query), glob) for glob in globs) ) diff --git a/rosapi/src/rosapi/objectutils.py b/rosapi/src/rosapi/objectutils.py index 1944c5336..49877d078 100644 --- a/rosapi/src/rosapi/objectutils.py +++ b/rosapi/src/rosapi/objectutils.py @@ -147,9 +147,7 @@ def _get_typedef(instance): fieldnames.append(name) # Pull out the type and determine whether it's an array - field_type = instance._fields_and_field_types[ - name[1:] - ] # Remove trailing underscore. + field_type = instance._fields_and_field_types[name[1:]] # Remove trailing underscore. arraylen = -1 if field_type[-1:] == "]": if field_type[-2:-1] == "[": diff --git a/rosapi/src/rosapi/params.py b/rosapi/src/rosapi/params.py index 597e7246b..f2fd58a3e 100644 --- a/rosapi/src/rosapi/params.py +++ b/rosapi/src/rosapi/params.py @@ -77,9 +77,7 @@ def init(parent_node_name): def set_param(node_name, name, value, params_glob): """Sets a parameter in a given node""" - if params_glob and not any( - fnmatch.fnmatch(str(name), glob) for glob in params_glob - ): + if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): # If the glob list is not empty and there are no glob matches, # stop the attempt to set the parameter. return @@ -126,9 +124,7 @@ def _set_param(node_name, name, value, parameter_type=None): def get_param(node_name, name, default, params_glob): """Gets a parameter from a given node""" - if params_glob and not any( - fnmatch.fnmatch(str(name), glob) for glob in params_glob - ): + if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): # If the glob list is not empty and there are no glob matches, # stop the attempt to get the parameter. return @@ -144,9 +140,7 @@ def get_param(node_name, name, default, params_glob): with param_server_lock: try: # call_get_parameters will fail if node does not exist. - response = call_get_parameters( - node=_node, node_name=node_name, parameter_names=[name] - ) + response = call_get_parameters(node=_node, node_name=node_name, parameter_names=[name]) pvalue = response.values[0] # if type is 0 (parameter not set), the next line will raise an exception # and return value shall go to default. @@ -161,9 +155,7 @@ def get_param(node_name, name, default, params_glob): def has_param(node_name, name, params_glob): """Checks whether a given node has a parameter or not""" - if params_glob and not any( - fnmatch.fnmatch(str(name), glob) for glob in params_glob - ): + if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): # If the glob list is not empty and there are no glob matches, # stop the attempt to set the parameter. return False @@ -172,23 +164,17 @@ def has_param(node_name, name, params_glob): node_name = get_absolute_node_name(node_name) with param_server_lock: try: - response = call_get_parameters( - node=_node, node_name=node_name, parameter_names=[name] - ) + response = call_get_parameters(node=_node, node_name=node_name, parameter_names=[name]) except Exception: return False - return response.values[0].type > 0 and response.values[0].type < len( - _parameter_type_mapping - ) + return response.values[0].type > 0 and response.values[0].type < len(_parameter_type_mapping) def delete_param(node_name, name, params_glob): """Deletes a parameter in a given node""" - if params_glob and not any( - fnmatch.fnmatch(str(name), glob) for glob in params_glob - ): + if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): # If the glob list is not empty and there are no glob matches, # stop the attempt to delete the parameter. return @@ -219,9 +205,7 @@ def get_node_param_names(node_name, params_glob): # If there is a parameter glob, filter by it. return list( filter( - lambda x: any( - fnmatch.fnmatch(str(x), glob) for glob in params_glob - ), + lambda x: any(fnmatch.fnmatch(str(x), glob) for glob in params_glob), _get_param_names(node_name), ) ) @@ -256,9 +240,7 @@ def _get_param_names(node_name): # TODO(@jubeira): functions to be ported below. def search_param(name, params_glob): - if params_glob and not any( - fnmatch.fnmatch(str(name), glob) for glob in params_glob - ): + if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): # If the glob list is not empty and there are no glob matches, # stop the attempt to find the parameter. return None diff --git a/rosapi/src/rosapi/proxy.py b/rosapi/src/rosapi/proxy.py index f7a23795c..b9f10c9d8 100644 --- a/rosapi/src/rosapi/proxy.py +++ b/rosapi/src/rosapi/proxy.py @@ -71,18 +71,14 @@ def get_topics_for_type(topic_type, topics_glob, include_hidden=False): node=_node, include_hidden_topics=include_hidden ) # topic[0] has the topic name and topic[1] has the type wrapped in a list. - topics_for_type = [ - topic[0] for topic in topic_names_and_types if topic[1][0] == topic_type - ] + topics_for_type = [topic[0] for topic in topic_names_and_types if topic[1][0] == topic_type] return filter_globs(topics_glob, topics_for_type) def get_services(services_glob, include_hidden=False): """Returns a list of all the services advertised in the ROS system""" # Filter the list of services by whether they are public before returning. - service_names = get_service_names( - node=_node, include_hidden_services=include_hidden - ) + service_names = get_service_names(node=_node, include_hidden_services=include_hidden) return filter_globs(services_glob, service_names) @@ -102,18 +98,14 @@ def get_services_for_type(service_type, services_glob, include_hidden=False): ) # service[0] has the topic name and service[1] has the type wrapped in a list. services_for_type = [ - service[0] - for service in services_names_and_types - if service[1][0] == service_type + service[0] for service in services_names_and_types if service[1][0] == service_type ] return filter_globs(services_glob, services_for_type) def get_publications_and_types(glob, getter_function, **include_hidden_publications): """Generic getter function for both services and topics""" - publication_names_and_types = getter_function( - node=_node, **include_hidden_publications - ) + publication_names_and_types = getter_function(node=_node, **include_hidden_publications) # publication[0] has the publication name and publication[1] has the type wrapped in a list. all_publications = [publication[0] for publication in publication_names_and_types] filtered_publications = filter_globs(glob, all_publications) diff --git a/rosbridge_library/src/rosbridge_library/capabilities/advertise.py b/rosbridge_library/src/rosbridge_library/capabilities/advertise.py index f3f95b854..1003bf80e 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/advertise.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/advertise.py @@ -57,9 +57,7 @@ def __init__(self, client_id, topic, node_handle): def unregister(self): manager.unregister(self.client_id, self.topic) - def register_advertisement( - self, msg_type, adv_id=None, latch=False, queue_size=100 - ): + def register_advertisement(self, msg_type, adv_id=None, latch=False, queue_size=100): # Register with the publisher manager, propagating any exception manager.register( self.client_id, @@ -114,17 +112,13 @@ def advertise(self, message): queue_size = message.get("queue_size", 100) if Advertise.topics_glob is not None and Advertise.topics_glob: - self.protocol.log( - "debug", "Topic security glob enabled, checking topic: " + topic - ) + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) match = False for glob in Advertise.topics_glob: if fnmatch.fnmatch(topic, glob): self.protocol.log( "debug", - "Found match with glob " - + glob - + ", continuing advertisement...", + "Found match with glob " + glob + ", continuing advertisement...", ) match = True break @@ -135,21 +129,15 @@ def advertise(self, message): ) return else: - self.protocol.log( - "debug", "No topic security glob, not checking advertisement." - ) + self.protocol.log("debug", "No topic security glob, not checking advertisement.") # Create the Registration if one doesn't yet exist if topic not in self._registrations: client_id = self.protocol.client_id - self._registrations[topic] = Registration( - client_id, topic, self.protocol.node_handle - ) + self._registrations[topic] = Registration(client_id, topic, self.protocol.node_handle) # Register, propagating any exceptions - self._registrations[topic].register_advertisement( - msg_type, aid, latch, queue_size - ) + self._registrations[topic].register_advertisement(msg_type, aid, latch, queue_size) def unadvertise(self, message): # Pull out the ID @@ -159,17 +147,13 @@ def unadvertise(self, message): topic = message["topic"] if Advertise.topics_glob is not None and Advertise.topics_glob: - self.protocol.log( - "debug", "Topic security glob enabled, checking topic: " + topic - ) + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) match = False for glob in Advertise.topics_glob: if fnmatch.fnmatch(topic, glob): self.protocol.log( "debug", - "Found match with glob " - + glob - + ", continuing unadvertisement...", + "Found match with glob " + glob + ", continuing unadvertisement...", ) match = True break @@ -180,9 +164,7 @@ def unadvertise(self, message): ) return else: - self.protocol.log( - "debug", "No topic security glob, not checking unadvertisement." - ) + self.protocol.log("debug", "No topic security glob, not checking unadvertisement.") # Now unadvertise the topic if topic not in self._registrations: diff --git a/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py b/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py index de38f4edf..72184a40f 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py @@ -58,8 +58,7 @@ def handle_request(self, req): self.protocol.log( "warning", "Service %s was unadvertised with a service call in progress, " - "aborting service call with request ID %s" - % (self.service_name, request_id), + "aborting service call with request ID %s" % (self.service_name, request_id), ) return None @@ -102,10 +101,7 @@ def advertise_service(self, message): # parse the incoming message service_name = message["service"] - if ( - AdvertiseService.services_glob is not None - and AdvertiseService.services_glob - ): + if AdvertiseService.services_glob is not None and AdvertiseService.services_glob: self.protocol.log( "debug", "Service security glob enabled, checking service: " + service_name, @@ -115,9 +111,7 @@ def advertise_service(self, message): if fnmatch.fnmatch(service_name, glob): self.protocol.log( "debug", - "Found match with glob " - + glob - + ", continuing service advertisement...", + "Found match with glob " + glob + ", continuing service advertisement...", ) match = True break @@ -145,8 +139,6 @@ def advertise_service(self, message): # setup and store the service information service_type = message["type"] - service_handler = AdvertisedServiceHandler( - service_name, service_type, self.protocol - ) + service_handler = AdvertisedServiceHandler(service_name, service_type, self.protocol) self.protocol.external_service_list[service_name] = service_handler self.protocol.log("info", "Advertised service %s." % service_name) diff --git a/rosbridge_library/src/rosbridge_library/capabilities/call_service.py b/rosbridge_library/src/rosbridge_library/capabilities/call_service.py index e8c0dd443..6b6a6be4c 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/call_service.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/call_service.py @@ -76,23 +76,18 @@ def call_service(self, message): if fnmatch.fnmatch(service, glob): self.protocol.log( "debug", - "Found match with glob " - + glob - + ", continuing service call...", + "Found match with glob " + glob + ", continuing service call...", ) match = True break if not match: self.protocol.log( "warn", - "No match found for service, cancelling service call for: " - + service, + "No match found for service, cancelling service call for: " + service, ) return else: - self.protocol.log( - "debug", "No service security glob, not checking service call." - ) + self.protocol.log("debug", "No service security glob, not checking service call.") # Check for deprecated service ID, eg. /rosbridge/topics#33 cid = extract_id(service, cid) @@ -102,9 +97,7 @@ def call_service(self, message): e_cb = partial(self._failure, cid, service) # Run service caller in the same thread. - ServiceCaller( - trim_servicename(service), args, s_cb, e_cb, self.protocol.node_handle - ).run() + ServiceCaller(trim_servicename(service), args, s_cb, e_cb, self.protocol.node_handle).run() def _success(self, cid, service, fragment_size, compression, message): outgoing_message = { @@ -119,9 +112,7 @@ def _success(self, cid, service, fragment_size, compression, message): self.protocol.send(outgoing_message) def _failure(self, cid, service, exc): - self.protocol.log( - "error", "call_service %s: %s" % (type(exc).__name__, str(exc)), cid - ) + self.protocol.log("error", "call_service %s: %s" % (type(exc).__name__, str(exc)), cid) # send response with result: false outgoing_message = { "op": "service_response", diff --git a/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py b/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py index 1d309ccd2..1757a1179 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py @@ -101,9 +101,7 @@ def defragment(self, message): else: log_msg.extend([" -> but we're just about to add fragment #"]) log_msg.extend([str(message.get("num")), " of "]) - log_msg.extend( - [str(self.received_fragments[message.get("id")]["total"])] - ) + log_msg.extend([str(self.received_fragments[message.get("id")]["total"])]) log_msg.extend([" ..keeping the list"]) self.protocol.log("warning", "".join(log_msg)) @@ -163,9 +161,7 @@ def defragment(self, message): # Make sure total number of fragments received if existing_fragments == announced_total: - log_msg = [ - "enough/all fragments for messageID " + str(msg_id) + " received" - ] + log_msg = ["enough/all fragments for messageID " + str(msg_id) + " received"] log_msg.extend([" [", str(existing_fragments), "]"]) log_msg = "".join(log_msg) self.protocol.log("debug", log_msg) @@ -185,9 +181,7 @@ def defragment(self, message): self.protocol.log("debug", log_msg) # Reconstruct the message - reconstructed_msg = "".join( - self.received_fragments[msg_id]["fragment_list"].values() - ) + reconstructed_msg = "".join(self.received_fragments[msg_id]["fragment_list"].values()) log_msg = ["reconstructed original message:\n"] log_msg.append(reconstructed_msg) diff --git a/rosbridge_library/src/rosbridge_library/capabilities/publish.py b/rosbridge_library/src/rosbridge_library/capabilities/publish.py index 6efadb06b..af8824eaa 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/publish.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/publish.py @@ -64,9 +64,7 @@ def publish(self, message): queue_size = message.get("queue_size", 100) if Publish.topics_glob is not None and Publish.topics_glob: - self.protocol.log( - "debug", "Topic security glob enabled, checking topic: " + topic - ) + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) match = False for glob in Publish.topics_glob: if fnmatch.fnmatch(topic, glob): diff --git a/rosbridge_library/src/rosbridge_library/capabilities/service_response.py b/rosbridge_library/src/rosbridge_library/capabilities/service_response.py index 96cacfcd4..79a364734 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/service_response.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/service_response.py @@ -30,9 +30,7 @@ def service_response(self, message): request_id = message["id"] values = message["values"] # create a message instance - resp = ros_loader.get_service_response_instance( - service_handler.service_type - ) + resp = ros_loader.get_service_response_instance(service_handler.service_type) message_conversion.populate_instance(values, resp) # pass along the response service_handler.responses[request_id] = resp diff --git a/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py b/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py index 598a639ff..231fa8cc9 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py @@ -243,17 +243,13 @@ def subscribe(self, msg): topic = msg["topic"] if Subscribe.topics_glob is not None and Subscribe.topics_glob: - self.protocol.log( - "debug", "Topic security glob enabled, checking topic: " + topic - ) + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) match = False for glob in Subscribe.topics_glob: if fnmatch.fnmatch(topic, glob): self.protocol.log( "debug", - "Found match with glob " - + glob - + ", continuing subscription...", + "Found match with glob " + glob + ", continuing subscription...", ) match = True break @@ -264,9 +260,7 @@ def subscribe(self, msg): ) return else: - self.protocol.log( - "debug", "No topic security glob, not checking subscription." - ) + self.protocol.log("debug", "No topic security glob, not checking subscription.") if topic not in self._subscriptions: client_id = self.protocol.client_id @@ -296,31 +290,24 @@ def unsubscribe(self, msg): topic = msg["topic"] if Subscribe.topics_glob is not None and Subscribe.topics_glob: - self.protocol.log( - "debug", "Topic security glob enabled, checking topic: " + topic - ) + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) match = False for glob in Subscribe.topics_glob: if fnmatch.fnmatch(topic, glob): self.protocol.log( "debug", - "Found match with glob " - + glob - + ", continuing unsubscription...", + "Found match with glob " + glob + ", continuing unsubscription...", ) match = True break if not match: self.protocol.log( "warn", - "No match found for topic, cancelling unsubscription from: " - + topic, + "No match found for topic, cancelling unsubscription from: " + topic, ) return else: - self.protocol.log( - "debug", "No topic security glob, not checking unsubscription." - ) + self.protocol.log("debug", "No topic security glob, not checking unsubscription.") if topic not in self._subscriptions: return @@ -346,17 +333,13 @@ def publish(self, topic, message, fragment_size=None, compression="none"): """ # TODO: fragmentation, proper ids if Subscribe.topics_glob and Subscribe.topics_glob: - self.protocol.log( - "debug", "Topic security glob enabled, checking topic: " + topic - ) + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) match = False for glob in Subscribe.topics_glob: if fnmatch.fnmatch(topic, glob): self.protocol.log( "debug", - "Found match with glob " - + glob - + ", continuing topic publish...", + "Found match with glob " + glob + ", continuing topic publish...", ) match = True break @@ -367,9 +350,7 @@ def publish(self, topic, message, fragment_size=None, compression="none"): ) return else: - self.protocol.log( - "debug", "No topic security glob, not checking topic publish." - ) + self.protocol.log("debug", "No topic security glob, not checking topic publish.") outgoing_msg = {"op": "publish", "topic": topic} if compression == "png": @@ -380,9 +361,7 @@ def publish(self, topic, message, fragment_size=None, compression="none"): outgoing_msg["msg"] = message.get_cbor_values() outgoing_msg = bytearray(encode_cbor(outgoing_msg)) elif compression == "cbor-raw": - (secs, nsecs) = ( - self.protocol.node_handle.get_clock().now().seconds_nanoseconds() - ) + (secs, nsecs) = self.protocol.node_handle.get_clock().now().seconds_nanoseconds() outgoing_msg["msg"] = { "secs": secs, "nsecs": nsecs, diff --git a/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py b/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py index 1f28fb346..8b2f7a746 100644 --- a/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py +++ b/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py @@ -20,10 +20,7 @@ def unadvertise_service(self, message): # parse the message service_name = message["service"] - if ( - UnadvertiseService.services_glob is not None - and UnadvertiseService.services_glob - ): + if UnadvertiseService.services_glob is not None and UnadvertiseService.services_glob: self.protocol.log( "debug", "Service security glob enabled, checking service: " + service_name, @@ -33,9 +30,7 @@ def unadvertise_service(self, message): if fnmatch.fnmatch(service_name, glob): self.protocol.log( "debug", - "Found match with glob " - + glob - + ", continuing service unadvertisement...", + "Found match with glob " + glob + ", continuing service unadvertisement...", ) match = True break @@ -54,9 +49,7 @@ def unadvertise_service(self, message): # unregister service in ROS if service_name in self.protocol.external_service_list.keys(): - self.protocol.external_service_list[service_name].graceful_shutdown( - timeout=1.0 - ) + self.protocol.external_service_list[service_name].graceful_shutdown(timeout=1.0) self.protocol.external_service_list[service_name].service_handle.shutdown( "Unadvertise request." ) diff --git a/rosbridge_library/src/rosbridge_library/internal/message_conversion.py b/rosbridge_library/src/rosbridge_library/internal/message_conversion.py index 4417068c6..55a8262c0 100644 --- a/rosbridge_library/src/rosbridge_library/internal/message_conversion.py +++ b/rosbridge_library/src/rosbridge_library/internal/message_conversion.py @@ -144,9 +144,7 @@ class NonexistentFieldException(Exception): def __init__(self, basetype, fields): Exception.__init__( self, - "Message type {} does not have a field {}".format( - basetype, ".".join(fields) - ), + "Message type {} does not have a field {}".format(basetype, ".".join(fields)), ) @@ -291,9 +289,7 @@ def _to_inst(msg, rostype, roottype, inst=None, stack=[]): def _to_binary_inst(msg): try: - return ( - standard_b64decode(msg) if isinstance(msg, str) else bytes(bytearray(msg)) - ) + return standard_b64decode(msg) if isinstance(msg, str) else bytes(bytearray(msg)) except Exception: return msg @@ -383,9 +379,7 @@ def _to_object_inst(msg, rostype, roottype, inst, stack): field_rostype = inst_fields[field_name] field_inst = getattr(inst, field_name) - field_value = _to_inst( - msg[field_name], field_rostype, roottype, field_inst, field_stack - ) + field_value = _to_inst(msg[field_name], field_rostype, roottype, field_inst, field_stack) setattr(inst, field_name, field_value) diff --git a/rosbridge_library/src/rosbridge_library/internal/publishers.py b/rosbridge_library/src/rosbridge_library/internal/publishers.py index 9507486f5..3235572c2 100644 --- a/rosbridge_library/src/rosbridge_library/internal/publishers.py +++ b/rosbridge_library/src/rosbridge_library/internal/publishers.py @@ -49,9 +49,7 @@ class MultiPublisher: Provides an API to publish messages and register clients that are using this publisher""" - def __init__( - self, topic, node_handle, msg_type=None, latched_client_id=None, queue_size=100 - ): + def __init__(self, topic, node_handle, msg_type=None, latched_client_id=None, queue_size=100): """Register a publisher on the specified topic. Keyword arguments: @@ -82,9 +80,7 @@ def __init__( # topic_type is a list of types or None at this point; only one type is supported. if topic_type is not None: if len(topic_type) > 1: - node_handle.get_logger().warning( - f"More than one topic type detected: {topic_type}" - ) + node_handle.get_logger().warning(f"More than one topic type detected: {topic_type}") topic_type = topic_type[0] # Use the established topic type if none was specified @@ -120,9 +116,7 @@ def __init__( else: publisher_qos.depth = 1 - self.publisher = node_handle.create_publisher( - msg_class, topic, qos_profile=publisher_qos - ) + self.publisher = node_handle.create_publisher(msg_class, topic, qos_profile=publisher_qos) def unregister(self): """Unregisters the publisher and clears the clients""" @@ -142,9 +136,7 @@ def verify_type(self, msg_type): """ if not ros_loader.get_message_class(msg_type) is self.msg_class: - raise TypeConflictException( - self.topic, msg_class_type_repr(self.msg_class), msg_type - ) + raise TypeConflictException(self.topic, msg_class_type_repr(self.msg_class), msg_type) return def publish(self, msg): @@ -209,9 +201,7 @@ def __init__(self): self.unregister_timers = {} self.unregister_timeout = 10.0 - def register( - self, client_id, topic, node_handle, msg_type=None, latch=False, queue_size=100 - ): + def register(self, client_id, topic, node_handle, msg_type=None, latch=False, queue_size=100): """Register a publisher on the specified topic. Publishers are shared between clients, so a single MultiPublisher diff --git a/rosbridge_library/src/rosbridge_library/internal/services.py b/rosbridge_library/src/rosbridge_library/internal/services.py index 2d52261b4..4eda3e7a7 100644 --- a/rosbridge_library/src/rosbridge_library/internal/services.py +++ b/rosbridge_library/src/rosbridge_library/internal/services.py @@ -104,9 +104,7 @@ def call_service(node_handle, service, args=None): # and a request instance # This should be equivalent to rospy.resolve_name. - service = expand_topic_name( - service, node_handle.get_name(), node_handle.get_namespace() - ) + 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) @@ -114,9 +112,7 @@ def call_service(node_handle, service, args=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}" - ) + node_handle.get_logger().warning(f"More than one service type detected: {service_type}") service_type = service_type[0] service_class = get_service_class(service_type) diff --git a/rosbridge_library/src/rosbridge_library/internal/subscribers.py b/rosbridge_library/src/rosbridge_library/internal/subscribers.py index c8a26ce6d..7ce1967e0 100644 --- a/rosbridge_library/src/rosbridge_library/internal/subscribers.py +++ b/rosbridge_library/src/rosbridge_library/internal/subscribers.py @@ -53,9 +53,7 @@ class MultiSubscriber: callbacks being called in separate threads, must lock whenever modifying or accessing the subscribed clients.""" - def __init__( - self, topic, client_id, callback, node_handle, msg_type=None, raw=False - ): + def __init__(self, topic, client_id, callback, node_handle, msg_type=None, raw=False): """Register a subscriber on the specified topic. Keyword arguments: @@ -87,9 +85,7 @@ def __init__( # topic_type is a list of types or None at this point; only one type is supported. if topic_type is not None: if len(topic_type) > 1: - node_handle.get_logger().warning( - f"More than one topic type detected: {topic_type}" - ) + node_handle.get_logger().warning(f"More than one topic type detected: {topic_type}") topic_type = topic_type[0] # Use the established topic type if none was specified @@ -136,9 +132,7 @@ def verify_type(self, msg_type): """ if not ros_loader.get_message_class(msg_type) is self.msg_class: - raise TypeConflictException( - self.topic, msg_class_type_repr(self.msg_class), msg_type - ) + raise TypeConflictException(self.topic, msg_class_type_repr(self.msg_class), msg_type) return def subscribe(self, client_id, callback): @@ -200,9 +194,7 @@ def callback(self, msg, callbacks=None): callback(outgoing) except Exception as exc: # Do nothing if one particular callback fails except log it - self.node_handle.get_logger().error( - f"Exception calling subscribe callback: {exc}" - ) + self.node_handle.get_logger().error(f"Exception calling subscribe callback: {exc}") pass def _new_sub_callback(self, msg): @@ -232,9 +224,7 @@ class SubscriberManager: def __init__(self): self._subscribers = {} - def subscribe( - self, client_id, topic, callback, node_handle, msg_type=None, raw=False - ): + def subscribe(self, client_id, topic, callback, node_handle, msg_type=None, raw=False): """Subscribe to a topic Keyword arguments: diff --git a/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py b/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py index 3f6c4a0e1..f75b1cec9 100644 --- a/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py +++ b/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py @@ -143,9 +143,7 @@ def finish(self): def run(self): while self.alive: with self.c: - while self.alive and ( - self.time_remaining() > 0 or len(self.queue) == 0 - ): + while self.alive and (self.time_remaining() > 0 or len(self.queue) == 0): if len(self.queue) == 0: self.c.wait() else: diff --git a/rosbridge_library/src/rosbridge_library/internal/topics.py b/rosbridge_library/src/rosbridge_library/internal/topics.py index 259b6e198..c47cc0353 100644 --- a/rosbridge_library/src/rosbridge_library/internal/topics.py +++ b/rosbridge_library/src/rosbridge_library/internal/topics.py @@ -37,8 +37,7 @@ class TopicNotEstablishedException(Exception): def __init__(self, topic): Exception.__init__( self, - "Cannot infer topic type for topic %s as it is not yet advertised" - % (topic,), + "Cannot infer topic type for topic %s as it is not yet advertised" % (topic,), ) diff --git a/rosbridge_library/src/rosbridge_library/protocol.py b/rosbridge_library/src/rosbridge_library/protocol.py index dd431ccd4..dd8fd9032 100644 --- a/rosbridge_library/src/rosbridge_library/protocol.py +++ b/rosbridge_library/src/rosbridge_library/protocol.py @@ -149,12 +149,8 @@ def incoming(self, message_string=""): # fragment data must NOT (!) contain a complete json-object that has an "op-field" # # an alternative solution would be to only check from first opening bracket and have a time out on data in input buffer.. (to handle broken data) - opening_brackets = [ - i for i, letter in enumerate(self.buffer) if letter == "{" - ] - closing_brackets = [ - i for i, letter in enumerate(self.buffer) if letter == "}" - ] + opening_brackets = [i for i, letter in enumerate(self.buffer) if letter == "{"] + closing_brackets = [i for i, letter in enumerate(self.buffer) if letter == "}"] for start in opening_brackets: for end in closing_brackets: @@ -261,9 +257,7 @@ def send(self, message, cid=None): # TODO: think about splitting into fragments that have specified size including header-fields! # --> estimate header size --> split content into fragments that have the requested overall size, rather than requested content size - fragment_list = Fragmentation(self).fragment( - message, self.fragment_size, mid - ) + fragment_list = Fragmentation(self).fragment(message, self.fragment_size, mid) # fragment list not empty -> send fragments if fragment_list is not None: @@ -311,9 +305,7 @@ def serialize(self, msg, cid=None): except Exception: if cid is not None: # Only bother sending the log message if there's an id - self.log( - "error", "Unable to serialize %s message to client" % msg["op"], cid - ) + self.log("error", "Unable to serialize %s message to client" % msg["op"], cid) return None def deserialize(self, msg, cid=None): diff --git a/rosbridge_library/src/rosbridge_library/util/cbor.py b/rosbridge_library/src/rosbridge_library/util/cbor.py index 656fc7c4e..e72acdfb6 100644 --- a/rosbridge_library/src/rosbridge_library/util/cbor.py +++ b/rosbridge_library/src/rosbridge_library/util/cbor.py @@ -50,9 +50,7 @@ CBOR_FLOAT64 = CBOR_7 | 27 CBOR_TAG_DATE_STRING = 0 # RFC3339 -CBOR_TAG_DATE_ARRAY = ( - 1 # any number type follows, seconds since 1970-01-01T00:00:00 UTC -) +CBOR_TAG_DATE_ARRAY = 1 # any number type follows, seconds since 1970-01-01T00:00:00 UTC CBOR_TAG_BIGNUM = 2 # big endian byte string follows CBOR_TAG_NEGBIGNUM = 3 # big endian byte string follows CBOR_TAG_DECIMAL = 4 # [ 10^x exponent, number ] diff --git a/rosbridge_library/test/capabilities/test_advertise.py b/rosbridge_library/test/capabilities/test_advertise.py index 8e859ffeb..ca475512c 100755 --- a/rosbridge_library/test/capabilities/test_advertise.py +++ b/rosbridge_library/test/capabilities/test_advertise.py @@ -100,9 +100,7 @@ def test_invalid_msg_package(self): "topic": "/test_invalid_msg_package", "type": invalid_type, } - self.assertRaises( - ros_loader.InvalidPackageException, adv.advertise, loads(dumps(msg)) - ) + self.assertRaises(ros_loader.InvalidPackageException, adv.advertise, loads(dumps(msg))) def test_invalid_msg_module(self): no_msgs = [ @@ -122,9 +120,7 @@ def test_invalid_msg_module(self): "topic": "/test_invalid_msg_module", "type": invalid_type, } - self.assertRaises( - ros_loader.InvalidModuleException, adv.advertise, loads(dumps(msg)) - ) + self.assertRaises(ros_loader.InvalidModuleException, adv.advertise, loads(dumps(msg))) def test_invalid_msg_classes(self): nonexistent = [ @@ -148,9 +144,7 @@ def test_invalid_msg_classes(self): "topic": "/test_invalid_msg_classes", "type": invalid_type, } - self.assertRaises( - ros_loader.InvalidClassException, adv.advertise, loads(dumps(msg)) - ) + self.assertRaises(ros_loader.InvalidClassException, adv.advertise, loads(dumps(msg))) def test_valid_msg_classes(self): assortedmsgs = [ diff --git a/rosbridge_library/test/capabilities/test_call_service.py b/rosbridge_library/test/capabilities/test_call_service.py index e3398d8c7..6faca9849 100755 --- a/rosbridge_library/test/capabilities/test_call_service.py +++ b/rosbridge_library/test/capabilities/test_call_service.py @@ -40,9 +40,7 @@ def test_call_service_works(self): proto = Protocol("test_call_service_works") s = CallService(proto) - msg = loads( - dumps({"op": "call_service", "service": rospy.get_name() + "/get_loggers"}) - ) + msg = loads(dumps({"op": "call_service", "service": rospy.get_name() + "/get_loggers"})) received = {"msg": None, "arrived": False} diff --git a/rosbridge_library/test/capabilities/test_service_capabilities.py b/rosbridge_library/test/capabilities/test_service_capabilities.py index 892c7c6ae..ad9b8b859 100755 --- a/rosbridge_library/test/capabilities/test_service_capabilities.py +++ b/rosbridge_library/test/capabilities/test_service_capabilities.py @@ -37,40 +37,26 @@ def mock_log(self, loglevel, message, _=None): def test_advertise_missing_arguments(self): advertise_msg = loads(dumps({"op": "advertise_service"})) - self.assertRaises( - MissingArgumentException, self.advertise.advertise_service, advertise_msg - ) + self.assertRaises(MissingArgumentException, self.advertise.advertise_service, advertise_msg) def test_advertise_invalid_arguments(self): - advertise_msg = loads( - dumps({"op": "advertise_service", "type": 42, "service": None}) - ) - self.assertRaises( - InvalidArgumentException, self.advertise.advertise_service, advertise_msg - ) + advertise_msg = loads(dumps({"op": "advertise_service", "type": 42, "service": None})) + self.assertRaises(InvalidArgumentException, self.advertise.advertise_service, advertise_msg) def test_response_missing_arguments(self): response_msg = loads(dumps({"op": "service_response"})) - self.assertRaises( - MissingArgumentException, self.response.service_response, response_msg - ) + self.assertRaises(MissingArgumentException, self.response.service_response, response_msg) # this message has the optional fields, with correct types, but not the # required ones response_msg = loads( dumps({"op": "service_response", "id": "dummy_service", "values": "none"}) ) - self.assertRaises( - MissingArgumentException, self.response.service_response, response_msg - ) + self.assertRaises(MissingArgumentException, self.response.service_response, response_msg) def test_response_invalid_arguments(self): - response_msg = loads( - dumps({"op": "service_response", "service": 5, "result": "error"}) - ) - self.assertRaises( - InvalidArgumentException, self.response.service_response, response_msg - ) + response_msg = loads(dumps({"op": "service_response", "service": 5, "result": "error"})) + self.assertRaises(InvalidArgumentException, self.response.service_response, response_msg) def test_advertise_service(self): service_path = "/set_bool_1" @@ -124,8 +110,7 @@ def test_call_advertised_service(self): loop_iterations += 1 if loop_iterations > 3: self.fail( - "did not receive service call rosbridge message " - "after waiting 2 seconds" + "did not receive service call rosbridge message " "after waiting 2 seconds" ) self.assertFalse(self.received_message is None) @@ -154,8 +139,7 @@ def test_call_advertised_service(self): loop_iterations += 1 if loop_iterations > 3: self.fail( - "did not receive service response rosbridge message " - "after waiting 2 seconds" + "did not receive service response rosbridge message " "after waiting 2 seconds" ) self.assertFalse(self.received_message is None) @@ -199,8 +183,7 @@ def test_unadvertise_with_live_request(self): loop_iterations += 1 if loop_iterations > 3: self.fail( - "did not receive service call rosbridge message " - "after waiting 2 seconds" + "did not receive service call rosbridge message " "after waiting 2 seconds" ) self.assertFalse(self.received_message is None) @@ -209,9 +192,7 @@ def test_unadvertise_with_live_request(self): self.assertTrue("id" in self.received_message) # Now send the response - response_msg = loads( - dumps({"op": "unadvertise_service", "service": service_path}) - ) + response_msg = loads(dumps({"op": "unadvertise_service", "service": service_path})) self.received_message = None self.unadvertise.unadvertise_service(response_msg) @@ -221,8 +202,7 @@ def test_unadvertise_with_live_request(self): loop_iterations += 1 if loop_iterations > 3: self.fail( - "did not receive service response rosbridge message " - "after waiting 2 seconds" + "did not receive service response rosbridge message " "after waiting 2 seconds" ) self.assertFalse(self.received_message is None) diff --git a/rosbridge_library/test/capabilities/test_subscribe.py b/rosbridge_library/test/capabilities/test_subscribe.py index 2c48713d3..b1b0dff3a 100755 --- a/rosbridge_library/test/capabilities/test_subscribe.py +++ b/rosbridge_library/test/capabilities/test_subscribe.py @@ -38,9 +38,7 @@ def test_update_params(self): for queue_length in range(min_queue_length, min_queue_length + 10): for frag_size in range(min_frag_size, min_frag_size + 10): sid = throttle_rate * 100 + queue_length * 10 + frag_size - subscription.subscribe( - sid, msg_type, throttle_rate, queue_length, frag_size - ) + subscription.subscribe(sid, msg_type, throttle_rate, queue_length, frag_size) subscription.update_params() @@ -104,9 +102,7 @@ def send(outgoing): proto.send = send - sub.subscribe( - loads(dumps({"op": "subscribe", "topic": topic, "type": msg_type})) - ) + sub.subscribe(loads(dumps({"op": "subscribe", "topic": topic, "type": msg_type}))) p = rospy.Publisher(topic, String, queue_size=5) time.sleep(0.25) diff --git a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py index 96107dc89..673c3164a 100755 --- a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py +++ b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py @@ -65,9 +65,7 @@ def request_service(): # but since its for test/demonstration only .. leave it as it is for now while not done: try: - incoming = sock.recv( - max_msg_length - ) # receive service_response from rosbridge + incoming = sock.recv(max_msg_length) # receive service_response from rosbridge if buffer == "": buffer = incoming if incoming == "": @@ -109,9 +107,7 @@ def request_service(): fragment_count = len(result) print("fragment_count:", fragment_count) announced = int(result[0]["total"]) - if ( - fragment_count == announced - ): # if all fragments received --> sort and defragment + if fragment_count == announced: # if all fragments received --> sort and defragment # sort fragments sorted_result = [None] * fragment_count unsorted_result = [] diff --git a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py index 1a0e157b9..6cea68e95 100755 --- a/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py +++ b/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py @@ -173,9 +173,7 @@ def send_service_response(response): # send response to rosbridge tcp_socket.send(response) -def list_of_fragments( - full_message, fragment_size -): # create fragment messages for a huge message +def list_of_fragments(full_message, fragment_size): # create fragment messages for a huge message message_id = randint(0, 64000) # generate random message id fragments = [] # generate list of data fragments cursor = 0 @@ -190,13 +188,9 @@ def list_of_fragments( fragment = full_message[fragment_begin:fragment_end] fragments.append(fragment) - fragmented_messages_list = ( - [] - ) # generate list of fragmented messages (including headers) + fragmented_messages_list = [] # generate list of fragmented messages (including headers) if len(fragments) > 1: - for count, fragment in enumerate( - fragments - ): # iterate through list and have index counter + for count, fragment in enumerate(fragments): # iterate through list and have index counter fragmented_message_object = { "op": "fragment", # create Python-object for each fragment message "id": str(message_id), @@ -212,9 +206,7 @@ def list_of_fragments( ) # append JSON-object to list of fragmented messages else: # if only 1 fragment --> do not send as fragment, but as service_response fragmented_messages_list.append(str(fragment)) - return ( - fragmented_messages_list # return list of 'ready-to-send' fragmented messages - ) + return fragmented_messages_list # return list of 'ready-to-send' fragmented messages # ##################### helper functions end ################################### diff --git a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py index 688cfa01f..368d6c04c 100755 --- a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py +++ b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py @@ -61,9 +61,7 @@ def request_service(): # but since its for test/demonstration only .. leave it as it is for now while not done: try: - incoming = sock.recv( - max_msg_length - ) # receive service_response from rosbridge + incoming = sock.recv(max_msg_length) # receive service_response from rosbridge if buffer == "": buffer = incoming if incoming == "": @@ -105,9 +103,7 @@ def request_service(): fragment_count = len(result) print("fragment_count:", fragment_count) announced = int(result[0]["total"]) - if ( - fragment_count == announced - ): # if all fragments received --> sort and defragment + if fragment_count == announced: # if all fragments received --> sort and defragment # sort fragments sorted_result = [None] * fragment_count unsorted_result = [] @@ -132,9 +128,7 @@ def request_service(): print("response was None -> service was not available") else: print("received:") - print( - returned_data["values"]["data"].decode("base64", "strict") - ) # decode values-field + print(returned_data["values"]["data"].decode("base64", "strict")) # decode values-field except Exception as e: print("ERROR - could not receive service_response") diff --git a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py index 2ed08b254..c9a156f3c 100755 --- a/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py +++ b/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py @@ -37,9 +37,7 @@ def calculate_service_response(request): request_object = json.loads(request) # parse string for service request args = request_object["args"] # get parameter field (args) - count = int( - args["count"] - ) # get parameter(s) as described in corresponding ROS srv-file + count = int(args["count"]) # get parameter(s) as described in corresponding ROS srv-file message = "" # calculate service response @@ -55,9 +53,7 @@ def calculate_service_response(request): --> use .decode("base64","strict") at client side """ message = message.encode("base64", "strict") - service_response_data = { - "data": message - } # service response (as defined in srv-file) + service_response_data = {"data": message} # service response (as defined in srv-file) response_object = { "op": "service_response", @@ -179,9 +175,7 @@ def send_service_response(response): # send response to rosbridge tcp_socket.send(response) -def list_of_fragments( - full_message, fragment_size -): # create fragment messages for a huge message +def list_of_fragments(full_message, fragment_size): # create fragment messages for a huge message message_id = randint(0, 64000) # generate random message id fragments = [] # generate list of data fragments cursor = 0 @@ -196,13 +190,9 @@ def list_of_fragments( fragment = full_message[fragment_begin:fragment_end] fragments.append(fragment) - fragmented_messages_list = ( - [] - ) # generate list of fragmented messages (including headers) + fragmented_messages_list = [] # generate list of fragmented messages (including headers) if len(fragments) > 1: - for count, fragment in enumerate( - fragments - ): # iterate through list and have index counter + for count, fragment in enumerate(fragments): # iterate through list and have index counter fragmented_message_object = { "op": "fragment", # create Python-object for each fragment message "id": str(message_id), @@ -218,9 +208,7 @@ def list_of_fragments( ) # append JSON-object to list of fragmented messages else: # if only 1 fragment --> do not send as fragment, but as service_response fragmented_messages_list.append(str(fragment)) - return ( - fragmented_messages_list # return list of 'ready-to-send' fragmented messages - ) + return fragmented_messages_list # return list of 'ready-to-send' fragmented messages # ##################### helper functions end ################################### diff --git a/rosbridge_library/test/internal/publishers/test_publisher_manager.py b/rosbridge_library/test/internal/publishers/test_publisher_manager.py index fd653913a..f0a739957 100755 --- a/rosbridge_library/test/internal/publishers/test_publisher_manager.py +++ b/rosbridge_library/test/internal/publishers/test_publisher_manager.py @@ -80,9 +80,7 @@ def test_register_publisher_conflicting_types(self): self.assertTrue(topic in manager._publishers) self.assertTrue(self.is_topic_published(topic)) - self.assertRaises( - TypeConflictException, manager.register, "client2", topic, msg_type_bad - ) + self.assertRaises(TypeConflictException, manager.register, "client2", topic, msg_type_bad) def test_register_multiple_publishers(self): topic1 = "/test_register_multiple_publishers1" @@ -182,9 +180,7 @@ def test_publish_not_registered(self): self.assertFalse(topic in manager._publishers) self.assertFalse(self.is_topic_published(topic)) - self.assertRaises( - TopicNotEstablishedException, manager.publish, client, topic, msg - ) + self.assertRaises(TopicNotEstablishedException, manager.publish, client, topic, msg) def test_publisher_manager_publish(self): """Make sure that publishing works""" @@ -211,9 +207,7 @@ def test_publisher_manager_bad_publish(self): msg = {"data": 3} manager.register(client, topic, msg_type) - self.assertRaises( - FieldTypeMismatchException, manager.publish, client, topic, msg - ) + self.assertRaises(FieldTypeMismatchException, manager.publish, client, topic, msg) PKG = "rosbridge_library" diff --git a/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py b/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py index 7034c9bb2..9e0f82769 100755 --- a/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py +++ b/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py @@ -120,9 +120,7 @@ def test_register_no_msgtype(self): self.assertFalse(topic in manager._subscribers) self.assertFalse(self.is_topic_subscribed(topic)) - self.assertRaises( - TopicNotEstablishedException, manager.subscribe, client, topic, None - ) + self.assertRaises(TopicNotEstablishedException, manager.subscribe, client, topic, None) def test_register_infer_topictype(self): topic = "/test_register_infer_topictype" @@ -169,9 +167,7 @@ def test_subscribe_not_registered(self): self.assertFalse(topic in manager._subscribers) self.assertFalse(self.is_topic_subscribed(topic)) - self.assertRaises( - TopicNotEstablishedException, manager.subscribe, client, topic, None - ) + self.assertRaises(TopicNotEstablishedException, manager.subscribe, client, topic, None) def test_publisher_manager_publish(self): topic = "/test_publisher_manager_publish" diff --git a/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py b/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py index bf1d4412e..c5243de97 100755 --- a/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py +++ b/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py @@ -19,15 +19,11 @@ def test_default_message_handler(self): self.help_test_default(handler) def test_throttle_message_handler(self): - handler = subscribe.ThrottleMessageHandler( - subscribe.MessageHandler(None, self.dummy_cb) - ) + handler = subscribe.ThrottleMessageHandler(subscribe.MessageHandler(None, self.dummy_cb)) self.help_test_throttle(handler, 50) def test_queue_message_handler_passes_msgs(self): - handler = subscribe.QueueMessageHandler( - subscribe.MessageHandler(None, self.dummy_cb) - ) + handler = subscribe.QueueMessageHandler(subscribe.MessageHandler(None, self.dummy_cb)) self.help_test_queue(handler, 1000) handler.finish() diff --git a/rosbridge_library/test/internal/test_cbor_conversion.py b/rosbridge_library/test/internal/test_cbor_conversion.py index a59788c31..8a5f0e4f1 100755 --- a/rosbridge_library/test/internal/test_cbor_conversion.py +++ b/rosbridge_library/test/internal/test_cbor_conversion.py @@ -86,12 +86,8 @@ def test_time(self): msg = msg_type() extracted = extract_cbor_values(msg) - self.assertEqual( - extracted["data"]["secs"], msg.data.secs, f"type={msg_type}" - ) - self.assertEqual( - extracted["data"]["nsecs"], msg.data.nsecs, f"type={msg_type}" - ) + self.assertEqual(extracted["data"]["secs"], msg.data.secs, f"type={msg_type}") + self.assertEqual(extracted["data"]["nsecs"], msg.data.nsecs, f"type={msg_type}") self.assertEqual(type(extracted["data"]["secs"]), int, f"type={msg_type}") self.assertEqual(type(extracted["data"]["nsecs"]), int, f"type={msg_type}") diff --git a/rosbridge_library/test/internal/test_message_conversion.py b/rosbridge_library/test/internal/test_message_conversion.py index 9868fd34a..e171f44ae 100755 --- a/rosbridge_library/test/internal/test_message_conversion.py +++ b/rosbridge_library/test/internal/test_message_conversion.py @@ -93,9 +93,7 @@ def test_float_special_cases(self): for msg in [1e9999999, -1e9999999, float("nan")]: for rostype in ["float32", "float64"]: self.assertEqual(c._from_inst(msg, rostype), None) - self.assertEqual( - dumps({"data": c._from_inst(msg, rostype)}), '{"data": null}' - ) + self.assertEqual(dumps({"data": c._from_inst(msg, rostype)}), '{"data": null}') def test_signed_int_base_msgs(self): int8s = range(-127, 128) @@ -120,21 +118,15 @@ def test_signed_int_base_msgs(self): self.do_primitive_test(int32, "std_msgs/Int64") self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Byte") self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Int8") - self.assertRaises( - Exception, self.do_primitive_test, int32, "std_msgs/Int16" - ) + self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Int16") int64s = [-9223372036854775807, 9223372036854775807] for int64 in int64s: self.do_primitive_test(int64, "std_msgs/Int64") self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Byte") self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Int8") - self.assertRaises( - Exception, self.do_primitive_test, int64, "std_msgs/Int16" - ) - self.assertRaises( - Exception, self.do_primitive_test, int64, "std_msgs/Int32" - ) + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Int16") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Int32") def test_unsigned_int_base_msgs(self): int8s = range(0, 256) @@ -151,21 +143,15 @@ def test_unsigned_int_base_msgs(self): self.do_primitive_test(int16, "std_msgs/UInt32") self.do_primitive_test(int16, "std_msgs/UInt64") self.assertRaises(Exception, self.do_primitive_test, int16, "std_msgs/Char") - self.assertRaises( - Exception, self.do_primitive_test, int16, "std_msgs/UInt8" - ) + self.assertRaises(Exception, self.do_primitive_test, int16, "std_msgs/UInt8") int32s = [2147483647, 2147483648, 4294967295] for int32 in int32s: self.do_primitive_test(int32, "std_msgs/UInt32") self.do_primitive_test(int32, "std_msgs/UInt64") self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Char") - self.assertRaises( - Exception, self.do_primitive_test, int32, "std_msgs/UInt8" - ) - self.assertRaises( - Exception, self.do_primitive_test, int32, "std_msgs/UInt16" - ) + self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/UInt8") + self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/UInt16") int64s = [ 4294967296, @@ -176,15 +162,9 @@ def test_unsigned_int_base_msgs(self): for int64 in int64s: self.do_primitive_test(int64, "std_msgs/UInt64") self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Char") - self.assertRaises( - Exception, self.do_primitive_test, int64, "std_msgs/UInt8" - ) - self.assertRaises( - Exception, self.do_primitive_test, int64, "std_msgs/UInt16" - ) - self.assertRaises( - Exception, self.do_primitive_test, int64, "std_msgs/UInt32" - ) + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/UInt8") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/UInt16") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/UInt32") def test_bool_base_msg(self): self.do_primitive_test(True, "std_msgs/Bool") diff --git a/rosbridge_library/test/internal/test_ros_loader.py b/rosbridge_library/test/internal/test_ros_loader.py index 768bf0af1..5c8cc988a 100755 --- a/rosbridge_library/test/internal/test_ros_loader.py +++ b/rosbridge_library/test/internal/test_ros_loader.py @@ -195,9 +195,7 @@ def test_nonexistent_packagenames(self): "pr2thoughts_msgs/Escape", ] for x in nonexistent: - self.assertRaises( - ros_loader.InvalidPackageException, ros_loader.get_message_class, x - ) + self.assertRaises(ros_loader.InvalidPackageException, ros_loader.get_message_class, x) self.assertRaises( ros_loader.InvalidPackageException, ros_loader.get_message_instance, x ) @@ -211,12 +209,8 @@ def test_packages_without_msgs(self): "topic_tools/MessageMessage", ] for x in no_msgs: - self.assertRaises( - ros_loader.InvalidModuleException, ros_loader.get_message_class, x - ) - self.assertRaises( - ros_loader.InvalidModuleException, ros_loader.get_message_instance, x - ) + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_message_class, x) + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_message_instance, x) def test_nonexistent_msg_classnames(self): nonexistent = [ @@ -231,12 +225,8 @@ def test_nonexistent_msg_classnames(self): "sensor_msgs/TelepathyUnit", ] for x in nonexistent: - self.assertRaises( - ros_loader.InvalidClassException, ros_loader.get_message_class, x - ) - self.assertRaises( - ros_loader.InvalidClassException, ros_loader.get_message_instance, x - ) + self.assertRaises(ros_loader.InvalidClassException, ros_loader.get_message_class, x) + self.assertRaises(ros_loader.InvalidClassException, ros_loader.get_message_instance, x) def test_bad_servicenames(self): bad = [ @@ -343,12 +333,8 @@ def test_srv_cache(self): def test_packages_without_srvs(self): no_msgs = ["roslib/A", "roslib/B", "roslib/C", "std_msgs/CuriousSrv"] for x in no_msgs: - self.assertRaises( - ros_loader.InvalidModuleException, ros_loader.get_service_class, x - ) - self.assertRaises( - ros_loader.InvalidModuleException, ros_loader.get_service_instance, x - ) + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_service_class, x) + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_service_instance, x) self.assertRaises( ros_loader.InvalidModuleException, ros_loader.get_service_request_instance, @@ -368,9 +354,7 @@ def test_nonexistent_service_packagenames(self): "revenge_srvs/BackStab", ] for x in nonexistent: - self.assertRaises( - ros_loader.InvalidPackageException, ros_loader.get_service_class, x - ) + self.assertRaises(ros_loader.InvalidPackageException, ros_loader.get_service_class, x) self.assertRaises( ros_loader.InvalidPackageException, ros_loader.get_service_instance, x ) @@ -394,12 +378,8 @@ def test_nonexistent_service_classnames(self): "topic_tools/TellMeWhatThisTopicIsActuallyAbout", ] for x in nonexistent: - self.assertRaises( - ros_loader.InvalidClassException, ros_loader.get_service_class, x - ) - self.assertRaises( - ros_loader.InvalidClassException, ros_loader.get_service_instance, x - ) + self.assertRaises(ros_loader.InvalidClassException, ros_loader.get_service_class, x) + self.assertRaises(ros_loader.InvalidClassException, ros_loader.get_service_instance, x) self.assertRaises( ros_loader.InvalidClassException, ros_loader.get_service_request_instance, diff --git a/rosbridge_library/test/internal/test_services.py b/rosbridge_library/test/internal/test_services.py index 90990ac18..dbf2e9259 100755 --- a/rosbridge_library/test/internal/test_services.py +++ b/rosbridge_library/test/internal/test_services.py @@ -102,18 +102,14 @@ def test_populate_request_args(self): cls = ros_loader.get_service_class("rosbridge_library/" + srv_type) for args in [[], {}, None]: # Should throw no exceptions - services.args_to_service_request_instance( - "", cls._request_class(), args - ) + services.args_to_service_request_instance("", cls._request_class(), args) # Test msgs with data message for srv_type in ["TestRequestOnly", "TestRequestAndResponse"]: cls = ros_loader.get_service_class("rosbridge_library/" + srv_type) for args in [[3], {"data": 3}]: # Should throw no exceptions - services.args_to_service_request_instance( - "", cls._request_class(), args - ) + services.args_to_service_request_instance("", cls._request_class(), args) self.assertRaises( FieldTypeMismatchException, services.args_to_service_request_instance, @@ -123,9 +119,7 @@ def test_populate_request_args(self): ) # Test message with multiple fields - cls = ros_loader.get_service_class( - "rosbridge_library/TestMultipleRequestFields" - ) + cls = ros_loader.get_service_class("rosbridge_library/TestMultipleRequestFields") for args in [ [3, 3.5, "hello", False], {"int": 3, "float": 3.5, "string": "hello", "bool": False}, @@ -162,9 +156,7 @@ def error(): raise Exception() # Now, call using the services - services.ServiceCaller( - rospy.get_name() + "/get_loggers", None, success, error - ).start() + services.ServiceCaller(rospy.get_name() + "/get_loggers", None, success, error).start() time.sleep(0.5) @@ -173,9 +165,7 @@ def error(): self.assertEqual(x.level, y["level"]) def test_service_tester(self): - t = ServiceTester( - "/test_service_tester", "rosbridge_library/TestRequestAndResponse" - ) + t = ServiceTester("/test_service_tester", "rosbridge_library/TestRequestAndResponse") t.start() time.sleep(1.0) t.validate(self.msgs_equal) @@ -191,9 +181,7 @@ def test_service_tester_alltypes(self): "TestMultipleRequestFields", "TestArrayRequest", ]: - t = ServiceTester( - "/test_service_tester_alltypes_" + srv, "rosbridge_library/" + srv - ) + t = ServiceTester("/test_service_tester_alltypes_" + srv, "rosbridge_library/" + srv) t.start() ts.append(t) diff --git a/rosbridge_server/scripts/rosbridge_tcp.py b/rosbridge_server/scripts/rosbridge_tcp.py index b265d5d84..d32058384 100755 --- a/rosbridge_server/scripts/rosbridge_tcp.py +++ b/rosbridge_server/scripts/rosbridge_tcp.py @@ -56,22 +56,14 @@ def shutdown_hook(server): # update parameters from parameter server or use default value ( second parameter of get_param ) port = get_param("~port", 9090) host = get_param("~host", "") - incoming_buffer = get_param( - "~incoming_buffer", RosbridgeTcpSocket.incoming_buffer - ) - socket_timeout = get_param( - "~socket_timeout", RosbridgeTcpSocket.socket_timeout - ) + incoming_buffer = get_param("~incoming_buffer", RosbridgeTcpSocket.incoming_buffer) + socket_timeout = get_param("~socket_timeout", RosbridgeTcpSocket.socket_timeout) retry_startup_delay = get_param("~retry_startup_delay", 5.0) # seconds - fragment_timeout = get_param( - "~fragment_timeout", RosbridgeTcpSocket.fragment_timeout - ) + fragment_timeout = get_param("~fragment_timeout", RosbridgeTcpSocket.fragment_timeout) delay_between_messages = get_param( "~delay_between_messages", RosbridgeTcpSocket.delay_between_messages ) - max_message_size = get_param( - "~max_message_size", RosbridgeTcpSocket.max_message_size - ) + max_message_size = get_param("~max_message_size", RosbridgeTcpSocket.max_message_size) unregister_timeout = get_param( "~unregister_timeout", RosbridgeTcpSocket.unregister_timeout ) @@ -200,8 +192,7 @@ def shutdown_hook(server): RosbridgeTcpSocket.topics_glob = [] else: RosbridgeTcpSocket.topics_glob = [ - element.strip().strip("'") - for element in value[1:-1].split(",") + element.strip().strip("'") for element in value[1:-1].split(",") ] else: print( @@ -217,8 +208,7 @@ def shutdown_hook(server): RosbridgeTcpSocket.services_glob = [] else: RosbridgeTcpSocket.services_glob = [ - element.strip().strip("'") - for element in value[1:-1].split(",") + element.strip().strip("'") for element in value[1:-1].split(",") ] else: print( @@ -234,8 +224,7 @@ def shutdown_hook(server): RosbridgeTcpSocket.params_glob = [] else: RosbridgeTcpSocket.params_glob = [ - element.strip().strip("'") - for element in value[1:-1].split(",") + element.strip().strip("'") for element in value[1:-1].split(",") ] else: print( diff --git a/rosbridge_server/scripts/rosbridge_udp.py b/rosbridge_server/scripts/rosbridge_udp.py index 18b5c7b23..072448511 100755 --- a/rosbridge_server/scripts/rosbridge_udp.py +++ b/rosbridge_server/scripts/rosbridge_udp.py @@ -165,9 +165,7 @@ def shutdown_hook(): element.strip().strip("'") for element in value[1:-1].split(",") ] else: - print( - "--topics_glob argument provided without a value. (can be None or a list)" - ) + print("--topics_glob argument provided without a value. (can be None or a list)") sys.exit(-1) if "--services_glob" in sys.argv: @@ -181,9 +179,7 @@ def shutdown_hook(): element.strip().strip("'") for element in value[1:-1].split(",") ] else: - print( - "--services_glob argument provided without a value. (can be None or a list)" - ) + print("--services_glob argument provided without a value. (can be None or a list)") sys.exit(-1) if "--params_glob" in sys.argv: @@ -197,9 +193,7 @@ def shutdown_hook(): element.strip().strip("'") for element in value[1:-1].split(",") ] else: - print( - "--params_glob argument provided without a value. (can be None or a list)" - ) + print("--params_glob argument provided without a value. (can be None or a list)") sys.exit(-1) # To be able to access the list of topics and services, you must be able to access the rosapi services. diff --git a/rosbridge_server/scripts/rosbridge_websocket.py b/rosbridge_server/scripts/rosbridge_websocket.py index f1e80fb48..c3c0e2cc6 100755 --- a/rosbridge_server/scripts/rosbridge_websocket.py +++ b/rosbridge_server/scripts/rosbridge_websocket.py @@ -70,13 +70,9 @@ def __init__(self): ################################################## # Parameter handling # ################################################## - retry_startup_delay = self.declare_parameter( - "retry_startup_delay", 2.0 - ).value # seconds. + retry_startup_delay = self.declare_parameter("retry_startup_delay", 2.0).value # seconds. - RosbridgeWebSocket.use_compression = self.declare_parameter( - "use_compression", False - ).value + RosbridgeWebSocket.use_compression = self.declare_parameter("use_compression", False).value # get RosbridgeProtocol parameters RosbridgeWebSocket.fragment_timeout = self.declare_parameter( @@ -110,9 +106,7 @@ def __init__(self): certfile = self.declare_parameter("certfile").value keyfile = self.declare_parameter("keyfile").value # if authentication should be used - RosbridgeWebSocket.authenticate = self.declare_parameter( - "authenticate", False - ).value + RosbridgeWebSocket.authenticate = self.declare_parameter("authenticate", False).value port = self.declare_parameter("port", 9090).value @@ -201,9 +195,7 @@ def __init__(self): value = sys.argv[idx] RosbridgeWebSocket.max_message_size = int(value) else: - print( - "--max_message_size argument provided without a value. (can be )" - ) + print("--max_message_size argument provided without a value. (can be )") sys.exit(-1) if "--unregister_timeout" in sys.argv: @@ -225,9 +217,7 @@ def __init__(self): element.strip().strip("'") for element in value[1:-1].split(",") ] else: - print( - "--topics_glob argument provided without a value. (can be None or a list)" - ) + print("--topics_glob argument provided without a value. (can be None or a list)") sys.exit(-1) if "--services_glob" in sys.argv: @@ -241,9 +231,7 @@ def __init__(self): element.strip().strip("'") for element in value[1:-1].split(",") ] else: - print( - "--services_glob argument provided without a value. (can be None or a list)" - ) + print("--services_glob argument provided without a value. (can be None or a list)") sys.exit(-1) if "--params_glob" in sys.argv: @@ -257,9 +245,7 @@ def __init__(self): element.strip().strip("'") for element in value[1:-1].split(",") ] else: - print( - "--params_glob argument provided without a value. (can be None or a list)" - ) + print("--params_glob argument provided without a value. (can be None or a list)") sys.exit(-1) if ("--bson_only_mode" in sys.argv) or bson_only_mode: @@ -311,14 +297,11 @@ def __init__(self): server = HTTPServer(application, ssl_options=ssl_options) server.add_sockets(sockets) self.declare_parameter("actual_port", actual_port) - self.get_logger().info( - f"Rosbridge WebSocket server started on port {actual_port}" - ) + self.get_logger().info(f"Rosbridge WebSocket server started on port {actual_port}") connected = True except OSError as e: self.get_logger().warn( - "Unable to start server: {} " - "Retrying in {}s.".format(e, retry_startup_delay) + "Unable to start server: {} " "Retrying in {}s.".format(e, retry_startup_delay) ) time.sleep(retry_startup_delay) diff --git a/rosbridge_server/src/rosbridge_server/tcp_handler.py b/rosbridge_server/src/rosbridge_server/tcp_handler.py index 95e77d439..a9c779674 100755 --- a/rosbridge_server/src/rosbridge_server/tcp_handler.py +++ b/rosbridge_server/src/rosbridge_server/tcp_handler.py @@ -49,9 +49,7 @@ def setup(self): cls.clients_connected += 1 if cls.client_count_pub: cls.client_count_pub.publish(cls.clients_connected) - self.protocol.log( - "info", "connected. " + str(cls.clients_connected) + " client total." - ) + self.protocol.log("info", "connected. " + str(cls.clients_connected) + " client total.") except Exception as exc: rospy.logerr("Unable to accept incoming connection. Reason: %s", str(exc)) @@ -127,9 +125,7 @@ def finish(self): self.protocol.finish() if cls.client_count_pub: cls.client_count_pub.publish(cls.clients_connected) - self.protocol.log( - "info", "disconnected. " + str(cls.clients_connected) + " client total." - ) + self.protocol.log("info", "disconnected. " + str(cls.clients_connected) + " client total.") def send_message(self, message=None): """ diff --git a/rosbridge_server/src/rosbridge_server/websocket_handler.py b/rosbridge_server/src/rosbridge_server/websocket_handler.py index b3e0b7d19..6ad620504 100755 --- a/rosbridge_server/src/rosbridge_server/websocket_handler.py +++ b/rosbridge_server/src/rosbridge_server/websocket_handler.py @@ -138,9 +138,7 @@ def send_message(self, message): binary = False with self._write_lock: - IOLoop.instance().add_callback( - partial(self.prewrite_message, message, binary) - ) + IOLoop.instance().add_callback(partial(self.prewrite_message, message, binary)) @coroutine def prewrite_message(self, message, binary): diff --git a/rosbridge_server/test/websocket/smoke.test.py b/rosbridge_server/test/websocket/smoke.test.py index 62c6e144f..2337213d7 100644 --- a/rosbridge_server/test/websocket/smoke.test.py +++ b/rosbridge_server/test/websocket/smoke.test.py @@ -95,15 +95,11 @@ async def get_server_port(self): """ Returns the port which the WebSocket server is running on """ - client = self.node.create_client( - GetParameters, "/rosbridge_websocket/get_parameters" - ) + client = self.node.create_client(GetParameters, "/rosbridge_websocket/get_parameters") try: if not client.wait_for_service(5): raise RuntimeError("GetParameters service not available") - port_param = await client.call_async( - GetParameters.Request(names=["actual_port"]) - ) + port_param = await client.call_async(GetParameters.Request(names=["actual_port"])) return port_param.values[0].integer_value finally: self.node.destroy_client(client) @@ -141,9 +137,7 @@ def callback(): def test_smoke(self): ros_received = [] - sub_a = self.node.create_subscription( - String, A_TOPIC, ros_received.append, NUM_MSGS - ) + sub_a = self.node.create_subscription(String, A_TOPIC, ros_received.append, NUM_MSGS) pub_b = self.node.create_publisher(String, B_TOPIC, NUM_MSGS) async def run_test(): @@ -188,9 +182,7 @@ async def run_test(): return ws_client.received future = self.executor.create_task(run_test) - reactor.callInThread( - rclpy.spin_until_future_complete, self.node, future, self.executor - ) + reactor.callInThread(rclpy.spin_until_future_complete, self.node, future, self.executor) reactor.run(installSignalHandlers=False) ws_received = future.result()