Skip to content

Commit

Permalink
Add new conditions for checking launch configuration values (#453) (#457
Browse files Browse the repository at this point in the history
)

* Add new conditions for checking launch configuration values

Resolves #452

These are useful for conditioning launch file actions based on the values of launch configurations.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Fix doc typo

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
  • Loading branch information
jacobperron authored Aug 27, 2020
1 parent 325d2b7 commit c139da8
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 0 deletions.
4 changes: 4 additions & 0 deletions launch/launch/conditions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@
from .evaluate_condition_expression_impl import evaluate_condition_expression
from .if_condition import IfCondition
from .invalid_condition_expression_error import InvalidConditionExpressionError
from .launch_configuration_equals import LaunchConfigurationEquals
from .launch_configuration_not_equals import LaunchConfigurationNotEquals
from .unless_condition import UnlessCondition

__all__ = [
'evaluate_condition_expression',
'IfCondition',
'InvalidConditionExpressionError',
'LaunchConfigurationEquals',
'LaunchConfigurationNotEquals',
'UnlessCondition',
]
67 changes: 67 additions & 0 deletions launch/launch/conditions/launch_configuration_equals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright 2020 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Module for LaunchConfigurationEquals class."""

from typing import Optional
from typing import Text

from ..condition import Condition
from ..launch_context import LaunchContext
from ..some_substitutions_type import SomeSubstitutionsType
from ..utilities import normalize_to_list_of_substitutions
from ..utilities import perform_substitutions


class LaunchConfigurationEquals(Condition):
"""
Condition on the value of a launch configuration.
This condition takes an optional string expression that is compared with the value of
a launch configuration.
If the value is equal to the launch configuration value, then this ``Condition``
evaluates to ``True``.
The expression may consist of :py:class:`launch.Substitution` instances.
If ``None`` is provided instead of a string expression, then the condition
evaluates to ``True`` if the launch configuration is not set.
"""

def __init__(
self,
launch_configuration_name: SomeSubstitutionsType,
expected_value: Optional[SomeSubstitutionsType]
) -> None:
self.__launch_configuration_name = launch_configuration_name
if expected_value is not None:
self.__expected_value = normalize_to_list_of_substitutions(expected_value)
else:
self.__expected_value = None
super().__init__(predicate=self._predicate_func)

def _predicate_func(self, context: LaunchContext) -> bool:
expanded_expected_value = None
if self.__expected_value is not None:
expanded_expected_value = perform_substitutions(context, self.__expected_value)
try:
value = context.launch_configurations[self.__launch_configuration_name]
return value == expanded_expected_value
except KeyError:
if expanded_expected_value is None:
return True
return False

def describe(self) -> Text:
"""Return a description of this Condition."""
return self.__repr__()
51 changes: 51 additions & 0 deletions launch/launch/conditions/launch_configuration_not_equals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright 2020 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Module for LaunchConfigurationNotEquals class."""

from typing import Optional
from typing import Text

from .launch_configuration_equals import LaunchConfigurationEquals
from ..launch_context import LaunchContext
from ..some_substitutions_type import SomeSubstitutionsType


class LaunchConfigurationNotEquals(LaunchConfigurationEquals):
"""
Condition on the value of a launch configuration.
This condition takes an optional string expression that is compared with the value of
a launch configuration.
If the value is not equal to the launch configuration value, then this ``Condition``
evaluates to ``True``.
The expression may consist of :py:class:`launch.Substitution` instances.
If ``None`` is provided instead of a string expression, then the condition
evaluates to ``True`` if the launch configuration is set.
"""

def __init__(
self,
launch_configuration_name: SomeSubstitutionsType,
expected_value: Optional[SomeSubstitutionsType]
) -> None:
super().__init__(launch_configuration_name, expected_value)

def _predicate_func(self, context: LaunchContext) -> bool:
return not super()._predicate_func(context)

def describe(self) -> Text:
"""Return a description of this Condition."""
return self.__repr__()
53 changes: 53 additions & 0 deletions launch/test/launch/conditions/test_launch_configuration_equals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright 2020 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Tests for the LaunchConfigurationEquals condition class."""

from launch.conditions import LaunchConfigurationEquals
from launch.substitutions import TextSubstitution


def test_launch_configuration_equals():
"""Test LaunchConfigurationEquals class."""
class MockLaunchContext:

def perform_substitution(self, substitution):
return substitution.perform(self)

@property
def launch_configurations(self):
return {
'foo': 'foo_value',
'bar': 'bar_value',
'empty': '',
}

lc = MockLaunchContext()
test_cases = [
('foo', 'foo_value', True),
('bar', 'bar_value', True),
('bar', 'foo_value', False),
('bar', None, False),
('empty', '', True),
('empty', 'foo_value', False),
('empty', None, False),
('baz', None, True),
('baz', 'foo_value', False),
]

for name, value, expected in test_cases:
assert LaunchConfigurationEquals(
name,
[TextSubstitution(text=value)] if value is not None else None
).evaluate(lc) is expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright 2020 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Tests for the LaunchConfigurationNotEquals condition class."""

from launch.conditions import LaunchConfigurationNotEquals
from launch.substitutions import TextSubstitution


def test_launch_configuration_not_equals():
"""Test LaunchConfigurationNotEquals class."""
class MockLaunchContext:

def perform_substitution(self, substitution):
return substitution.perform(self)

@property
def launch_configurations(self):
return {
'foo': 'foo_value',
'bar': 'bar_value',
'empty': '',
}

lc = MockLaunchContext()
test_cases = [
('foo', 'foo_value', False),
('bar', 'bar_value', False),
('bar', 'foo_value', True),
('bar', None, True),
('empty', '', False),
('empty', 'foo_value', True),
('empty', None, True),
('baz', None, False),
('baz', 'foo_value', True),
]

for name, value, expected in test_cases:
assert LaunchConfigurationNotEquals(
name,
[TextSubstitution(text=value)] if value is not None else None
).evaluate(lc) is expected

0 comments on commit c139da8

Please sign in to comment.