Skip to content

Commit 2cd6fa7

Browse files
committed
Merge branch 'rolling' into feat/argument_check_skipping
2 parents 767504c + 9390852 commit 2cd6fa7

File tree

34 files changed

+326
-63
lines changed

34 files changed

+326
-63
lines changed

launch/CHANGELOG.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@
22
Changelog for package launch
33
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44

5+
3.4.1 (2024-03-28)
6+
------------------
7+
* Small fixes for modern flake8. (`#772 <https://github.com/ros2/launch/issues/772>`_)
8+
* Cleanup some type annotations.
9+
* Contributors: Chris Lalancette
10+
11+
3.4.0 (2024-02-07)
12+
------------------
13+
* Rework task exceptions loop. (`#755 <https://github.com/ros2/launch/issues/755>`_)
14+
* add format overriding by environment variables (`#722 <https://github.com/ros2/launch/issues/722>`_)
15+
* Add exception type to error output (`#753 <https://github.com/ros2/launch/issues/753>`_)
16+
* Contributors: Chris Lalancette, David Yackzan, Marc Bestmann
17+
18+
3.3.0 (2024-01-24)
19+
------------------
20+
* Let XML executables/nodes be "required" (like in ROS 1) (`#751 <https://github.com/ros2/launch/issues/751>`_)
21+
* Contributors: Matthew Elwin
22+
23+
3.2.1 (2023-12-26)
24+
------------------
25+
526
3.2.0 (2023-10-04)
627
------------------
728
* Add conditional substitution (`#734 <https://github.com/ros2/launch/issues/734>`_)

launch/launch/actions/execute_process.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from typing import Text
2323

2424
from .execute_local import ExecuteLocal
25-
25+
from .shutdown_action import Shutdown
2626
from ..descriptions import Executable
2727
from ..frontend import Entity
2828
from ..frontend import expose_action
@@ -331,6 +331,16 @@ def parse(
331331
if name is not None:
332332
kwargs['name'] = parser.parse_substitution(name)
333333

334+
if 'on_exit' not in ignore:
335+
on_exit = entity.get_attr('on_exit', optional=True)
336+
if on_exit is not None:
337+
if on_exit == 'shutdown':
338+
kwargs['on_exit'] = [Shutdown()]
339+
else:
340+
raise ValueError(
341+
'Attribute on_exit of Entity node expected to be shutdown but got `{}`'
342+
'Other on_exit actions not yet supported'.format(on_exit))
343+
334344
if 'prefix' not in ignore:
335345
prefix = entity.get_attr('launch-prefix', optional=True)
336346
if prefix is not None:

launch/launch/invalid_launch_file_error.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def __init__(self, extension='', *, likely_errors=None):
3232
).format('multiple exceptions' if len(self._likely_errors) > 1 else 'exception',
3333
self._extension)
3434
for error in self._likely_errors:
35-
self._error_message += '\n - {}'.format(error)
35+
self._error_message += '\n - {}: {}'.format(type(error).__name__, error)
3636

3737
self.__cause__ = self._likely_errors[0]
3838

launch/launch/launch_context.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,24 @@ def __init__(
5252
self.__argv = argv if argv is not None else []
5353
self.__noninteractive = noninteractive
5454

55-
self._event_queue = asyncio.Queue() # type: asyncio.Queue
56-
self._event_handlers = collections.deque() # type: collections.deque
57-
self._completion_futures = [] # type: List[asyncio.Future]
55+
self._event_queue: asyncio.Queue = asyncio.Queue()
56+
self._event_handlers: collections.deque = collections.deque()
57+
self._completion_futures: List[asyncio.Future] = []
5858

59-
self.__globals = {} # type: Dict[Text, Any]
60-
self.__locals_stack = [] # type: List[Dict[Text, Any]]
61-
self.__locals = {} # type: Dict[Text, Any]
62-
self.__combined_locals_cache = None # type: Optional[Dict[Text, Any]]
59+
self.__globals: Dict[Text, Any] = {}
60+
self.__locals_stack: List[Dict[Text, Any]] = []
61+
self.__locals: Dict[Text, Any] = {}
62+
self.__combined_locals_cache: Optional[Dict[Text, Any]] = None
6363

64-
self.__launch_configurations_stack = [] # type: List[Dict[Text, Text]]
65-
self.__launch_configurations = {} # type: Dict[Text, Text]
64+
self.__launch_configurations_stack: List[Dict[Text, Text]] = []
65+
self.__launch_configurations: Dict[Text, Text] = {}
6666

67-
self.__environment_stack = [] # type: List[Mapping[Text, Text]]
67+
self.__environment_stack: List[Mapping[Text, Text]] = []
6868
# We will reset to this copy when "reset_environment" is called
69-
self.__environment_reset = os.environ.copy() # type: Mapping[Text, Text]
69+
self.__environment_reset: Mapping[Text, Text] = os.environ.copy()
7070

7171
self.__is_shutdown = False
72-
self.__asyncio_loop = None # type: Optional[asyncio.AbstractEventLoop]
72+
self.__asyncio_loop: Optional[asyncio.AbstractEventLoop] = None
7373

7474
self.__logger = launch.logging.get_logger(__name__)
7575

launch/launch/launch_service.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -327,14 +327,20 @@ def _on_exception(loop, context):
327327
return_when=asyncio.FIRST_COMPLETED
328328
)
329329
# Propagate exception from completed tasks
330-
completed_tasks_exceptions = [task.exception() for task in completed_tasks]
331-
completed_tasks_exceptions = list(filter(None, completed_tasks_exceptions))
332-
if completed_tasks_exceptions:
333-
self.__logger.debug('An exception was raised in an async action/event')
334-
# in case there is more than one completed_task, log other exceptions
335-
for completed_tasks_exception in completed_tasks_exceptions[1:]:
336-
self.__logger.error(completed_tasks_exception)
337-
raise completed_tasks_exceptions[0]
330+
exception_to_raise = None
331+
for task in completed_tasks:
332+
exc = task.exception()
333+
if exc is None:
334+
continue
335+
336+
if exception_to_raise is None:
337+
self.__logger.debug('An exception was raised in an async action/event')
338+
exception_to_raise = exc
339+
else:
340+
self.__logger.error(exc)
341+
342+
if exception_to_raise is not None:
343+
raise exception_to_raise
338344

339345
except KeyboardInterrupt:
340346
continue

launch/launch/logging/__init__.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,21 @@ def set_screen_format(self, screen_format, *, screen_style=None):
206206
:param screen_format: format specification used when logging to the screen,
207207
as expected by the `logging.Formatter` constructor.
208208
Alternatively, aliases for common formats are available, see above.
209+
This format can also be overridden by the environment variable
210+
'OVERRIDE_LAUNCH_SCREEN_FORMAT'.
209211
:param screen_style: the screen style used if no alias is used for
210212
screen_format.
211213
No style can be provided if a format alias is given.
212214
"""
215+
# Check if the environment variable is set
216+
screen_format_env = os.environ.get('OVERRIDE_LAUNCH_SCREEN_FORMAT')
217+
# If the environment variable is set override the given format
218+
if screen_format_env not in [None, '']:
219+
# encoded escape characters correctly
220+
screen_format = screen_format_env.encode(
221+
'latin1').decode('unicode_escape')
222+
# Set the style correspondingly
223+
screen_style = '{'
213224
if screen_format is not None:
214225
if screen_format == 'default':
215226
screen_format = '[{levelname}] [{name}]: {msg}'
@@ -258,9 +269,20 @@ def set_log_format(self, log_format, *, log_style=None):
258269
as expected by the `logging.Formatter` constructor.
259270
Alternatively, the 'default' alias can be given to log verbosity level,
260271
logger name and logged message.
272+
This format can also be overridden by the environment variable
273+
'OVERRIDE_LAUNCH_LOG_FORMAT'.
261274
:param log_style: the log style used if no alias is given for log_format.
262275
No style can be provided if a format alias is given.
263276
"""
277+
# Check if the environment variable is set
278+
log_format_env = os.environ.get('OVERRIDE_LAUNCH_LOG_FORMAT')
279+
# If the environment variable is set override the given format
280+
if log_format_env not in [None, '']:
281+
# encoded escape characters correctly
282+
log_format = log_format_env.encode(
283+
'latin1').decode('unicode_escape')
284+
# Set the style correspondingly
285+
log_style = '{'
264286
if log_format is not None:
265287
if log_format == 'default':
266288
log_format = '{created:.7f} [{levelname}] [{name}]: {msg}'
@@ -489,7 +511,7 @@ def get_output_loggers(process_name, output_config):
489511

490512
# Mypy does not support dynamic base classes, so workaround by typing the base
491513
# class as Any
492-
_Base = logging.getLoggerClass() # type: Any
514+
_Base: Any = logging.getLoggerClass()
493515

494516

495517
# Track all loggers to support module resets

launch/package.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
33
<package format="2">
44
<name>launch</name>
5-
<version>3.2.0</version>
5+
<version>3.4.1</version>
66
<description>The ROS launch tool.</description>
77

88
<maintainer email="[email protected]">Aditya Pande</maintainer>

launch/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setup(
77
name=package_name,
8-
version='3.2.0',
8+
version='3.4.1',
99
packages=find_packages(exclude=['test']),
1010
data_files=[
1111
('share/' + package_name, ['package.xml']),

launch/test/launch/actions/test_push_and_pop_environment.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_push_and_pop_environment_constructors():
3333
@sandbox_environment_variables
3434
def test_push_and_pop_environment_execute():
3535
"""Test the execute() of the PopEnvironment and PushEnvironment classes."""
36-
assert type(os.environ) == os._Environ
36+
assert isinstance(os.environ, os._Environ)
3737

3838
context = LaunchContext()
3939

@@ -89,4 +89,4 @@ def test_push_and_pop_environment_execute():
8989
assert context.environment['foo'] == 'FOO'
9090

9191
# Pushing and popping the environment should not change the type of os.environ
92-
assert type(os.environ) == os._Environ
92+
assert isinstance(os.environ, os._Environ)

launch/test/launch/frontend/test_substitutions.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from launch import SomeSubstitutionsType
2222
from launch import Substitution
2323
from launch.actions import ExecuteProcess
24+
from launch.frontend import Parser
2425
from launch.frontend.expose import expose_substitution
2526
from launch.frontend.parse_substitution import parse_if_substitutions
2627
from launch.frontend.parse_substitution import parse_substitution
@@ -317,13 +318,13 @@ def test_parse_if_substitutions():
317318
parse_if_substitutions(['$(test asd)', 1, 1.0])
318319

319320

320-
class MockParser:
321+
class MockParser(Parser):
321322

322-
def parse_substitution(self, value: Text) -> SomeSubstitutionsType:
323+
def parse_substitution(self, value: Text) -> List[Substitution]:
323324
return parse_substitution(value)
324325

325326

326-
def test_execute_process_parse_cmd_line():
327+
def test_execute_process_parse_cmd_line() -> None:
327328
"""Test ExecuteProcess._parse_cmd_line."""
328329
parser = MockParser()
329330

0 commit comments

Comments
 (0)