Skip to content

Commit 266c2b9

Browse files
authored
Backport error message improvements (ros2#754)
* Improve launch file parsing error messages Backport of ros2#626: * Parser errors clearly show that values are substituted and not part of the error message itself. * On an InvalidLaunchFileError, all parsing errors are logged. * Add exception type to error output Backport of ros2#753: * Output exception type for InvalidLaunchFileErrors * Add test checking for exception type in output Signed-off-by: David Yackzan <[email protected]>
1 parent aed025e commit 266c2b9

File tree

4 files changed

+46
-9
lines changed

4 files changed

+46
-9
lines changed

launch/launch/invalid_launch_file_error.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ def __init__(self, extension='', *, likely_errors=None):
2828
)
2929
else:
3030
self._error_message = (
31-
'Caught exception when trying to load file of format [{}]: {}'
32-
).format(self._extension, self._likely_errors[0])
31+
'Caught {} when trying to load file of format [{}]:'
32+
).format('multiple exceptions' if len(self._likely_errors) > 1 else 'exception',
33+
self._extension)
34+
for error in self._likely_errors:
35+
self._error_message += '\n - {}: {}'.format(type(error).__name__, error)
36+
3337
self.__cause__ = self._likely_errors[0]
3438

3539
def __str__(self):
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Copyright 2024 Open Source Robotics Foundation, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from launch.invalid_launch_file_error import InvalidLaunchFileError
16+
17+
18+
def test_invalid_launch_file_error():
19+
try:
20+
exception = KeyError('Test')
21+
raise InvalidLaunchFileError(extension='.py', likely_errors=[exception])
22+
except InvalidLaunchFileError as ex:
23+
assert 'KeyError' in ex.__str__()
24+
25+
26+
def test_invalid_launch_file_errors():
27+
try:
28+
exceptions = [ValueError('Test1'), AttributeError('Test2'), BufferError('Test3')]
29+
raise InvalidLaunchFileError(extension='.py', likely_errors=exceptions)
30+
except InvalidLaunchFileError as ex:
31+
assert 'ValueError' in ex.__str__()
32+
assert 'AttributeError' in ex.__str__()
33+
assert 'BufferError' in ex.__str__()

launch_xml/launch_xml/entity.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def __init__(
3636
*,
3737
parent: 'Entity' = None
3838
) -> Text:
39-
"""Construnctor."""
39+
"""Construct the Entity."""
4040
self.__xml_element = xml_element
4141
self.__parent = parent
4242
self.__read_attributes = set()
@@ -91,7 +91,7 @@ def get_attr(
9191
If coercion fails, `ValueError` will be raised.
9292
"""
9393
attr_error = AttributeError(
94-
'Attribute {} of type {} not found in Entity {}'.format(
94+
"Attribute '{}' of type '{}' not found in Entity '{}'".format(
9595
name, data_type, self.type_name
9696
)
9797
)
@@ -123,8 +123,8 @@ def get_attr(
123123
value = get_typed_value(value, data_type, can_be_str=can_be_str)
124124
except ValueError:
125125
raise TypeError(
126-
'Attribute {} of Entity {} expected to be of type {}.'
127-
'`{}` can not be converted to one of those types'.format(
126+
"Attribute '{}' of Entity '{}' expected to be of type '{}'."
127+
"'{}' can not be converted to one of those types".format(
128128
name, self.type_name, data_type, value
129129
)
130130
)

launch_yaml/launch_yaml/entity.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def get_attr(
116116
if name not in self.__element:
117117
if not optional:
118118
raise AttributeError(
119-
'Can not find attribute {} in Entity {}'.format(
119+
"Can not find attribute '{}' in Entity '{}'".format(
120120
name, self.type_name))
121121
else:
122122
return None
@@ -126,13 +126,13 @@ def get_attr(
126126
if isinstance(data, list) and isinstance(data[0], dict):
127127
return [Entity(child, name) for child in data]
128128
raise TypeError(
129-
'Attribute {} of Entity {} expected to be a list of dictionaries.'.format(
129+
"Attribute '{}' of Entity '{}' expected to be a list of dictionaries.".format(
130130
name, self.type_name
131131
)
132132
)
133133
if not is_instance_of(data, data_type, can_be_str=can_be_str):
134134
raise TypeError(
135-
'Attribute {} of Entity {} expected to be of type {}, got {}'.format(
135+
"Attribute '{}' of Entity '{}' expected to be of type '{}', got '{}'".format(
136136
name, self.type_name, data_type, type(data)
137137
)
138138
)

0 commit comments

Comments
 (0)