Go to the documentation of this file.
36 from __future__
import print_function
39 from contextlib
import contextmanager
51 from xml.dom.minidom
import parseString
54 from cStringIO
import StringIO
56 from io
import StringIO
59 from unittest
import subTest
67 whitespace = re.compile(
r'\s+')
72 if whitespace.sub(
' ', a).strip() == whitespace.sub(
' ', b).strip():
76 a_dict = ast.literal_eval(a)
77 b_dict = ast.literal_eval(b)
78 if (isinstance(a_dict, dict)
and isinstance(b_dict, dict)
and a_dict == b_dict):
84 def match_splits(a_, b_):
85 if len(a_) != len(b_):
87 for a, b
in zip(a_, b_):
91 if abs(float(a) - float(b)) > 1.0e-9:
97 return match_splits(a.split(), b.split())
101 if len(a.attributes) != len(b.attributes):
102 print(
'Different number of attributes')
104 a_atts = a.attributes.items()
105 b_atts = b.attributes.items()
109 for a, b
in zip(a_atts, b_atts):
111 print(
'Different attribute names: %s and %s' % (a[0], b[0]))
114 print(
'Different attribute values: %s and %s' % (a[1], b[1]))
122 print(
"Different text values: '%s' and '%s'" % (a, b))
132 if a.nodeType != b.nodeType:
133 print(
'Different node types: %s and %s' % (a, b))
137 if a.nodeType
in [xml.dom.Node.TEXT_NODE,
138 xml.dom.Node.CDATA_SECTION_NODE,
139 xml.dom.Node.COMMENT_NODE]:
143 if a.nodeType != xml.dom.Node.ELEMENT_NODE:
147 if a.nodeName != b.nodeName:
148 print(
'Different element names: %s and %s' % (a.nodeName, b.nodeName))
160 ((a.nodeType
in ignore_nodes)
or
161 (a.nodeType == xml.dom.Node.TEXT_NODE
and whitespace.sub(
'', a.data) ==
""))):
164 ((b.nodeType
in ignore_nodes)
or
165 (b.nodeType == xml.dom.Node.TEXT_NODE
and whitespace.sub(
'', b.data) ==
""))):
180 if isinstance(a, str):
181 return xml_matches(parseString(a).documentElement, b, ignore_nodes)
182 if isinstance(b, str):
183 return xml_matches(a, parseString(b).documentElement, ignore_nodes)
184 if a.nodeType == xml.dom.Node.DOCUMENT_NODE:
185 return xml_matches(a.documentElement, b, ignore_nodes)
186 if b.nodeType == xml.dom.Node.DOCUMENT_NODE:
187 return xml_matches(a, b.documentElement, ignore_nodes)
190 print(
'Match failed:')
191 a.writexml(sys.stdout)
194 b.writexml(sys.stdout)
203 old, sys.stderr = sys.stderr, StringIO()
204 result = function(*args, **kwargs)
206 yield (result, sys.stderr.read())
213 self.assertTrue(top.top()
is top)
216 self.assertTrue(sub.top()
is top)
220 self.assertTrue(
'a' in top)
222 self.assertFalse(
'b' in top)
224 self.assertTrue(
'b' in top)
228 for key
in [
'a',
'b',
'c']:
229 self.assertTrue(key
in sub)
233 self.assertEqual(top[
'a'], 1)
235 self.assertEqual(top[
'b'], 2)
239 for i, key
in enumerate([
'a',
'b',
'c']):
240 self.assertEqual(sub[key], i+1)
248 self.assertEqual(sub[
'b'], 3)
249 self.assertEqual(top[
'b'], 2)
252 self.assertFalse(
'b' in sub)
253 self.assertFalse(
'b' in top)
256 with capture_stderr(xacro.Table.__setitem__, sub,
'a', 42)
as (_, output):
257 self.assertTrue(
'redefining global symbol: a' in output)
258 self.assertEqual(sub[
'a'], 42)
259 self.assertEqual(sub.parent[
'a'], 1)
262 with capture_stderr(xacro.Table.__delitem__, sub,
'a')
as (_, output):
263 self.assertTrue(
'Cannot remove global symbol: a' in output)
264 self.assertEqual(sub[
'a'], 1)
269 with capture_stderr(xacro.error,
'Hello World', alt_text=
'')
as (result, output):
270 self.assertEqual(output,
'Hello World\n')
278 self.assertTrue(
text_matches(
" foo bar ",
"foo \t\n\r bar"))
281 self.assertTrue(
text_matches(
"0.123456789",
"0.123456788"))
284 self.assertFalse(
text_matches(
"0.123456789",
"0.1234567879"))
287 self.assertTrue(
text_matches(
"{'a': 1, 'b': 2, 'c': 3}",
"{'c': 3, 'b': 2, 'a': 1}"))
290 self.assertFalse(
text_matches(
"{'a': 1, 'b': 2, 'c': 3}",
"{'c': 3, 'b': 2, 'a': 0}"))
293 self.assertTrue(
xml_matches(
'''<foo/>''',
'''<foo> \t\n\r </foo>'''))
296 self.assertTrue(
xml_matches(
'''<foo> \t\n\r </foo>''',
'''<foo/>'''))
299 self.assertTrue(
xml_matches(
'''<a><b/></a>''',
'''<a>\n<b> </b> </a>'''))
302 self.assertTrue(
xml_matches(
'''<a><b/><!-- foo --> <!-- bar --></a>''',
303 '''<a><b/></a>''', [xml.dom.Node.COMMENT_NODE]))
322 content = {
'simple':
'simple'}
323 ns2 = dict({k: v +
'2' for k, v
in content.items()})
324 ns1 = dict({k: v +
'1' for k, v
in content.items()})
329 self.assertEqual(xacro.resolve_macro(
'simple', ns, ns), (ns, ns,
'simple'))
330 self.assertEqual(xacro.resolve_macro(
'ns1.simple', ns, ns), (ns1, ns1,
'simple1'))
331 self.assertEqual(xacro.resolve_macro(
'ns1.ns2.simple', ns, ns), (ns2, ns2,
'simple2'))
335 self.assertEqual(p, param, msg=
"'{0}' != '{1}' parsing {2}".format(p, param, s))
336 if forward
or default:
337 self.assertTrue(v
is not None)
338 self.assertEqual(v[0], forward, msg=
"'{0}' != '{1}' parsing {2}".format(v[0], forward, s))
339 self.assertEqual(v[1], default, msg=
"'{0}' != '{1}' parsing {2}".format(v[1], default, s))
341 self.assertTrue(v
is None)
342 self.assertEqual(r, rest, msg=
"'{0}' != '{1}' parsing {2}".format(r, rest, s))
345 for forward
in [
'',
'^',
'^|']:
346 defaults = [
'',
"'single quoted'",
'"double quoted"',
'${2 * (prop_with_spaces + 1)}',
'$(substitution arg)',
347 "anything~w/o~space-'space allowed in quotes'(\"as here too\")",
'unquoted']
350 for default
in defaults:
351 seps = [
'=',
':=']
if forward
or default
else [
'']
353 for rest
in [
'',
' ',
' bar',
' bar=42']:
354 s =
'foo{0}{1}{2}{3}'.format(sep, forward, default, rest)
356 default
if default
else None,
360 for ws
in [
' ',
' \t ',
' \n ']:
361 self.
check_macro_arg(ws +
'foo' + ws +
'bar=42' + ws,
'foo',
None,
None,
'bar=42' + ws)
364 tokens = [
'ab',
'cd',
'ef']
365 for sep
in [
' ',
',',
';',
', ']:
369 tokens =
' '.join([
'ab',
' ',
'cd',
'ef'])
371 self.assertEqual(len(results), 5)
372 self.assertEqual(
' '.join(results), tokens)
378 super(TestXacroBase, self).
__init__(*args, **kwargs)
388 args.update(vars(opts))
391 doc = xacro.parse(xml)
392 xacro.filestack =
None
393 xacro.process_doc(doc, **args)
398 subprocess.call([
'xacro', input_path] + args)
404 super(TestXacroCommentsIgnored, self).
__init__(*args, **kwargs)
409 test_dir = os.path.abspath(os.path.dirname(__file__))
410 pr2_xacro_path = os.path.join(test_dir,
'robots',
'pr2',
'pr2.urdf.xacro')
411 pr2_golden_parse_path = os.path.join(test_dir,
'robots',
'pr2',
'pr2_1.11.4.xml')
413 xml.dom.minidom.parse(pr2_golden_parse_path),
420 super(TestXacroCommentsIgnored, self).
__init__(*args, **kwargs)
424 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
425 <xacro:property name="invalid.name"/></a>'''
429 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
430 <xacro:property name="__hidden"/></a>'''
433 self.assertEqual(str(cm.exception),
'Property names must not start with double underscore:__hidden')
436 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
437 <xacro:macro name="foo"><a>foo</a></xacro:macro>
438 <xacro:macro name="bar"><b>bar</b></xacro:macro>
439 <xacro:property name="var" value="%s"/>
440 <xacro:call macro="${var}"/></a>'''
441 res =
'''<a>%s</a>'''
446 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
447 <xacro:macro name="foo"><a name="foo"/></xacro:macro>
448 <xacro:macro name="call"><a name="bar"/></xacro:macro>
449 <xacro:call macro="foo"/></a>'''
455 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
456 <xacro:call macro="foo"/></a>''')
461 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
462 <xacro:undefined><foo/><bar/></xacro:undefined></a>''')
465 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
466 <xacro:macro name="foo" params="name"><xacro:element xacro:name="${name}"/></xacro:macro>
467 <xacro:foo name="A"/>
468 <xacro:foo name="B"/>
470 res =
'''<a><A/><B/></a>'''
474 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
475 <xacro:macro name="foo" params="name value">
476 <tag><xacro:attribute name="${name}" value="${value}"/></tag>
478 <xacro:foo name="A" value="foo"/>
479 <xacro:foo name="B" value="bar"/>
481 res =
'''<a><tag A="foo"/><tag B="bar"/></a>'''
486 <xml xmlns:xacro="http://www.ros.org/wiki/xacro">
487 <xacro:property name="foo" value="1.0"/>
488 <xacro:macro name="m" params="foo"><a foo="${foo}"/></xacro:macro>
489 <xacro:m foo="1 ${foo}"/>
490 <!-- now redefining the property and macro -->
491 <xacro:property name="foo" value="2.0"/>
492 <xacro:macro name="m" params="foo"><b bar="${foo}"/></xacro:macro>
493 <xacro:m foo="2 ${foo}"/>
504 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
505 <xacro:macro name="inner" params="*the_block">
506 <in_the_inner><xacro:insert_block name="the_block" /></in_the_inner>
508 <xacro:macro name="outer" params="*the_block">
509 <in_the_outer><xacro:inner><xacro:insert_block name="the_block" /></xacro:inner></in_the_outer>
511 <xacro:outer><woot /></xacro:outer></a>'''
512 res =
'''<a><in_the_outer><in_the_inner><woot /></in_the_inner></in_the_outer></a>'''
516 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
517 <xacro:macro name="foo" params="lst">${lst[-1]}</xacro:macro>
518 <xacro:foo lst="${[1,2,3]}"/></a>'''
522 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
523 <xacro:macro name="foo" params="a='1 -2' c=3"><bar a="${a}" c="${c}"/></xacro:macro>
528 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
529 <xacro:property name="foo" value="42" />
530 <the_foo result="${foo}" />
532 res =
'''<a><the_foo result="42"/></a>'''
536 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
537 <xacro:macro name="foo" params="factor">
538 <xacro:property name="foo" value="${21*factor}" scope="parent"/>
540 <xacro:foo factor="2"/><a foo="${foo}"/></a>'''
544 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
545 <xacro:macro name="foo" params="factor">
546 <xacro:macro name="bar">
547 <xacro:property name="foo" value="${21*factor}" scope="global"/>
551 <xacro:foo factor="2"/><a foo="${foo}"/></a>'''
555 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
556 <xacro:property name="abc" value="${[1,2,3]}"/>
557 <xacro:property name="xyz" value="${[abc[i]*abc[i] for i in [0,1,2]]}"/>
563 src =
'''<a><f v="${0.9 / 2 - 0.2}" /></a>'''
568 '''<a><f v="''' + os.path.abspath((__file__).replace(
".pyc",
".py") +
'''" /></a>'''))
571 res =
'''<a><f v="my_arg" /></a>'''
575 src =
'''<a b="$${foo}" c="$$${foo}" d="text $${foo}" e="text $$${foo}" f="$$(pwd)" />'''
576 res =
'''<a b="${foo}" c="$${foo}" d="text ${foo}" e="text $${foo}" f="$(pwd)" />'''
580 src =
'''<a b="$" c="text $" d="text $ text"/>'''
585 <xacro:macro name="foo" params="*block">
586 <xacro:insert_block name="block" />
587 <xacro:insert_block name="block" />
598 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
599 <xacro:macro name="foo" params="*block{A} *block{B}">
600 <xacro:insert_block name="block1" />
601 <xacro:insert_block name="block2" />
613 for d
in [dict(A=
'1', B=
'2'), dict(A=
'2', B=
'1')]:
618 <xacro:macro name="m" params="num">
619 <test number="${num}" />
621 <xacro:m num="100" />
624 <test number="100" />
629 <xacro:macro name="bar">bar</xacro:macro>
630 <xacro:property name="val" value="2" />
631 <xacro:property name="some_block">
632 <some_block attr="${val}"><xacro:bar/></some_block>
635 <xacro:insert_block name="some_block" />
639 <foo><some_block attr="2">bar</some_block></foo>
643 src =
'''<a xmlns:xacro="http://www.ros.org/xacro"><xacro:include filename="include1.xml"/></a>'''
647 src =
'''<a xmlns:xacro="http://www.ros.org/xacro"><xacro:include filename="include{glob}.xml"/></a>'''
648 res =
'<a><inc1/><inc2/></a>'
649 for pattern
in [
'*',
'?',
'[1-2]']:
654 self.
quick_xacro,
'''<a xmlns:xacro="http://www.ros.org/xacro">
655 <xacro:include filename="include-nada.xml" /></a>''')
659 src =
'''<a><include filename="nada"><tag/></include></a>'''
662 self.assertEqual(output,
'')
665 doc =
'''<a xmlns:xacro="http://www.ros.org/xacro">
666 <xacro:property name="file" value="include1.xml"/>
667 <xacro:include filename="${file}" /></a>'''
672 <a xmlns:xacro="http://www.ros.org/xacro">
673 <xacro:include filename="include1.xml"/>
674 <xacro:include filename="./include1.xml"/>
675 <xacro:include filename="subdir/include-recursive.xacro"/>
677 <a><inc1/><inc1/><subdir_inc1/><subdir_inc1/><inc1/></a>''')
681 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
682 <xacro:property name="var" value="main"/>
683 <xacro:include filename="include1.xacro" ns="A"/>
684 <xacro:include filename="include2.xacro" ns="B"/>
685 <xacro:A.foo/><xacro:B.foo/>
686 <main var="${var}" A="${2*A.var}" B="${B.var+1}"/>
690 <inc1/><inc2/><main var="main" A="2" B="3"/>
695 src =
'''<root xmlns:xacro="http://www.ros.org/wiki/xacro">
696 <xacro:property name="prop" value="outer"/>
697 <xacro:macro name="foo">
698 <outer prop="${prop}"/>
699 <xacro:property name="prop" value="inner"/>
700 <xacro:macro name="foo">
701 <inner prop="${prop}"/>
709 <outer prop="outer"/>
710 <inner prop="inner"/>
711 <outer prop="outer"/>
712 <inner prop="inner"/>
717 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
718 <xacro:if value="false">
721 <xacro:if value="true">
732 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
733 <xacro:if value="nonsense"><foo/></xacro:if></a>''')
737 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
738 <xacro:if value="${0*42}">
744 <xacro:if value="${0}">
747 <xacro:if value="${1*2+3}">
757 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
758 <xacro:if value="${3*0.0}">
761 <xacro:if value="${3*0.1}">
771 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
772 <xacro:property name="condT" value="${True}"/>
773 <xacro:property name="condF" value="${False}"/>
774 <xacro:if value="${condF}"><a /></xacro:if>
775 <xacro:if value="${condT}"><b /></xacro:if>
776 <xacro:if value="${True}"><c /></xacro:if>
784 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
785 <xacro:if value="1"><xacro:if value="0"><a>bar</a></xacro:if></xacro:if>
786 </a>'''),
'''<a/>''')
790 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
791 <xacro:property name="var" value="useit"/>
792 <xacro:if value="${var == 'useit'}"><foo>bar</foo></xacro:if>
793 <xacro:if value="${'use' in var}"><bar>foo</bar></xacro:if>
802 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
803 <xacro:property name="xyz" value="5 -2"/>
812 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
813 <foo function="${1. + sin(pi)}"/>
816 <foo function="1.0"/>
822 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">${__import__('math')}</a>''')
826 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
827 <xacro:macro name="foo" params="arg">
828 <xacro:property name="prop" value="${arg}"/>
829 ${__import__('math')}
836 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">${"".__class__.__base__.__subclasses__()}</a>''')
840 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
841 <xacro:if value="1"><!-- comment --> text <b>bar</b></xacro:if>
843 <a><!-- comment --> text <b>bar</b></a>''')
847 self.
quick_xacro(
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
848 <xacro:macro name="foo" params="*block">
851 <xacro:insert_block name="block" />
854 <!-- ignored comment -->
867 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
870 <!-- ignore multiline comments before any xacro tag -->
872 <xacro:property name="foo" value="1"/>
874 <xacro:if value="1"><!-- B --></xacro:if>
876 <xacro:macro name="foo"><!-- C --></xacro:macro>
880 <a><!-- A --><!-- B --><!-- C --></a>''')
884 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
885 <xacro:property name="a" value=" 42 "/>
886 <xacro:property name="a2" value="${ 2 * a }"/>
895 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
896 <xacro:property name="a2" value="${2*a}"/>
897 <xacro:property name="a" value="42"/>
907 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
908 <xacro:property name="a" value="${a2}"/>
909 <xacro:property name="a2" value="${2*a}"/>
912 msg = str(cm.exception)
913 self.assertTrue(msg.startswith(
'circular variable definition: a2 -> a -> a2\n'
914 'Consider disabling lazy evaluation via lazy_eval="false"'))
917 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
918 <xacro:property name="s" value="AbCd"/>
919 <xacro:property name="s" value="${s.lower()}" lazy_eval="false"/>
925 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
926 <xacro:property name="a" value="1"/>
927 <xacro:property name="b" value="2"/>
928 <xacro:property name="c" value="3"/>
929 <xacro:property name="product" value="${a*b*c}"/>
930 <answer product="${product}"/>
933 <answer product="6"/>
938 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
939 <xacro:property name="a" value="42"/>
940 <xacro:property name="b" value="${a}"/>
941 <xacro:property name="b" value="${-a}"/>
942 <xacro:property name="b" value="${a}"/>
943 <answer b="${b} ${b} ${b}"/>
946 <answer b="42 42 42"/>
951 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
952 <xacro:property name="a" value="42"/>
953 <xacro:property name="b" value="${a}"/>
954 <xacro:property name="c" value="${b}"/>
955 <xacro:property name="d" value="${c}"/>
964 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
965 <xacro:property name="a" value="42"/>
966 <xacro:property name="b" value="2.1"/>
967 <xacro:property name="c" value="${a}"/>
968 <xacro:property name="d" value="${b}"/>
969 <xacro:property name="f" value="${c*d}"/>
978 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
979 <xacro:property name="x" value="42"/>
980 <xacro:property name="wheel_width" value="${x}"/>
981 <link name="my_link">
982 <origin xyz="0 0 ${wheel_width/2}"/>
986 <link name="my_link">
987 <origin xyz="0 0 21.0"/>
993 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
994 <xacro:property name="x" value="0"/>
995 <tag badness="${1/x}"/>
1000 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
1001 <xacro:macro name="fixed_link" params="parent_link:=base_link child_link *joint_pose">
1002 <link name="${child_link}"/>
1003 <joint name="${child_link}_joint" type="fixed">
1004 <xacro:insert_block name="joint_pose" />
1005 <parent link="${parent_link}"/>
1006 <child link="${child_link}" />
1009 <xacro:fixed_link child_link="foo">
1010 <origin xyz="0 0 0" rpy="0 0 0" />
1011 </xacro:fixed_link >
1015 <joint name="foo_joint" type="fixed">
1016 <origin rpy="0 0 0" xyz="0 0 0"/>
1017 <parent link="base_link"/>
1024 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
1025 <xacro:macro name="fixed_link" params="parent_link:=base_link child_link *joint_pose">
1026 <link name="${child_link}"/>
1027 <joint name="${child_link}_joint" type="fixed">
1028 <xacro:insert_block name="joint_pose" />
1029 <parent link="${parent_link}"/>
1030 <child link="${child_link}" />
1033 <xacro:fixed_link child_link="foo" parent_link="bar">
1034 <origin xyz="0 0 0" rpy="0 0 0" />
1035 </xacro:fixed_link >
1039 <joint name="foo_joint" type="fixed">
1040 <origin rpy="0 0 0" xyz="0 0 0"/>
1041 <parent link="bar"/>
1048 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
1049 <xacro:macro name="fixed_link" params="parent_link child_link *joint_pose">
1050 <link name="${child_link}"/>
1051 <joint name="${child_link}_joint" type="fixed">
1052 <xacro:insert_block name="joint_pose" />
1053 <parent link="${parent_link}"/>
1054 <child link="${child_link}" />
1057 <xacro:fixed_link child_link="foo">
1058 <origin xyz="0 0 0" rpy="0 0 0" />
1059 </xacro:fixed_link >
1064 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
1065 <xacro:arg name="foo" default="2"/>
1066 <link name="my_link">
1067 <origin xyz="0 0 $(arg foo)"/>
1072 <link name="my_link">
1073 <origin xyz="0 0 2"/>
1079 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
1080 <xacro:arg name="foo" default="2"/>
1081 <link name="my_link">
1082 <origin xyz="0 0 $(arg foo)"/>
1085 ''', [
'foo:=4']),
'''
1087 <link name="my_link">
1088 <origin xyz="0 0 4"/>
1093 self.assertRaises(Exception, self.
quick_xacro,
'''
1094 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1095 <a arg="$(arg foo)"/>
1101 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1102 <xacro:arg name="foo" default=""/>$(arg foo)</a>'''),
'''<a/>''')
1106 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1107 <xacro:arg name="foo" default="bar"/>${xacro.arg('foo')}</a>'''),
'<a>bar</a>')
1110 self.assertRaises(xml.parsers.expat.ExpatError, self.
quick_xacro,
1111 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1112 <xacro:include filename="broken.xacro"/></a>''')
1113 self.assertEqual(xacro.filestack, [
None,
'./broken.xacro'])
1118 tmp_dir_name = tempfile.mkdtemp()
1119 output_path = os.path.join(tmp_dir_name,
"should_not_exist")
1120 self.
run_xacro(
'broken.xacro',
'-o', output_path)
1122 output_file_created = os.path.isfile(output_path)
1123 shutil.rmtree(tmp_dir_name)
1125 self.assertFalse(output_file_created)
1130 tmp_dir_name = tempfile.mkdtemp()
1131 shutil.rmtree(tmp_dir_name)
1132 output_path = os.path.join(tmp_dir_name,
"out")
1133 self.
run_xacro(
'include1.xml',
'-o', output_path)
1135 output_file_created = os.path.isfile(output_path)
1136 shutil.rmtree(tmp_dir_name)
1138 self.assertTrue(output_file_created)
1142 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1143 <xacro:property name="l" value="[0, 1+1, 2]"/>
1144 <xacro:property name="t" value="(0,1+1,2)"/>
1145 <xacro:property name="d" value="{'a':0, 'b':1+1, 'c':2}"/>
1146 <a list="${l}" tuple="${t}" dict="${d}"/>
1149 <a list="[0, 1+1, 2]" tuple="(0,1+1,2)" dict="{'a':0, 'b':1+1, 'c':2}"/>
1154 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1155 <xacro:property name="l" value="${[0, 1+1, 2]}"/>
1156 <xacro:property name="t" value="${(0,1+1,2)}"/>
1157 <xacro:property name="d" value="${dict(a=0, b=1+1, c=2)}"/>
1158 <a list="${l}" tuple="${t}" dict="${d}"/>
1161 <a list="[0, 2, 2]" tuple="(0, 2, 2)" dict="{'a': 0, 'c': 2, 'b': 2}"/>
1166 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1167 <xacro:property name="f" value="1.23"/>
1168 <xacro:property name="i" value="123"/>
1169 <xacro:property name="s" value="1_2_3"/>
1170 float=${f+1} int=${i+1} string=${s}
1173 float=2.23 int=124 string=1_2_3
1178 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1179 <arg name="foo" value="bar"/>
1180 <include filename="foo"/>
1181 </a>''', xacro_ns=
False),
'''
1183 <arg name="foo" value="bar"/>
1184 <include filename="foo"/>
1192 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1193 <xacro:arg name="foo" default="0.5"/>
1194 <xacro:property name="prop" value="$(arg foo)" />
1195 <a prop="${prop-0.3}"/>
1204 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1205 <xacro:arg name="foo" default="0.5"/>
1206 <xacro:arg name="bar" default="$(arg foo)"/>
1207 <xacro:property name="prop" value="$(arg bar)" />
1208 <a prop="${prop-0.3}"/>
1216 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1217 <xacro:macro name="xacro:my_macro"><foo/></xacro:macro>
1220 res =
'''<a><foo/></a>'''
1223 self.assertTrue(
"macro names must not contain prefix 'xacro:'" in output)
1226 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1227 <xacro:property name="pi" value="3.14"/></a>'''
1230 self.assertTrue(output)
1234 <a xmlns:xacro="http://www.ros.org/xacro">
1235 <xacro:macro name="foo" params="a b:=${a} c:=$${a}"> a=${a} b=${b} c=${c} </xacro:macro>
1236 <xacro:property name="a" value="1"/>
1237 <xacro:property name="d" value="$${a}"/>
1238 <d d="${d}"><xacro:foo a="2"/></d>
1240 res =
'''<a><d d="${a}"> a=2 b=1 c=${a} </d></a>'''
1244 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1245 <xacro:property name="arg" value="42"/>
1246 <xacro:macro name="foo" params="arg:=^%s">${arg}</xacro:macro>
1249 res =
'''<a>%s</a>'''
1255 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">${2*'$(arg var)'}</a>'''
1256 res =
'''<a>%s</a>'''
1260 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">$(arg ${'v'+'ar'})</a>'''
1261 res =
'''<a>%s</a>'''
1265 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro" xacro:targetNamespace="http://www.ros.org"/>'''
1266 res =
'''<a xmlns="http://www.ros.org"/>'''
1270 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro"><b xacro:targetNamespace="http://www.ros.org"/></a>'''
1271 res =
'''<a><b/></a>'''
1275 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">${{xacro.{f}('colored', 'text', 2, 3.14)}}</a>'''
1277 for f
in [
'message',
'warning',
'error']:
1280 self.assertTrue(
'colored text 2 3.14' in output)
1284 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1285 <xacro:include filename="raise.xacro"/>
1291 expected =
'''when instantiating macro: inner ({file})
1292 instantiated from: outer ({file})
1294 '''.format(file=
"./raise.xacro")
1295 self.assertEqual(output, expected)
1298 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro" xmlns:a="http://www.ros.org/a">
1299 <xacro:macro name="test">
1300 <xacro:include filename="namespace.xml"></xacro:include>
1304 res =
'''<a xmlns:a="http://www.ros.org/a" xmlns:b="http://www.ros.org/b" />'''
1308 original =
'<!-- ${name} -->'
1309 processed =
'<!-- foo -->'
1310 enabler =
'<!-- xacro:eval-comments{suffix} -->'
1311 disabler = enabler.format(suffix=
":off")
1313 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1314 <xacro:property name="name" value="foo"/>
1315 {enabler}{comment}{text}{comment}</a>'''
1316 result =
'<a>{c1}{text}{c2}</a>'
1317 for enable, suffix, text
in itertools.product([
False,
True], [
"",
":on",
":off"], [
"",
" ",
" text ",
"<tag/>", disabler]):
1318 src_params = dict(comment=original, text=text,
1319 enabler=enabler.format(suffix=suffix)
if enable
else "")
1320 enabled = enable
and suffix !=
":off"
1321 res_params = dict(c1=processed
if enabled
else original, text=
"" if text == disabler
else text,
1322 c2=processed
if enabled
and not text.strip()
and text != disabler
else original)
1325 except AssertionError
as e:
1326 print(
"When evaluating\n{}".format(src.format(**src_params)))
1330 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1331 <xacro:macro name="scope"><xacro:include filename="location.xacro"/></xacro:macro>
1337 self.assertTrue(output ==
'''when instantiating macro: scope (???)
1338 in file: ./location.xacro
1339 included from: string
1343 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1344 <xacro:property name="str" value="sin"/>
1346 res =
'''<a>sin</a>'''
1349 self.assertTrue(
"redefining global symbol: str" in output)
1352 doc = (
'''<a xmlns:xacro="http://www.ros.org/xacro">
1353 <xacro:if value="false"><xacro:include filename="non-existent"/></xacro:if></a>''')
1358 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1359 <xacro:arg name="has_stuff" default="false"/>
1360 <xacro:if value="$(arg has_stuff)">
1361 <xacro:include file="$(find nonexistent_package)/stuff.urdf" />
1367 src =
'''<a version="1.0" xmlns:xacro="http://www.ros.org/wiki/xacro">
1368 <xacro:include filename="./include2.xacro" ns="B"/>
1369 <xacro:property name="ext" value="main"/>
1370 <xacro:property name="var" value="main"/>
1371 <xacro:B.bar arg="${ext}"/>
1372 <xacro:B.bar arg="${var}"/>
1373 <xacro:B.bar arg="${inner}"/>
1375 res =
'''<a version="1.0">
1376 <a arg="main" ext="main" var="2"/>
1377 <a arg="2" ext="main" var="2"/>
1378 <a arg="int" ext="main" var="2"/>
1384 <a xmlns:xacro="http://www.ros.org/xacro">
1385 <xacro:macro name="foo" params="file:=include1.xml"><xacro:include filename="${file}"/></xacro:macro>
1387 <xacro:foo file="${xacro.abs_filename('include1.xml')}"/>
1388 <xacro:include filename="subdir/foo.xacro"/>
1389 <xacro:foo file="$(cwd)/subdir/include1.xml"/>
1391 res =
'''<a><inc1/><inc1/><subdir_inc1/><subdir_inc1/></a>'''
1395 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1396 <xacro:include filename="include3.xacro" ns="C"/><xacro:C.foo/></a>'''
1397 res =
'''<a><inc3 included="inner"/><inner/></a>'''
1402 <a xmlns:xacro="http://www.ros.org/xacro">
1403 <xacro:property name="settings" value="${xacro.dotify(dict(a=1, b=2))}"/>
1404 ${settings.a + settings.b}
1406 res =
'''<a>3</a>'''
1410 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1411 <xacro:property name="prop" value="root"/>
1412 <root prop="${prop}"/>
1414 <xacro:include filename="A.xacro" ns="A"/>
1415 <root prop="${prop}" A.prop="${A.prop}" A.B.prop="${A.B.prop}" />
1418 <root prop="${prop}"/>
1423 <root A.B.prop="b" A.prop="B" prop="root"/>
1424 <root prop="macro"/>
1430 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1431 <xacro:property name="settings" value="${xacro.load_yaml('settings.yaml')}"/>
1432 <xacro:property name="type" value="$(arg type)"/>
1433 <xacro:include filename="${settings['arms'][type]['file']}"/>
1434 <xacro:call macro="${settings['arms'][type]['macro']}"/>
1436 res =
'''<a><{tag}/></a>'''
1437 for i
in [
'inc1',
'inc2']:
1443 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1444 <xacro:property name="settings" value="${xacro.load_yaml('settings.yaml')}"/>
1445 <xacro:property name="type" value="$(arg type)"/>
1446 <xacro:include filename="${settings.arms[type].file}"/>
1447 <xacro:call macro="${settings.arms[type].macro}"/>
1449 res =
'''<a><{tag}/></a>'''
1450 for i
in [
'inc1',
'inc2']:
1456 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1457 <xacro:property name="settings" value="${xacro.load_yaml('settings.yaml')}"/>
1458 <xacro:property name="bar" value="${settings.baz}"/>
1465 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1466 <xacro:property name="settings" value="${xacro.load_yaml('settings.yaml')}"/>
1467 <xacro:property name="bar" value="${settings.arms.inc2.props.port + 1}"/>
1470 res =
'''<a>4243</a>'''
1475 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1476 <xacro:property name="settings" value="${xacro.load_yaml('settings.yaml')}"/>
1477 ${'arms' in settings} ${'baz' in settings}
1479 res =
'''<a>True False</a>'''
1484 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1485 <xacro:property name="l" value="${xacro.load_yaml('list.yaml')}"/>
1486 ${l[0][1]} ${l[1][0]} ${l[2].a.A} ${l[2].a.B[0]} ${l[2].a.B[1]} ${l[2].b[0]}
1488 res =
'''<a>A2 B1 1 2 3 4</a>'''
1493 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1494 ${[2*item.val.x for item in xacro.load_yaml('list2.yaml')]}
1496 res =
'''<a>[2, 4]</a>'''
1501 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1502 <xacro:property name="values" value="${xacro.load_yaml('constructors.yaml')}"/>
1503 <values no_tag="${values.no_tag}" angles="${values.angles}" lengths="${values.lengths}"/>
1505 res =
'''<a><values no_tag="42" angles="{}" lengths="{}"/></a>'''.format([math.pi]*2, [25.0]*4)
1509 for file
in [
'constructors_bad1.yaml',
'constructors_bad2.yaml']:
1511 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1512 <xacro:property name="values" value="${{xacro.load_yaml({file})}}"/>
1513 <values a="${{values.a}}" />
1519 self.assertTrue(hasattr(yaml,
'arms'))
1520 self.assertFalse(hasattr(yaml,
'this_key_does_not_exist'))
1524 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1525 <xacro:include filename="non-existent.xacro"/>
1531 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1532 <xacro:include filename="non-existent.xacro" optional="True"/>
1538 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1539 <xacro:macro name="foo" params="arg:=${2*foo}">
1540 <xacro:property name="foo" value="-"/>
1543 <xacro:property name="foo" value="${3*7}"/>
1545 <xacro:property name="foo" value="*"/>
1549 <f val="42"/><f val="**"/></a>'''
1554 <a xmlns:xacro="http://www.ros.org/xacro">
1555 <xacro:property name="prop" default="false"/>
1556 <xacro:unless value="${prop}">
1558 <xacro:property name="prop" value="true"/>
1561 <!-- second foo should be ignored -->
1562 <xacro:unless value="${prop}">
1564 <xacro:property name="prop" value="true"/>
1567 res =
'''<a><foo/></a>'''
1571 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">🍔 </a>'''
1575 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1576 <xacro:property name="burger" value="🍔"/>
1578 res =
'''<a>🍔</a>'''
1582 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1583 <xacro:property name="burger" value="🍔"/>
1584 <b c="${burger}"/></a>'''
1585 res =
'''<a><b c="🍔"/></a>'''
1589 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1590 <xacro:property name="burger">
1593 <xacro:insert_block name="burger"/></a>'''
1594 res =
'''<a>🍔</a>'''
1598 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1599 <xacro:property name="burger" value="🍔"/>
1600 <xacro:if value="${burger == u'🍔'}">
1604 res =
'''<a>🍟</a>'''
1608 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1609 <xacro:macro name="burger" params="how_many">
1612 <xacro:burger how_many="4"/>
1614 res =
'''<a>🍔🍔🍔🍔</a>'''
1620 test_dir = os.path.abspath(os.path.dirname(__file__))
1621 input_path = os.path.join(test_dir,
'emoji.xacro')
1622 tmp_dir_name = tempfile.mkdtemp()
1623 output_path = os.path.join(tmp_dir_name,
"out.xml")
1624 self.
run_xacro(input_path,
'-o', output_path)
1625 self.assertTrue(os.path.isfile(output_path))
1626 self.
assert_matches(xml.dom.minidom.parse(output_path),
'''<robot>🍔</robot>''')
1627 shutil.rmtree(tmp_dir_name)
1637 template =
'<a xmlns:xacro="http://www.ros.org/wiki/xacro"><xacro:property name="p" {} /> ${{p}} </a>'
1639 def check(attributes, expected, **kwargs):
1640 with subTest(msg=
'Checking ' + attributes):
1642 self.
quick_xacro(template.format(attributes), **kwargs)
1643 self.assertEqual(str(cm.exception), expected)
1645 expected =
'Property attributes default, value, and remove are mutually exclusive: p'
1646 check(
'value="" default=""', expected)
1647 check(
'value="" remove="true"', expected)
1648 check(
'default="" remove="true"', expected)
1652 src =
'''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1653 <xacro:property name="p" default="1st" />
1654 <xacro:property name="p" remove="true" />
1655 <xacro:property name="p" default="2nd" />
1660 if __name__ ==
'__main__':
def test_parse_macro_whitespace(self)
def test_multiple_insert_blocks(self)
def test_unicode_property_attribute(self)
def test_include_lazy(self)
def test_include_from_variable(self)
def test_default_property(self)
def test_ignore_xacro_comments(self)
def test_default_arg(self)
def test_yaml_support_dotted_list_iterator(self)
def test_normalize_whitespace_text(self)
def test_unicode_property(self)
def test_math_expressions(self)
def assert_matches(self, a, b)
def test_dynamic_macro_names(self)
def test_unicode_file(self)
def test_broken_input_doesnt_create_empty_output_file(self)
def test_integer_if_statement(self)
def test_param_missing(self)
def test_create_subdirs(self)
def test_property_scope_parent_namespaced(self)
def test_print_location(self)
def test_default_arg_override(self)
def run_xacro(self, input_path, *args)
def test_default_param(self)
def test_property_scope_global(self)
def test_transitive_arg_evaluation(self)
def test_substitution_args_find(self)
def test_overwrite_globals(self)
def check_macro_arg(self, s, param, forward, default, rest)
def test_restricted_builtins(self)
def test_is_valid_name(self)
def test_no_evaluation(self)
def test_multi_tree_evaluation(self)
def test_equality_expression_in_if_statement(self)
def test_greedy_property_evaluation(self)
def tokenize(s, sep=',;', skip_empty=True)
def test_invalid_syntax(self)
def test_default_arg_empty(self)
def test_macro_has_new_scope(self)
def test_unicode_literal_parsing(self)
def test_from_issue(self)
def test_yaml_hasattr_support(self)
def test_recursive_evaluation_wrong_order(self)
def test_whitespace_vs_empty_node(self)
def test_default_param_override(self)
def test_mismatch_different_dicts(self)
def all_attributes_match(a, b)
def test_issue_63_fixed_with_inorder_processing(self)
def test_remove_property(self)
def test_xacro_exist_required(self)
def test_yaml_support_dotted(self)
def test_include_with_namespace(self)
def test_iterable_literals_eval(self)
def test_yaml_custom_constructors(self)
def test_tokenize_keep_empty(self)
def test_property_scope_parent(self)
def test_capture_stderr(self, *args, **kwargs)
def test_include_recursive(self)
def quick_xacro(self, xml, cli=None, **kwargs)
def test_invalid_property_name(self)
def test_consider_non_elements_if(self)
def test_property_if_statement(self)
def test_include_from_macro(self)
def test_dynamic_macro_name_clash(self)
def test_recursive_evaluation(self)
def test_macro_default_param_evaluation_order(self)
def test_error_reporting(self)
def test_insert_block_property(self)
def test_macro_undefined(self)
def __init__(self, *args, **kwargs)
def test_include_nonexistent(self)
def test_evaluate_macro_params_before_body(self)
def test_message_functions(self)
def test_iterable_literals_plain(self)
def test_xacro_exist_optional(self)
def test_literals_eval(self)
def test_invalid_property_definitions(self)
def test_mismatch_different_numbers(self)
def test_namespace_propagation(self)
def capture_stderr(function, *args, **kwargs)
def test_recursive_definition(self)
def test_issue_68_numeric_arg(self)
def test_multiple_definition_and_evaluation(self)
def test_xacro_element(self)
def test_property_replacement(self)
def test_expression_in_extension(self)
def test_substitution_args_arg(self)
def test_ignore_comments(self)
def test_default_arg_missing(self)
def test_no_double_evaluation(self)
def test_extension_in_expression(self)
def test_yaml_support_dotted_arith(self)
def test_unicode_conditional(self)
def test_multiple_recursive_evaluation(self)
def test_macro_params_escaped_string(self)
def test_yaml_support_list_of_x(self)
def test_escaping_dollar_braces(self)
def test_target_namespace(self)
def test_recursive_bad_math(self)
def test_inorder_processing(self)
def __init__(self, *args, **kwargs)
def test_boolean_if_statement(self)
def test_restricted_builtins_nested(self)
def test_normalize_whitespace_trim(self)
def test_include_glob(self)
def test_target_namespace_only_from_root(self)
def test_should_replace_before_macroexpand(self)
def test_property_forwarding(self)
def test_unicode_property_block(self)
def xml_matches(a, b, ignore_nodes=[])
def test_enforce_xacro_ns(self)
def test_yaml_support(self)
def nodes_match(a, b, ignore_nodes)
def test_xml_namespace_lifting(self)
def test_multiple_blocks(self)
def test_dynamic_macro_undefined(self)
def test_consider_non_elements_block(self)
def text_values_match(a, b)
def test_parse_macro_arg(self)
def test_just_a_dollar_sign(self)
def test_include_deprecated(self)
def test_invalid_if_statement(self)
def test_float_if_statement(self)
def test_redefine_global_symbol(self)
def test_xacro_attribute(self)
def test_resolve_macro(self)
def test_unicode_macro(self)
def test_match_similar_numbers(self)
def test_macro_name_with_colon(self)
def test_match_unordered_dicts(self)
def test_property_resolution_with_namespaced_include(self)
def test_transitive_evaluation(self)
def test_yaml_support_key_in_dict(self)
def test_integer_stays_integer(self)
def test_normalize_whitespace_nested(self)
def test_property_in_comprehension(self)
def test_double_underscore_property_name_raises(self)
def test_yaml_support_dotted_key_error(self)
def process_args(argv, require_input=True)
def test_broken_include_error_reporting(self)
def test_math_ignores_spaces(self)
def test_empty_node_vs_whitespace(self)
def test_arg_function(self)
def test_consecutive_if(self)
def test_yaml_custom_constructors_illegal_expr(self)
xacro
Author(s): Stuart Glaser, William Woodall, Robert Haschke
autogenerated on Sat Jan 11 2025 03:50:37