Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions launch/launch/actions/include_launch_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,13 @@ def execute(self, context: LaunchContext) -> List[Union[SetLaunchConfiguration,
if argument.name not in argument_names:
raise RuntimeError(
"Included launch description missing required argument '{}' "
"(description: '{}'), given: [{}]"
.format(argument.name, argument.description, ', '.join(argument_names))
"(description: '{}'), given: [{}] (launch file: '{}')"
.format(
argument.name,
argument.description,
', '.join(argument_names),
self.__launch_description_source.location,
)
)

# Create actions to set the launch arguments into the launch configurations.
Expand Down
13 changes: 12 additions & 1 deletion launch/launch/invalid_launch_file_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,17 @@
class InvalidLaunchFileError(Exception):
"""Exception raised when the given launch file is not valid."""

def __init__(self, extension: str = '', *, likely_errors: Optional[List[Exception]] = None):
def __init__(
self,
extension: str = '',
*,
likely_errors: Optional[List[Exception]] = None,
launch_file_path: Optional[str] = None,
):
"""Create an InvalidLaunchFileError."""
self._extension = extension
self._likely_errors = likely_errors
self._launch_file_path = launch_file_path
if self._extension == '' or not self._likely_errors:
self._error_message = (
'The launch file may have a syntax error, or its format is unknown'
Expand All @@ -39,6 +46,10 @@ def __init__(self, extension: str = '', *, likely_errors: Optional[List[Exceptio

self.__cause__ = self._likely_errors[0]

if self._launch_file_path is not None:
self._error_message = "Error loading '{}':\n{}".format(
self._launch_file_path, self._error_message)

def __str__(self) -> str:
"""Pretty print."""
return self._error_message
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,5 @@ def get_launch_description_from_any_launch_file(
return loader(launch_file_path)
except Exception as ex:
exceptions.append(ex)
raise InvalidLaunchFileError(extension, likely_errors=exceptions)
raise InvalidLaunchFileError(
extension, likely_errors=exceptions, launch_file_path=launch_file_path)
15 changes: 15 additions & 0 deletions launch/test/launch/actions/test_include_launch_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,18 @@ def test_include_python():
assert len(action.launch_arguments) == 0

assert action.launch_description_source.location == str(simple_launch_file_path)


def test_missing_required_include_argument_identifies_launch_file(tmp_path):
"""A missing argument error identifies the included launch file."""
launch_file_path = str(tmp_path / 'included.launch.py')
launch_description = LaunchDescription([DeclareLaunchArgument('required_argument')])
action = IncludeLaunchDescription(
LaunchDescriptionSource(launch_description, launch_file_path)
)

with pytest.raises(RuntimeError) as exc_info:
action.visit(LaunchContext())

assert 'Included launch description missing required argument' in str(exc_info.value)
assert launch_file_path in str(exc_info.value)
19 changes: 19 additions & 0 deletions launch/test/launch/test_invalid_launch_file_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
# limitations under the License.

from launch.invalid_launch_file_error import InvalidLaunchFileError
from launch.launch_description_sources import any_launch_file_utilities

import pytest


def test_invalid_launch_file_error():
Expand All @@ -31,3 +34,19 @@ def test_invalid_launch_file_errors():
assert 'ValueError' in ex.__str__()
assert 'AttributeError' in ex.__str__()
assert 'BufferError' in ex.__str__()


def test_invalid_launch_file_error_includes_path(tmp_path):
"""The error for a failed launch file load identifies the file path."""
launch_file_path = tmp_path / 'broken.launch.py'
launch_file_path.write_text(
'def generate_launch_description(:\n pass\n',
encoding='utf-8',
)

with pytest.raises(InvalidLaunchFileError) as exc_info:
any_launch_file_utilities.get_launch_description_from_any_launch_file(
str(launch_file_path))

assert str(launch_file_path) in str(exc_info.value)
assert 'SyntaxError' in str(exc_info.value)