Skip to content

Commit

Permalink
Add more unit tags for yaml files (ros#331)
Browse files Browse the repository at this point in the history
Co-authored-by: Robert Haschke <rhaschke@users.noreply.github.com>
  • Loading branch information
BrunoB81HK and rhaschke authored Mar 10, 2024
1 parent b183cf5 commit 7045754
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 19 deletions.
37 changes: 23 additions & 14 deletions src/xacro/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from __future__ import print_function, division

import ast
import collections
import enum
import glob
import math
import os
Expand Down Expand Up @@ -115,25 +117,32 @@ def __getattr__(self, item):
__getitem__ = __getattr__


def construct_angle_radians(loader, node):
"""utility function to construct radian values from yaml"""
value = loader.construct_scalar(node)
try:
return float(safe_eval(value, _global_symbols))
except SyntaxError:
raise XacroException("invalid expression: %s" % value)


def construct_angle_degrees(loader, node):
"""utility function for converting degrees into radians from yaml"""
return math.radians(construct_angle_radians(loader, node))
class ConstructUnits(enum.Enum):
"""utility enumeration to construct a values with a unit from yaml"""
__ConstructUnitsValue = collections.namedtuple('__ConstructUnitsValue', ['tag', 'conversion_constant'])
# Angles [base: radians]
angle_radians = __ConstructUnitsValue(u'!radians', 1.0)
angle_degrees = __ConstructUnitsValue(u'!degrees', math.pi/180.0)
# Length [base: meters]
length_meters = __ConstructUnitsValue(u'!meters', 1.0)
length_millimeters = __ConstructUnitsValue(u'!millimeters', 0.001)
length_foot = __ConstructUnitsValue(u'!foot', 0.3048)
length_inches = __ConstructUnitsValue(u'!inches', 0.0254)

def constructor(self, loader, node):
"""utility function to construct a values with a unit from yaml"""
value = loader.construct_scalar(node)
try:
return float(safe_eval(value, _global_symbols))*self.value.conversion_constant
except SyntaxError:
raise XacroException("invalid expression: %s" % value)


def load_yaml(filename):
try:
import yaml
yaml.SafeLoader.add_constructor(u'!radians', construct_angle_radians)
yaml.SafeLoader.add_constructor(u'!degrees', construct_angle_degrees)
for unit in ConstructUnits:
yaml.SafeLoader.add_constructor(unit.value.tag, unit.constructor)
except Exception:
raise XacroException("yaml support not available; install python-yaml")

Expand Down
12 changes: 9 additions & 3 deletions test/constructors.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
a: !degrees 2*90
b: !radians 0.5*pi
c: 42
no_tag: 42
angles:
- !radians pi
- !degrees 2*90
lengths:
- !meters 5.0*5.0
- !millimeters 25.0*1000.0
- !foot 25.0/0.3048
- !inches 25.0/0.0254
4 changes: 2 additions & 2 deletions test/test_xacro.py
Original file line number Diff line number Diff line change
Expand Up @@ -1500,9 +1500,9 @@ def test_yaml_custom_constructors(self):
src = '''
<a xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:property name="values" value="${xacro.load_yaml('constructors.yaml')}"/>
<values a="${values.a}" b="${values.b}" c="${values.c}"/>
<values no_tag="${values.no_tag}" angles="${values.angles}" lengths="${values.lengths}"/>
</a>'''
res = '''<a><values a="{}" b="{}" c="42"/></a>'''.format(math.pi, 0.5*math.pi)
res = '''<a><values no_tag="42" angles="{}" lengths="{}"/></a>'''.format([math.pi]*2, [25.0]*4)
self.assert_matches(self.quick_xacro(src), res)

def test_yaml_custom_constructors_illegal_expr(self):
Expand Down

0 comments on commit 7045754

Please sign in to comment.