Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix resolving of properties declared and used in/from a namespace #306

Merged
merged 1 commit into from Jan 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 8 additions & 7 deletions src/xacro/__init__.py
Expand Up @@ -848,23 +848,24 @@ def handle_dynamic_macro_call(node, macros, symbols):
raise XacroException("unknown macro name '%s' in xacro:call" % name)


def resolve_macro(fullname, macros):
def resolve_macro(fullname, macros, symbols):
# split name into namespaces and real name
namespaces = fullname.split('.')
name = namespaces.pop(-1)

def _resolve(namespaces, name, macros):
# traverse namespaces to actual macros dict
def _resolve(namespaces, name, macros, symbols):
# traverse namespaces to actual macros+symbols dicts
for ns in namespaces:
macros = macros[ns]
return macros, macros[name]
symbols = symbols[ns]
return macros, symbols, macros[name]

# try fullname and (namespaces, name) in this order
try:
return _resolve([], fullname, macros)
return _resolve([], fullname, macros, symbols)
except KeyError:
if namespaces:
return _resolve(namespaces, name, macros)
return _resolve(namespaces, name, macros, symbols)
else:
raise

Expand All @@ -878,7 +879,7 @@ def handle_macro_call(node, macros, symbols):
return False

try:
macros, m = resolve_macro(name, macros)
macros, symbols, m = resolve_macro(name, macros, symbols)
if name is node.tagName: # no xacro prefix provided?
deprecated_tag(name)
body = m.body.cloneNode(deep=True)
Expand Down
8 changes: 8 additions & 0 deletions test/include3.xacro
@@ -0,0 +1,8 @@
<a xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:include filename="./inner.xacro" />
<xacro:property name="var" value="3"/>
<xacro:macro name="foo">
<xacro:element xacro:name="inc${var}" included="${included}"/>
<xacro:included/>
</xacro:macro>
</a>
5 changes: 5 additions & 0 deletions test/inner.xacro
@@ -0,0 +1,5 @@
<?xml version="1.0"?>
<defs xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:property name="included" value="inner" />
<xacro:macro name="included"><inner/></xacro:macro>
</defs>
18 changes: 12 additions & 6 deletions test/test_xacro.py
Expand Up @@ -260,17 +260,17 @@ def test_is_valid_name(self):
self.assertFalse(xacro.is_valid_name('invalid.too')) # dot separates fields

def test_resolve_macro(self):
# define three nested macro dicts with the same macro names (keys)
# define three nested dicts with the same names (keys)
content = {'simple': 'simple'}
ns2 = dict({k: v + '2' for k, v in content.items()})
ns1 = dict({k: v + '1' for k, v in content.items()})
ns1.update(ns2=ns2)
macros = dict(content)
macros.update(ns1=ns1)
ns = dict(content)
ns.update(ns1=ns1)

self.assertEqual(xacro.resolve_macro('simple', macros), (macros, 'simple'))
self.assertEqual(xacro.resolve_macro('ns1.simple', macros), (ns1, 'simple1'))
self.assertEqual(xacro.resolve_macro('ns1.ns2.simple', macros), (ns2, 'simple2'))
self.assertEqual(xacro.resolve_macro('simple', ns, ns), (ns, ns, 'simple'))
self.assertEqual(xacro.resolve_macro('ns1.simple', ns, ns), (ns1, ns1, 'simple1'))
self.assertEqual(xacro.resolve_macro('ns1.ns2.simple', ns, ns), (ns2, ns2, 'simple2'))

def check_macro_arg(self, s, param, forward, default, rest):
p, v, r = xacro.parse_macro_arg(s)
Expand Down Expand Up @@ -1285,6 +1285,12 @@ def test_include_from_macro(self):
res = '''<a><inc1/><inc1/><subdir_inc1/><subdir_inc1/></a>'''
self.assert_matches(self.quick_xacro(src), res)

def test_namespace_propagation(self):
src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:include filename="include3.xacro" ns="C"/><xacro:C.foo/></a>'''
res = '''<a><inc3 included="inner"/><inner/></a>'''
self.assert_matches(self.quick_xacro(src), res)

def test_dotify(self):
src = '''
<a xmlns:xacro="http://www.ros.org/xacro">
Expand Down