Skip to content
Open
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
27 changes: 24 additions & 3 deletions launch_param_builder/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from typing import List, Union
import xacro
from ament_index_python.packages import get_package_share_directory
import math


class ParameterBuilderFileNotFoundError(KeyError):
Expand All @@ -52,6 +53,20 @@ class ParameterBuilderFileNotFoundError(KeyError):
]


def construct_angle_radians(loader, node):
"""Utility function to construct radian values from YAML."""
value = loader.construct_scalar(node)
try:
return float(value)
except SyntaxError:
raise Exception(f"invalid expression: {value}")


def construct_angle_degrees(loader, node):
"""Utility function for converting degrees into radians from YAML."""
return math.radians(construct_angle_radians(loader, node))


def raise_if_file_not_found(file_path: Path):
if not file_path.exists():
raise ParameterBuilderFileNotFoundError(f"File {file_path} doesn't exist")
Expand All @@ -62,17 +77,23 @@ def load_file(file_path: Path):
try:
with open(file_path, "r") as file:
return file.read()
except EnvironmentError: # parent of IOError, OSError *and* WindowsError where available
except OSError: # parent of IOError, OSError *and* WindowsError where available
return None


def load_yaml(file_path: Path):
raise_if_file_not_found(file_path)

try:
yaml.SafeLoader.add_constructor("!radians", construct_angle_radians)
yaml.SafeLoader.add_constructor("!degrees", construct_angle_degrees)
except Exception:
raise Exception("yaml support not available; install python-yaml")

try:
with open(file_path, "r") as file:
return yaml.load(file, Loader=yaml.FullLoader)
except EnvironmentError: # parent of IOError, OSError *and* WindowsError where available
return yaml.safe_load(file)
Comment on lines +87 to +95
Copy link

@sea-bass sea-bass Feb 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on this resource and some limitation I found when integrating this in Studio, I have a suggestion.

First, make a function like this which we can use standalone:

def get_yaml_loader():
    """Gets a YAML loader that additionally supports custom constructors."""
    loader = yaml.SafeLoader
    loader.add_constructor("!radians", construct_angle_radians)
    loader.add_constructor("!degrees", construct_angle_degrees)
    return loader

Then, in your implementation, you can do:

def load_yaml(file_path: Path, loader=get_yaml_loader()):
    ...
    return yaml.load(file, Loader=loader)

except OSError: # parent of IOError, OSError *and* WindowsError where available
return None


Expand Down