33 from __future__ 
import print_function, division
 
   43 import xml.dom.minidom
 
   45 from copy 
import deepcopy
 
   46 from .cli 
import process_args
 
   47 from .color 
import error, message, warning
 
   48 from .xmlutils 
import opt_attrs, reqd_attrs, first_child_element, \
 
   49     next_sibling_element, replace_node
 
   54     encoding = {
'encoding': 
'utf-8'}
 
   61 substitution_args_context = {}
 
   78     Prepend the dirname of the currently processed file 
   79     if filename_spec is not yet absolute 
   81     if not os.path.isabs(filename_spec):
 
   82         parent_filename = filestack[-1]
 
   83         basedir = os.path.dirname(parent_filename) 
if parent_filename 
else '.' 
   84         return os.path.join(basedir, filename_spec)
 
   89     """Wrapper class for yaml lists to allow recursive inheritance of wrapper property""" 
   92         """This static method, used by both YamlListWrapper and YamlDictWrapper, 
   93            dispatches to the correct wrapper class depending on the type of yaml item""" 
   94         if isinstance(item, dict):
 
   96         elif isinstance(item, list):
 
  102         return YamlListWrapper.wrap(super(YamlListWrapper, self).
__getitem__(idx))
 
  105         for item 
in super(YamlListWrapper, self).
__iter__():
 
  106             yield YamlListWrapper.wrap(item)
 
  110     """Wrapper class providing dotted access to dict items""" 
  113             return YamlListWrapper.wrap(super(YamlDictWrapper, self).
__getitem__(item))
 
  115             raise AttributeError(
"The yaml dictionary has no key '{}'".format(item))
 
  117     __getitem__ = __getattr__
 
  121     """utility enumeration to construct a values with a unit from yaml""" 
  122     __ConstructUnitsValue = collections.namedtuple(
'__ConstructUnitsValue', [
'tag', 
'conversion_constant'])
 
  133         """utility function to construct a values with a unit from yaml""" 
  134         value = loader.construct_scalar(node)
 
  136             return float(
safe_eval(value, _global_symbols))*self.value.conversion_constant
 
  144         for unit 
in ConstructUnits:
 
  145             yaml.SafeLoader.add_constructor(unit.value.tag, unit.constructor)
 
  147         raise XacroException(
"yaml support not available; install python-yaml")
 
  151     filestack.append(filename)
 
  153         return YamlListWrapper.wrap(yaml.safe_load(f))
 
  158         all_includes.append(filename)
 
  162     results = re.split(
'[{}]'.format(sep), s)
 
  164         return [item 
for item 
in results 
if item]
 
  176     def deprecate(f, msg):
 
  177         def wrapper(*args, **kwargs):
 
  179             return f(*args, **kwargs)
 
  181         return wrapper 
if msg 
else f
 
  183     def expose(*args, **kwargs):
 
  185         source, ns, deprecate_msg = (kwargs.pop(key, 
None) 
for key 
in [
'source', 
'ns', 
'deprecate_msg'])
 
  188         if source 
is not None:
 
  189             addons.update([(key, source[key]) 
for key 
in args])  
 
  192         addons.update(**kwargs)  
 
  199                 result.update([(ns, target)])
 
  200             target.update(addons)  
 
  202             if deprecate_msg 
is not None:  
 
  203                 result.update([(key, deprecate(f, deprecate_msg.format(name=key, ns=ns))) 
for key, f 
in addons.items()])
 
  205             result.update(addons)  
 
  207     deprecate_msg = 
'Using {name}() directly is deprecated. Use {ns}.{name}() instead.' 
  209     expose(
'list', 
'dict', 
'map', 
'len', 
'str', 
'float', 
'int', 
'True', 
'False', 
'min', 
'max', 
'round',
 
  212     expose(
'sorted', 
'range', source=__builtins__, ns=
'python', deprecate_msg=deprecate_msg)
 
  214     expose(
'list', 
'dict', 
'map', 
'len', 
'str', 
'float', 
'int', 
'True', 
'False', 
'min', 
'max', 
'round',
 
  215            'abs', 
'all', 
'any', 
'complex', 
'divmod', 
'enumerate', 
'filter', 
'frozenset', 
'hash', 
'isinstance', 
'issubclass',
 
  216            'ord', 
'repr', 
'reversed', 
'slice', 
'set', 
'sum', 
'tuple', 
'type', 
'vars', 
'zip', source=__builtins__, ns=
'python')
 
  219     expose([(k, v) 
for k, v 
in math.__dict__.items() 
if not k.startswith(
'_')], ns=
'math', deprecate_msg=
'')
 
  222     expose(load_yaml=load_yaml, abs_filename=abs_filename_spec, dotify=YamlDictWrapper,
 
  223            ns=
'xacro', deprecate_msg=deprecate_msg)
 
  224     expose(arg=
lambda name: substitution_args_context[
'arg'][name], ns=
'xacro')
 
  226     def message_adapter(f):
 
  227         def wrapper(*args, **kwargs):
 
  228             location = kwargs.pop(
'print_location', f.__name__ 
in [
'warning', 
'error'])
 
  229             kwargs.pop(
'file', 
None)  
 
  240     expose([(f.__name__, message_adapter(f)) 
for f 
in [message, warning, error, print_location]], ns=
'xacro')
 
  241     expose(fatal=fatal, tokenize=tokenize, ns=
'xacro')
 
  247     code = compile(expr.strip(), 
"<expression>", 
"eval")
 
  248     invalid_names = [n 
for n 
in code.co_names 
if n.startswith(
"__")]
 
  250         raise XacroException(
"Use of invalid name(s): ", 
', '.join(invalid_names))
 
  251     globals.update(__builtins__= {})  
 
  252     return eval(code, globals, locals)
 
  257     XacroException allows to wrap another exception (exc) and to augment 
  258     its error message: prefixing with msg and suffixing with suffix. 
  259     str(e) finally prints: msg str(exc) suffix 
  262     def __init__(self, msg=None, suffix=None, exc=None, macro=None):
 
  263         super(XacroException, self).
__init__(msg)
 
  266         self.
macros = [] 
if macro 
is None else [macro]
 
  270         return ' '.join([s 
for s 
in [
unicode(e) 
for e 
in items] 
if s 
not in [
'', 
'None']])
 
  278     Helper routine to fetch required and optional attributes 
  279     and complain about any additional attributes. 
  280     :param tag (xml.dom.Element): DOM element node 
  281     :param required [str]: list of required attributes 
  282     :param optional [str]: list of optional attributes 
  286     allowed = required + optional
 
  287     extra = [a 
for a 
in tag.attributes.keys() 
if a 
not in allowed 
and not a.startswith(
"xmlns:")]
 
  289         warning(
"%s: unknown attribute(s): %s" % (tag.nodeName, 
', '.join(extra)))
 
  307         from roslaunch.substitution_args 
import resolve_args, ArgException
 
  308         from rospkg.common 
import ResourceNotFound
 
  309         return resolve_args(s, context=substitution_args_context, resolve_anon=
False)
 
  310     except ImportError 
as e:
 
  312     except ArgException 
as e:
 
  314     except ResourceNotFound 
as e:
 
  327         except AttributeError:
 
  335         if isinstance(value, _basestr):
 
  337             if len(value) >= 2 
and value[0] == 
"'" and value[-1] == 
"'":
 
  345             for f 
in [int, float, 
lambda x: get_boolean_value(x, 
None)]:  
 
  357                                      'Consider disabling lazy evaluation via lazy_eval="false"' 
  358                                      .format(
" -> ".join(self.
recursive + [key])))
 
  360             dict.__setitem__(self, key, self.
_eval_literal(eval_text(dict.__getitem__(self, key), self)))
 
  365         value = dict.__getitem__(self, key)
 
  366         if (verbosity > 2 
and self.
parent is self.
root) 
or verbosity > 3:
 
  367             print(
"{indent}use {key}: {value} ({loc})".format(
 
  368                 indent=self.
depth * 
' ', key=key, value=value, loc=filestack[-1]), file=sys.stderr)
 
  372         if dict.__contains__(self, key):
 
  379             warning(
"redefining global symbol: %s" % key)
 
  383         dict.__setitem__(self, key, value)
 
  384         if unevaluated 
and isinstance(value, _basestr):
 
  390         if (verbosity > 2 
and self.
parent is self.
root) 
or verbosity > 3:
 
  391             print(
"{indent}set {key}: {value} ({loc})".format(
 
  392                 indent=self.
depth * 
' ', key=key, value=value, loc=filestack[-1]), file=sys.stderr)
 
  395         self.
_setitem(key, value, unevaluated=
True)
 
  400         while p 
is not self.
root:
 
  401             dict.pop(p, key, 
None)
 
  404             warning(
'Cannot remove global symbol: ' + key)
 
  408             dict.__contains__(self, key) 
or (key 
in self.
parent)
 
  411         s = dict.__str__(self)
 
  412         if self.
parent is not None:
 
  419         while p.parent 
is not p.root:
 
  426         super(NameSpace, self).
__init__(parent)
 
  433             raise NameError(
"name '{}' is not defined".format(item))
 
  441             self.__dict__.update(other.__dict__)
 
  444             for k, v 
in kwargs.items():
 
  445                 self.__setattr__(k, len(self.
res))
 
  446                 self.
res.append(re.compile(v))
 
  463         for i 
in range(len(self.
res)):
 
  464             m = self.
res[i].match(self.
str)
 
  466                 self.
top = (i, m.group(0))
 
  467                 self.
str = self.
str[m.end():]
 
  473 include_no_matches_msg = 
"""Include tag's filename spec \"{}\" matched no files.""" 
  479     except XacroException 
as e:
 
  480         if e.exc 
and isinstance(e.exc, NameError) 
and symbols 
is None:
 
  481             raise XacroException(
'variable filename is supported with in-order option only')
 
  485     if re.search(
'[*[?]+', filename_spec):
 
  487         filenames = sorted(glob.glob(filename_spec))
 
  488         if len(filenames) == 0:
 
  489             warning(include_no_matches_msg.format(filename_spec))
 
  492         filenames = [filename_spec]
 
  494     for filename 
in filenames:
 
  496         all_includes.append(filename)
 
  501     """import all namespace declarations into parent""" 
  502     for name, value 
in attributes.items():
 
  503         if name.startswith(
'xmlns:'):
 
  504             oldAttr = parent.getAttributeNode(name)
 
  505             if oldAttr 
and oldAttr.value != value:
 
  506                 warning(
"inconsistent namespace redefinitions for {name}:" 
  507                         "\n old: {old}\n new: {new} ({new_file})".format(
 
  508                             name=name, old=oldAttr.value, new=value,
 
  509                             new_file=filestack[-1]))
 
  511                 parent.setAttribute(name, value)
 
  516     filename_spec, namespace_spec, optional = 
check_attrs(elt, [
'filename'], [
'ns', 
'optional'])
 
  519             namespace_spec = eval_text(namespace_spec, symbols)
 
  520             macros[namespace_spec] = ns_macros = 
NameSpace()
 
  521             symbols[namespace_spec] = ns_symbols = 
NameSpace(parent=symbols)
 
  523             raise XacroException(
'namespaces are supported with in-order option only')
 
  528     optional = get_boolean_value(optional, 
None)
 
  531         warning(
"Child elements of a <xacro:include> tag are ignored")
 
  538             filestack.append(filename)
 
  539             include = parse(
None, filename).documentElement
 
  542             func(include, ns_macros, ns_symbols)
 
  543             included.append(include)
 
  548         except XacroException 
as e:
 
  549             if e.exc 
and isinstance(e.exc, IOError) 
and optional 
is True:
 
  554     remove_previous_comments(elt)
 
  561     Checks whether name is a valid property or macro identifier. 
  562     With python-based evaluation, we need to avoid name clashes with python keywords. 
  566         root = ast.parse(name)
 
  568         if isinstance(root, ast.Module) 
and \
 
  569            len(root.body) == 1 
and isinstance(root.body[0], ast.Expr) 
and \
 
  570            isinstance(root.body[0].value, ast.Name) 
and root.body[0].value.id == name:
 
  578 default_value = 
r'''\$\{.*?\}|\$\(.*?\)|(?:'.*?'|\".*?\"|[^\s'\"]+)+|''' 
  579 re_macro_arg = re.compile(
r'^\s*([^\s:=]+?)\s*:?=\s*(\^\|?)?(' + default_value + 
r')(?:\s+|$)(.*)')
 
  585     parse the first param spec from a macro parameter string s 
  586     accepting the following syntax: <param>[:=|=][^|]<default> 
  587     :param s: param spec string 
  588     :return: param, (forward, default), rest-of-string 
  589              forward will be either param or None (depending on whether ^ was specified) 
  590              default will be the default string or None 
  591              If there is no default spec at all, the middle pair will be replaced by None 
  593     m = re_macro_arg.match(s)
 
  596         param, forward, default, rest = m.groups()
 
  599         return param, (param 
if forward 
else None, default), rest
 
  602         result = s.lstrip().split(
None, 1)
 
  603         return result[0], 
None, result[1] 
if len(result) > 1 
else '' 
  607     assert(elt.tagName == 
'xacro:macro')
 
  608     remove_previous_comments(elt)
 
  610     name, params = 
check_attrs(elt, [
'name'], [
'params'])
 
  613     if name.find(
'.') != -1:
 
  614         raise XacroException(
"macro names must not contain '.' (reserved for namespaces): %s" % name)
 
  615     if name.startswith(
'xacro:'):
 
  616         warning(
"macro names must not contain prefix 'xacro:': %s" % name)
 
  620     macro = macros.get(name, 
Macro())
 
  622     macro.history.append(deepcopy(filestack))
 
  627     macro.defaultmap = {}
 
  630         macro.params.append(param)
 
  631         if value 
is not None:
 
  632             macro.defaultmap[param] = value  
 
  639     assert(elt.tagName == 
'xacro:property')
 
  640     remove_previous_comments(elt)
 
  642     name, value, default, remove, scope, lazy_eval = \
 
  643         check_attrs(elt, [
'name'], [
'value', 
'default', 
'remove', 
'scope', 
'lazy_eval'])
 
  644     name = eval_text(name, table)  
 
  646         raise XacroException(
'Property names must be valid python identifiers: ' + name)
 
  647     if name.startswith(
'__'):
 
  648         raise XacroException(
'Property names must not start with double underscore:' + name)
 
  649     remove = get_boolean_value(eval_text(remove 
or 'false', table), remove)
 
  650     if sum([value 
is not None, default 
is not None, remove]) > 1:
 
  651         raise XacroException(
'Property attributes default, value, and remove are mutually exclusive: ' + name)
 
  653     if remove 
and name 
in table:
 
  658     if default 
is not None:
 
  659         if scope 
is not None:
 
  660             warning(
"%s: default property value can only be defined on local scope" % name)
 
  661         if name 
not in table:
 
  674     lazy_eval = get_boolean_value(eval_text(lazy_eval 
or 'true', table), lazy_eval)
 
  676     if scope 
and scope == 
'global':
 
  677         target_table = table.top()
 
  679     elif scope 
and scope == 
'parent':
 
  680         if table.parent 
is not None:
 
  681             target_table = table.parent
 
  683             if not isinstance(table, NameSpace):  
 
  685                 while isinstance(target_table, NameSpace):
 
  686                     target_table = target_table.parent
 
  688             warning(
"%s: no parent scope at global scope " % name)
 
  693     if not lazy_eval 
and isinstance(value, _basestr):
 
  694         value = eval_text(value, table)  
 
  696     target_table._setitem(name, value, unevaluated=lazy_eval)
 
  699 LEXER = 
QuickLexer(DOLLAR_DOLLAR_BRACE=
r"^\$\$+(\{|\()",  
 
  700                    EXPR=
r"^\$\{[^\}]*\}",        
 
  701                    EXTENSION=
r"^\$\([^\)]*\)",   
 
  702                    TEXT=
r"[^$]+|\$[^{($]+|\$$")  
 
  706 def eval_text(text, symbols):
 
  709             return safe_eval(eval_text(s, symbols), symbols)
 
  710         except Exception 
as e:
 
  713                                  suffix=os.linesep + 
"when evaluating expression '%s'" % s)
 
  715     def handle_extension(s):
 
  724             results.append(handle_expr(lex.next()[1][2:-1]))
 
  725         elif id == lex.EXTENSION:
 
  726             results.append(handle_extension(lex.next()[1][2:-1]))
 
  728             results.append(lex.next()[1])
 
  729         elif id == lex.DOLLAR_DOLLAR_BRACE:
 
  730             results.append(lex.next()[1][1:])
 
  732     if len(results) == 1:
 
  736         return ''.join(map(unicode, results))
 
  739 def eval_default_arg(forward_variable, default, symbols, macro):
 
  740     if forward_variable 
is None:
 
  741         return eval_text(default, symbols)
 
  743         return symbols[forward_variable]
 
  745         if default 
is not None:
 
  746             return eval_text(default, symbols)
 
  748             raise XacroException(
"Undefined property to forward: " + forward_variable, macro=macro)
 
  751 def handle_dynamic_macro_call(node, macros, symbols):
 
  754         raise XacroException(
"xacro:call is missing the 'macro' attribute")
 
  755     name = 
unicode(eval_text(name, symbols))
 
  758     node.removeAttribute(
'macro')
 
  759     node.tagName = 
'xacro:' + name
 
  761     handle_macro_call(node, macros, symbols)
 
  765 def resolve_macro(fullname, macros, symbols):
 
  766     def _resolve(namespaces, name, macros, symbols):
 
  768         for ns 
in namespaces:
 
  770             symbols = symbols[ns]
 
  771         return macros, symbols, macros[name]
 
  775         return _resolve([], fullname, macros, symbols)
 
  778         namespaces = fullname.split(
'.')
 
  779         name = namespaces.pop(-1)
 
  781             return _resolve(namespaces, name, macros, symbols)
 
  786 def handle_macro_call(node, macros, symbols):
 
  787     if node.tagName == 
'xacro:call':
 
  788         return handle_dynamic_macro_call(node, macros, symbols)
 
  789     elif not node.tagName.startswith(
'xacro:'):
 
  792     name = node.tagName[6:]  
 
  794         macros, symbols, m = resolve_macro(name, macros, symbols)
 
  795         body = m.body.cloneNode(deep=
True)
 
  803     scoped_symbols = 
Table(symbols)  
 
  804     scoped_macros = 
Table(macros)
 
  806     for name, value 
in node.attributes.items():
 
  807         if name 
not in params:
 
  810         scoped_symbols._setitem(name, eval_text(value, symbols), unevaluated=
False)
 
  811         node.setAttribute(name, 
"")  
 
  814     eval_all(node, macros, symbols)
 
  818     for param 
in params[:]:
 
  823             scoped_symbols[param] = block
 
  826     if block 
is not None:
 
  827         raise XacroException(
"Unused block \"%s\"" % block.tagName, macro=m)
 
  830     for param 
in params[:]:
 
  836         name, default = m.defaultmap.get(param, (
None, 
None))
 
  837         if name 
is not None or default 
is not None:
 
  838             scoped_symbols._setitem(param, eval_default_arg(name, default, symbols, m), unevaluated=
False)
 
  842         raise XacroException(
"Undefined parameters [%s]" % 
",".join(params), macro=m)
 
  844     eval_all(body, scoped_macros, scoped_symbols)
 
  847     remove_previous_comments(node)
 
  857 def get_boolean_value(value, condition):
 
  859     Return a boolean value that corresponds to the given Xacro condition value. 
  860     Values "true", "1" and "1.0" are supposed to be True. 
  861     Values "false", "0" and "0.0" are supposed to be False. 
  862     All other values raise an exception. 
  864     :param value: The value to be evaluated. The value has to already be evaluated by Xacro. 
  865     :param condition: The original condition text in the XML. 
  866     :return: The corresponding boolean value, or a Python expression that, converted to boolean, corresponds to it. 
  867     :raises ValueError: If the condition value is incorrect. 
  870         if isinstance(value, _basestr):
 
  871             if value == 
'true' or value == 
'True':
 
  873             elif value == 
'false' or value == 
'False':
 
  876                 return bool(int(value))
 
  880         raise XacroException(
"Xacro conditional \"%s\" evaluated to \"%s\", " 
  881                              "which is not a boolean expression." % (condition, value))
 
  884 _empty_text_node = xml.dom.minidom.getDOMImplementation().createDocument(
None, 
"dummy", 
None).createTextNode(
'\n\n')
 
  887 def remove_previous_comments(node):
 
  888     """remove consecutive comments in front of the xacro-specific node""" 
  889     next = node.nextSibling
 
  890     previous = node.previousSibling
 
  892         if previous.nodeType == xml.dom.Node.TEXT_NODE 
and \
 
  893                 previous.data.isspace() 
and previous.data.count(
'\n') <= 1:
 
  894             previous = previous.previousSibling  
 
  896         if previous 
and previous.nodeType == xml.dom.Node.COMMENT_NODE:
 
  898             previous = previous.previousSibling
 
  899             node.parentNode.removeChild(comment)
 
  903             if next 
and _empty_text_node != next:
 
  904                 node.parentNode.insertBefore(_empty_text_node, next)
 
  908 def eval_all(node, macros, symbols):
 
  909     """Recursively evaluate node, expanding macros, replacing properties, and evaluating expressions""" 
  911     for name, value 
in node.attributes.items():
 
  912         if name.startswith(
'xacro:'):  
 
  913             node.removeAttribute(name)
 
  915             result = 
unicode(eval_text(value, symbols))
 
  916             node.setAttribute(name, result)
 
  920         node.removeAttribute(
'xmlns:xacro')
 
  921     except xml.dom.NotFoundErr:
 
  924     node = node.firstChild
 
  925     eval_comments = 
False 
  927         next = node.nextSibling
 
  928         if node.nodeType == xml.dom.Node.ELEMENT_NODE:
 
  929             eval_comments = 
False   
  930             if node.tagName == 
'xacro:insert_block':
 
  933                 if (
"**" + name) 
in symbols:
 
  935                     block = symbols[
'**' + name]
 
  937                 elif (
"*" + name) 
in symbols:
 
  939                     block = symbols[
'*' + name]
 
  945                 block = block.cloneNode(deep=
True)
 
  947                 eval_all(block, macros, symbols)
 
  950             elif node.tagName == 
'xacro:include':
 
  953             elif node.tagName == 
'xacro:property':
 
  956             elif node.tagName == 
'xacro:macro':
 
  959             elif node.tagName == 
'xacro:arg':
 
  960                 name, default = 
check_attrs(node, [
'name', 
'default'], [])
 
  961                 if name 
not in substitution_args_context[
'arg']:
 
  962                     substitution_args_context[
'arg'][name] = 
unicode(eval_text(default, symbols))
 
  964                 remove_previous_comments(node)
 
  967             elif node.tagName == 
'xacro:element':
 
  968                 name = eval_text(*
reqd_attrs(node, [
'xacro:name']), symbols=symbols)
 
  972                 node.removeAttribute(
'xacro:name')
 
  973                 node.nodeName = node.tagName = name
 
  976             elif node.tagName == 
'xacro:attribute':
 
  977                 name, value = [eval_text(a, symbols) 
for a 
in reqd_attrs(node, [
'name', 
'value'])]
 
  981                 node.parentNode.setAttribute(name, value)
 
  984             elif node.tagName 
in [
'xacro:if', 
'xacro:unless']:
 
  985                 remove_previous_comments(node)
 
  987                 keep = get_boolean_value(eval_text(cond, symbols), cond)
 
  988                 if node.tagName 
in [
'unless', 
'xacro:unless']:
 
  992                     eval_all(node, macros, symbols)
 
  997             elif handle_macro_call(node, macros, symbols):
 
 1001                 eval_all(node, macros, symbols)
 
 1003         elif node.nodeType == xml.dom.Node.TEXT_NODE:
 
 1004             node.data = 
unicode(eval_text(node.data, symbols))
 
 1005             if node.data.strip():
 
 1006                 eval_comments = 
False  
 1008         elif node.nodeType == xml.dom.Node.COMMENT_NODE:
 
 1009             if "xacro:eval-comments" in node.data:
 
 1010                 eval_comments = 
"xacro:eval-comments:off" not in node.data
 
 1013                 node.data = 
unicode(eval_text(node.data, symbols))
 
 1020 def parse(inp, filename=None):
 
 1022     Parse input or filename into a DOM tree. 
 1023     If inp is None, open filename and load from there. 
 1024     Otherwise, parse inp, either as string or file object. 
 1025     If inp is already a DOM tree, this function is a noop. 
 1026     :return:xml.dom.minidom.Document 
 1027     :raise: xml.parsers.expat.ExpatError 
 1032             inp = f = open(filename)
 
 1033         except IOError 
as e:
 
 1039         if isinstance(inp, _basestr):
 
 1040             return xml.dom.minidom.parseString(inp)
 
 1041         elif hasattr(inp, 
'read'):
 
 1042             return xml.dom.minidom.parse(inp)
 
 1050 def process_doc(doc, mappings=None, **kwargs):
 
 1052     verbosity = kwargs.get(
'verbosity', verbosity)
 
 1055     substitution_args_context[
'arg'] = {} 
if mappings 
is None else mappings
 
 1062     symbols = 
Table(_global_symbols)
 
 1065     targetNS = doc.documentElement.getAttribute(
'xacro:targetNamespace')
 
 1067         doc.documentElement.removeAttribute(
'xacro:targetNamespace')
 
 1068         doc.documentElement.setAttribute(
'xmlns', targetNS)
 
 1070     eval_all(doc.documentElement, macros, symbols)
 
 1073     substitution_args_context[
'arg'] = {}
 
 1076 def open_output(output_filename):
 
 1077     if output_filename 
is None:
 
 1080         dir_name = os.path.dirname(output_filename)
 
 1083                 os.makedirs(dir_name)
 
 1090             return open(output_filename, 
'w')
 
 1091         except IOError 
as e:
 
 1095 def print_location():
 
 1096     msg = 
'when instantiating macro:' 
 1097     for m 
in reversed(macrostack 
or []):
 
 1098         name = m.body.getAttribute(
'name')
 
 1099         location = 
'({file})'.format(file = m.history[-1][-1] 
or '???')
 
 1100         print(msg, name, location, file=sys.stderr)
 
 1101         msg = 
'instantiated from:' 
 1103     msg = 
'in file:' if macrostack 
else 'when processing file:' 
 1104     for f 
in reversed(filestack 
or []):
 
 1107         print(msg, f, file=sys.stderr)
 
 1108         msg = 
'included from:' 
 1111 def process_file(input_file_name, **kwargs):
 
 1112     """main processing pipeline""" 
 1116     doc = parse(
None, input_file_name)
 
 1118     process_doc(doc, **kwargs)
 
 1121     banner = [xml.dom.minidom.Comment(c) 
for c 
in 
 1122               [
" %s " % (
'=' * 83),
 
 1123                " |    This document was autogenerated by xacro from %-30s | " % input_file_name,
 
 1124                " |    EDITING THIS FILE BY HAND IS NOT RECOMMENDED  %-30s | " % 
"",
 
 1125                " %s " % (
'=' * 83)]]
 
 1126     first = doc.firstChild
 
 1127     for comment 
in banner:
 
 1128         doc.insertBefore(comment, first)
 
 1140         doc = process_file(input_file_name, **vars(opts))
 
 1142         out = open_output(opts.output)
 
 1145     except xml.parsers.expat.ExpatError 
as e:
 
 1146         error(
"XML parsing error: %s" % 
unicode(e), alt_text=
None)
 
 1149             print(file=sys.stderr)  
 
 1150             print(
"Check that:", file=sys.stderr)
 
 1151             print(
" - Your XML is well-formed", file=sys.stderr)
 
 1152             print(
" - You have the xacro xmlns declaration:",
 
 1153                   "xmlns:xacro=\"http://www.ros.org/wiki/xacro\"", file=sys.stderr)
 
 1156     except Exception 
as e:
 
 1164             print(file=sys.stderr)  
 
 1171         out.write(
" ".join(set(all_includes)))
 
 1176     out.write(doc.toprettyxml(indent=
'  ', **encoding))