Skip to content

Commit

Permalink
Added a custom launch substitution to modify YAML parameters based on…
Browse files Browse the repository at this point in the history
… launch params - lifecycle version (ros-navigation#771)

* Initial version copied from old code

* Code now installs

You can `import nav2_common.launch.rewritten_yaml` now.

* Bring RewrittenYaml class into launch scope like other launch packages do

This lets you say:
`from nav2_common.launch import RewrittenYaml`
instead of
`from nav2_common.launch.rewritten_yaml import RewrittenYaml`

* Add support for converting strings to non-string values in YAML

By the time RewrittenYaml gets the rewrite values, they've already been
resolved to strings. This is a problem for use_sim_time because the
code only accepts bools. To work around this RewrritenYaml has an option
to convert all values to an actual type.

* Add dependency in nav2_bringup package so it doesn't get forgotten.
  • Loading branch information
Carl Delsey committed Jun 10, 2019
1 parent 3d123cb commit 3746a16
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 0 deletions.
1 change: 1 addition & 0 deletions nav2_bringup/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

<exec_depend>launch_ros</exec_depend>
<exec_depend>navigation2</exec_depend>
<exec_depend>nav2_common</exec_depend>

<test_depend>ament_lint_common</test_depend>
<test_depend>ament_lint_auto</test_depend>
Expand Down
3 changes: 3 additions & 0 deletions nav2_common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.5)
project(nav2_common NONE)

find_package(ament_cmake_core REQUIRED)
find_package(ament_cmake_python REQUIRED)

ament_python_install_package(nav2_common)

ament_package(
CONFIG_EXTRAS "nav2_common-extras.cmake"
Expand Down
Empty file.
1 change: 1 addition & 0 deletions nav2_common/nav2_common/launch/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .rewritten_yaml import RewrittenYaml
98 changes: 98 additions & 0 deletions nav2_common/nav2_common/launch/rewritten_yaml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from typing import Dict
from typing import List
from typing import Text
import yaml
import tempfile
import launch

class DictItemReference:
def __init__(self, dictionary, key):
self.dictionary = dictionary
self.dictKey = key

def key(self):
return self.dictKey

def setValue(self, value):
self.dictionary[self.dictKey] = value

class RewrittenYaml(launch.Substitution):
"""
Substitution that modifies the given Yaml file.
"""

def __init__(self,
source_file: launch.SomeSubstitutionsType,
rewrites: Dict,
convert_types = False) -> None:
super().__init__()

from launch.utilities import normalize_to_list_of_substitutions # import here to avoid loop
self.__source_file = normalize_to_list_of_substitutions(source_file)
self.__rewrites = {}
self.__convert_types = convert_types
for key in rewrites:
self.__rewrites[key] = normalize_to_list_of_substitutions(rewrites[key])

@property
def name(self) -> List[launch.Substitution]:
"""Getter for name."""
return self.__source_file

def describe(self) -> Text:
"""Return a description of this substitution as a string."""
return ''

def perform(self, context: launch.LaunchContext) -> Text:
yaml_filename = launch.utilities.perform_substitutions(context, self.name)
rewritten_yaml = tempfile.NamedTemporaryFile(mode='w', delete=False)
resolved_rewrites = self.resolve_rewrites(context)
data = yaml.load(open(yaml_filename, 'r'))
self.substitute_values(data, resolved_rewrites)
yaml.dump(data, rewritten_yaml)
rewritten_yaml.close()
return rewritten_yaml.name

def resolve_rewrites(self, context):
resolved = {}
for key in self.__rewrites:
resolved[key] = launch.utilities.perform_substitutions(context, self.__rewrites[key])
return resolved

def substitute_values(self, yaml, rewrites):
for key in self.getYamlKeys(yaml):
if key.key() in rewrites:
raw_value = rewrites[key.key()]
key.setValue(self.convert(raw_value))

def getYamlKeys(self, yamlData):
try:
for key in yamlData.keys():
for k in self.getYamlKeys(yamlData[key]):
yield k
yield DictItemReference(yamlData, key)
except AttributeError:
return

def convert(self, text_value):
if self.__convert_types:
# try converting to float
try:
return float(text_value)
except ValueError:
pass

# try converting to int
try:
return int(text_value)
except ValueError:
pass

# try converting to bool
if text_value.lower() == "true":
return True
if text_value.lower() == "false":
return False

#nothing else worked so fall through and return text
return text_value
2 changes: 2 additions & 0 deletions nav2_common/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

<buildtool_depend>ament_cmake_core</buildtool_depend>

<build_depend>ament_cmake_python</build_depend>

<buildtool_export_depend>ament_cmake_core</buildtool_export_depend>

<export>
Expand Down

0 comments on commit 3746a16

Please sign in to comment.