33 from __future__ 
import print_function, division
    42 from roslaunch 
import substitution_args
    43 from rospkg.common 
import ResourceNotFound
    44 from copy 
import deepcopy
    45 from .color 
import warning, error, message
    46 from .xmlutils 
import *
    47 from .cli 
import process_args
    56 substitution_args_context = {}
    64     Push a new filename to the filestack.    65     Instead of directly modifying filestack, a deep-copy is created and modified,    66     while the old filestack is returned.    67     This allows to store the filestack that was active when a macro or property is defined    71     filestack = deepcopy(filestack)
    72     filestack.append(filename)
    82     Prepend the dirname of the currently processed file    83     if filename_spec is not yet absolute    85     if not os.path.isabs(filename_spec):
    86         parent_filename = filestack[-1]
    87         basedir = os.path.dirname(parent_filename) 
if parent_filename 
else '.'    88         return os.path.join(basedir, filename_spec)
    96         raise XacroException(
"yaml support not available; install python-yaml")
   107         all_includes.append(filename)
   114 global_symbols = {
'__builtins__': {k: __builtins__[k] 
for k 
in [
'list', 
'dict', 
'map', 
'str', 
'float', 
'int', 
'True', 
'False', 
'min', 
'max', 
'round']}}
   116 global_symbols.update(math.__dict__)
   118 global_symbols.update(dict(load_yaml=load_yaml))
   123     XacroException allows to wrap another exception (exc) and to augment   124     its error message: prefixing with msg and suffixing with suffix.   125     str(e) finally prints: msg str(exc) suffix   127     def __init__(self, msg=None, suffix=None, exc=None, macro=None):
   128         super(XacroException, self).
__init__(msg)
   131         self.
macros = [] 
if macro 
is None else [macro]
   135         return ' '.join([str(e) 
for e 
in items 
if e 
not in [
'', 
'None']])
   146         warning(
"deprecated: xacro tags should be prepended with 'xacro' xml namespace.")
   147         message(
"""Use the following script to fix incorrect usage:   148         find . -iname "*.xacro" | xargs sed -i 's#<\([/]\\?\)\(if\|unless\|include\|arg\|property\|macro\|insert_block\)#<\\1xacro:\\2#g'""")
   150         print(file=sys.stderr)
   154 allow_non_prefixed_tags = 
True   159     Check whether tagName starts with xacro prefix. If not, issue a warning.   161     :return: True if tagName is accepted as xacro tag   162              False if tagName doesn't start with xacro prefix, but the prefix is required   164     if tag_name.startswith(
'xacro:'):
   167         if allow_non_prefixed_tags:
   169         return allow_non_prefixed_tags
   184         return substitution_args.resolve_args(s, context=substitution_args_context, resolve_anon=
False)
   185     except substitution_args.ArgException 
as e:
   187     except ResourceNotFound 
as e:
   207         if isinstance(value, _basestr):
   211                 evaluated = ast.literal_eval(value.strip())
   214                 if not isinstance(evaluated, (list, dict, tuple)):
   227             self.recursive.append(key)
   229             self.unevaluated.remove(key)
   230             self.recursive.remove(key)
   233         value = self.
table[key]
   234         if (verbosity > 2 
and self.
parent is None) 
or verbosity > 3:
   235             print(
"{indent}use {key}: {value} ({loc})".format(
   236                 indent=self.
depth*
' ', key=key, value=value, loc=filestack[-1]), file=sys.stderr)
   242         if key 
in self.
table:
   250         if do_check_order 
and key 
in self.
used and key 
not in self.
redefined:
   253         if key 
in global_symbols:
   254             warning(
"redefining global property: %s" % key)
   258         self.
table[key] = value
   259         if unevaluated 
and isinstance(value, _basestr):
   261             self.unevaluated.add(key)
   264             self.unevaluated.remove(key)
   265         if (verbosity > 2 
and self.
parent is None) 
or verbosity > 3:
   266             print(
"{indent}set {key}: {value} ({loc})".format(
   267                 indent=self.
depth*
' ', key=key, value=value, loc=filestack[-1]), file=sys.stderr)
   270         self.
_setitem(key, value, unevaluated=
True)
   274             key 
in self.
table or \
   279         if isinstance(self.
parent, Table):
   293         return self.__getitem__(item)
   297         super(PropertyNameSpace, self).
__init__(parent)
   301         super(MacroNameSpace, self).
__init__(*args, **kwargs)
   309             self.__dict__.update(other.__dict__)
   312             for k, v 
in kwargs.items():
   313                 self.__setattr__(k, len(self.
res))
   314                 self.res.append(re.compile(v))
   329         for i 
in range(len(self.
res)):
   330             m = self.
res[i].match(self.
str)
   332                 self.
top = (i, m.group(0))
   333                 self.
str = self.
str[m.end():]
   340 include_no_matches_msg = 
"""Include tag's filename spec \"{}\" matched no files."""   346     if elt.tagName 
not in [
'xacro:include', 
'include']:
   350     if elt.tagName == 
'include':
   355         if elt.childNodes 
and not (len(elt.childNodes) == 1 
and   356                                    elt.childNodes[0].nodeType == elt.TEXT_NODE):
   368     except XacroException 
as e:
   369         if e.exc 
and isinstance(e.exc, NameError) 
and symbols 
is None:
   370             raise XacroException(
'variable filename is supported with --inorder option only')
   374     if re.search(
'[*[?]+', filename_spec):
   376         filenames = sorted(glob.glob(filename_spec))
   377         if len(filenames) == 0:
   378             warning(include_no_matches_msg.format(filename_spec))
   381         filenames = [filename_spec]
   383     for filename 
in filenames:
   385         all_includes.append(filename)
   390     """import all namespace declarations into parent"""   391     for name, value 
in attributes.items():
   392         if name.startswith(
'xmlns:'):
   393             oldAttr = parent.getAttributeNode(name)
   394             if oldAttr 
and oldAttr.value != value:
   395                 warning(
"inconsistent namespace redefinitions for {name}:"   396                         "\n old: {old}\n new: {new} ({new_file})".format(
   397                     name=name, old=oldAttr.value, new=value,
   398                     new_file=filestack[-1]))
   400                 parent.setAttribute(name, value)
   405     filename_spec, namespace_spec = 
check_attrs(elt, [
'filename'], [
'ns'])
   408             namespace_spec = 
eval_text(namespace_spec, symbols)
   414             raise XacroException(
'namespaces are supported with --inorder option only')
   419         include = 
parse(
None, filename).documentElement
   422         func(include, macros, symbols)
   423         included.append(include)
   449     Checks whether name is a valid property or macro identifier.   450     With python-based evaluation, we need to avoid name clashes with python keywords.   454         root = ast.parse(name)
   456         if isinstance(root, ast.Module) 
and \
   457            len(root.body) == 1 
and isinstance(root.body[0], ast.Expr) 
and \
   458            isinstance(root.body[0].value, ast.Name) 
and root.body[0].value.id == name:
   466 re_macro_arg = re.compile(
r'''\s*([^\s:=]+?):?=(\^\|?)?((?:(?:'[^']*')?[^\s'"]*?)*)(?:\s+|$)(.*)''')
   470     parse the first param spec from a macro parameter string s   471     accepting the following syntax: <param>[:=|=][^|]<default>   472     :param s: param spec string   473     :return: param, (forward, default), rest-of-string   474              forward will be either param or None (depending on whether ^ was specified)   475              default will be the default string or None   476              If there is no default spec at all, the middle pair will be replaced by None   478     m = re_macro_arg.match(s)
   481         param, forward, default, rest = m.groups()
   482         if not default: default = 
None   483         return param, (param 
if forward 
else None, default), rest
   486         result = s.lstrip().split(
None, 1)
   487         return result[0], 
None, result[1] 
if len(result) > 1 
else ''   491     assert(elt.tagName 
in [
'macro', 
'xacro:macro'])
   494     name, params = 
check_attrs(elt, [
'name'], [
'params'])
   496         warning(
"deprecated use of macro name 'call'; xacro:call became a new keyword")
   497     if name.find(
'.') != -1:
   498         warning(
"macro names must not contain '.': %s" % name)
   500     if not name.startswith(
'xacro:'):
   501         name = 
'xacro:' + name
   504     macro = macros.get(name, 
Macro())
   506     macro.history.append(filestack)
   511     macro.defaultmap = {}
   514         macro.params.append(param)
   515         if value 
is not None:
   516             macro.defaultmap[param] = value  
   527         if elt.tagName 
in [
'macro', 
'xacro:macro'] \
   537     assert(elt.tagName 
in [
'property', 
'xacro:property'])
   540     name, value, default, scope = 
check_attrs(elt, [
'name'], [
'value', 
'default', 
'scope'])
   542         raise XacroException(
'Property names must be valid python identifiers: ' + name)
   543     if value 
is not None and default 
is not None:
   544         raise XacroException(
'Property cannot define both a default and a value: ' + name)
   546     if default 
is not None:
   547         if scope 
is not None:
   548             warning(
"%s: default property value can only be defined on local scope" % name)
   549         if name 
not in table:
   561     if scope 
and scope == 
'global':
   562         target_table = table.root()
   564     elif scope 
and scope == 
'parent':
   566             target_table = table.parent
   569             warning(
"%s: no parent scope at global scope " % name)
   575     if not unevaluated 
and isinstance(value, _basestr):
   578     target_table._setitem(name, value, unevaluated=unevaluated)
   586         if elt.tagName 
in [
'property', 
'xacro:property'] \
   588             if "default" in elt.attributes.keys():
   589                 raise XacroException(
'default property value supported with --inorder option only')
   598                    EXPR=
r"\$\{[^\}]*\}",
   599                    EXTENSION=
r"\$\([^\)]*\)",
   600                    TEXT=
r"([^\$]|\$[^{(]|\$$)+")
   607             return eval(
eval_text(s, symbols), global_symbols, symbols)
   608         except Exception 
as e:
   611                 suffix=os.linesep + 
"when evaluating expression '%s'" % s)
   613     def handle_extension(s):
   620         if lex.peek()[0] == lex.EXPR:
   621             results.append(handle_expr(lex.next()[1][2:-1]))
   622         elif lex.peek()[0] == lex.EXTENSION:
   623             results.append(handle_extension(lex.next()[1][2:-1]))
   624         elif lex.peek()[0] == lex.TEXT:
   625             results.append(lex.next()[1])
   626         elif lex.peek()[0] == lex.DOLLAR_DOLLAR_BRACE:
   627             results.append(lex.next()[1][1:])
   629     if len(results) == 1:
   633         return ''.join(map(str, results))
   637     if forward_variable 
is None:
   640         return symbols[forward_variable]
   642         if default 
is not None:
   645             raise XacroException(
"Undefined property to forward: " + forward_variable, macro=macro)
   651         raise XacroException(
"xacro:call is missing the 'macro' attribute")
   655     node.removeAttribute(
'macro')
   660         raise XacroException(
"unknown macro name '%s' in xacro:call" % name)
   665     namespaces = fullname.split(
'.')
   666     name = namespaces.pop(-1)
   668     if namespaces 
and namespaces[0].startswith(
'xacro:'):
   669         namespaces[0] = namespaces[0].replace(
'xacro:', 
'')
   670         name = 
'xacro:' + name
   672     def _resolve(namespaces, name, macros):
   674         for ns 
in namespaces:
   680             if allow_non_prefixed_tags 
and not name.startswith(
'xacro:'):
   681                 return _resolve([], 
'xacro:' + name, macros)
   684     m = _resolve([], fullname, macros)
   686     elif namespaces: 
return _resolve(namespaces, name, macros)\
   692         body = m.body.cloneNode(deep=
True)
   694     except (KeyError, TypeError, AttributeError):
   696         if node.tagName == 
'xacro:call':
   701     scoped = 
Table(symbols)  
   703     for name, value 
in node.attributes.items():
   704         if name 
not in params:
   705             raise XacroException(
"Invalid parameter \"%s\"" % str(name), macro=m)
   707         scoped._setitem(name, 
eval_text(value, symbols), unevaluated=
False)
   708         node.setAttribute(name, 
"")  
   715     for param 
in params[:]:
   720             scoped[param] = block
   723     if block 
is not None:
   724         raise XacroException(
"Unused block \"%s\"" % block.tagName, macro=m)
   727     for param 
in params[:]:
   729         if param[0] == 
'*': 
continue   732         name, default = m.defaultmap.get(param, (
None,
None))
   733         if name 
is not None or default 
is not None:
   734             scoped._setitem(param, 
eval_default_arg(name, default, symbols, m), unevaluated=
False)
   738         raise XacroException(
"Undefined parameters [%s]" % 
",".join(params), macro=m)
   742     except Exception 
as e:
   744         if hasattr(e, 
'macros'):
   758     Return a boolean value that corresponds to the given Xacro condition value.   759     Values "true", "1" and "1.0" are supposed to be True.   760     Values "false", "0" and "0.0" are supposed to be False.   761     All other values raise an exception.   763     :param value: The value to be evaluated. The value has to already be evaluated by Xacro.   764     :param condition: The original condition text in the XML.   765     :return: The corresponding boolean value, or a Python expression that, converted to boolean, corresponds to it.   766     :raises ValueError: If the condition value is incorrect.   769         if isinstance(value, _basestr):
   770             if value == 
'true': 
return True   771             elif value == 
'false': 
return False   772             else: 
return ast.literal_eval(value)
   776         raise XacroException(
"Xacro conditional \"%s\" evaluated to \"%s\", "   777                              "which is not a boolean expression." % (condition, value))
   780 _empty_text_node = xml.dom.minidom.getDOMImplementation().createDocument(
None, 
"dummy", 
None).createTextNode(
'\n\n')
   782     """remove consecutive comments in front of the xacro-specific node"""   783     next = node.nextSibling
   784     previous = node.previousSibling
   786         if previous.nodeType == xml.dom.Node.TEXT_NODE 
and \
   787                 previous.data.isspace() 
and previous.data.count(
'\n') <= 1:
   788             previous = previous.previousSibling  
   790         if previous 
and previous.nodeType == xml.dom.Node.COMMENT_NODE:
   792             previous = previous.previousSibling
   793             node.parentNode.removeChild(comment)
   797             if next 
and _empty_text_node != next: node.parentNode.insertBefore(_empty_text_node, next)
   802     """Recursively evaluate node, expanding macros, replacing properties, and evaluating expressions"""   804     for name, value 
in node.attributes.items():
   806         node.setAttribute(name, result)
   808     node = node.firstChild
   810         next = node.nextSibling
   811         if node.nodeType == xml.dom.Node.ELEMENT_NODE:
   812             if node.tagName 
in [
'insert_block', 
'xacro:insert_block'] \
   816                 if (
"**" + name) 
in symbols:
   818                     block = symbols[
'**' + name]
   820                 elif (
"*" + name) 
in symbols:
   822                     block = symbols[
'*' + name]
   828                 block = block.cloneNode(deep=
True)
   836             elif node.tagName 
in [
'property', 
'xacro:property'] \
   840             elif node.tagName 
in [
'macro', 
'xacro:macro'] \
   844             elif node.tagName 
in [
'arg', 
'xacro:arg'] \
   846                 name, default = 
check_attrs(node, [
'name', 
'default'], [])
   847                 if name 
not in substitution_args_context[
'arg']:
   848                     substitution_args_context[
'arg'][name] = 
eval_text(default, symbols)
   853             elif node.tagName == 
'xacro:element':
   858                 node.removeAttribute(
'xacro:name')
   859                 node.nodeName = node.tagName = name
   862             elif node.tagName == 
'xacro:attribute':
   867                 node.parentNode.setAttribute(name, value)
   870             elif node.tagName 
in [
'if', 
'xacro:if', 
'unless', 
'xacro:unless'] \
   875                 if node.tagName 
in [
'unless', 
'xacro:unless']:
   889                 if node.tagName.startswith(
"xacro:"):
   895         elif node.nodeType == xml.dom.Node.TEXT_NODE:
   896             node.data = str(
eval_text(node.data, symbols))
   903     Parse input or filename into a DOM tree.   904     If inp is None, open filename and load from there.   905     Otherwise, parse inp, either as string or file object.   906     If inp is already a DOM tree, this function is a noop.   907     :return:xml.dom.minidom.Document   908     :raise: xml.parsers.expat.ExpatError   913             inp = f = open(filename)
   920         if isinstance(inp, _basestr):
   921             return xml.dom.minidom.parseString(inp)
   922         elif hasattr(inp, 
'read'):
   923             return xml.dom.minidom.parse(inp)
   932                 in_order=
False, just_deps=
False, just_includes=
False,
   933                 mappings=
None, xacro_ns=
True, **kwargs):
   934     global verbosity, do_check_order
   935     verbosity = kwargs.get(
'verbosity', verbosity)
   936     do_check_order = kwargs.get(
'do_check_order', do_check_order)
   939     if mappings 
is not None:
   940         substitution_args_context[
'arg'] = mappings
   942     global allow_non_prefixed_tags
   943     allow_non_prefixed_tags = xacro_ns
   950     if (just_deps 
or just_includes) 
and not in_order:
   962     eval_all(doc.documentElement, macros, symbols)
   965     substitution_args_context[
'arg'] = {}
   967     if do_check_order 
and symbols.redefined:
   968         warning(
"Document is incompatible to --inorder processing.")
   969         warning(
"The following properties were redefined after usage:")
   970         for k, v 
in symbols.redefined.iteritems():
   971             message(k, 
"redefined in", v, color=
'yellow')
   975     if output_filename 
is None:
   978         dir_name = os.path.dirname(output_filename)
   981                 os.makedirs(dir_name)
   988             return open(output_filename, 
'w')
   994     macros = getattr(err, 
'macros', []) 
if err 
else []
   995     msg = 
'when instantiating macro:'   997         name = m.body.getAttribute(
'name')
   998         location = 
'(%s)' % m.history[-1][-1]
   999         print(msg, name, location, file=file)
  1000         msg = 
'instantiated from:'  1002     msg = 
'in file:' if macros 
else 'when processing file:'  1003     for f 
in reversed(filestack):
  1004         if f 
is None: f = 
'string'  1005         print(msg, f, file=file)
  1006         msg = 
'included from:'  1009     """main processing pipeline"""  1013     doc = 
parse(
None, input_file_name)
  1018     banner = [xml.dom.minidom.Comment(c) 
for c 
in  1019               [
" %s " % (
'=' * 83),
  1020                " |    This document was autogenerated by xacro from %-30s | " % input_file_name,
  1021                " |    EDITING THIS FILE BY HAND IS NOT RECOMMENDED  %-30s | " % 
"",
  1022                " %s " % (
'=' * 83)]]
  1023     first = doc.firstChild
  1024     for comment 
in banner:
  1025         doc.insertBefore(comment, first)
  1031     if opts.in_order == 
False and not opts.just_includes:
  1032         warning(
"xacro: Traditional processing is deprecated. Switch to --inorder processing!")
  1033         message(
"To check for compatibility of your document, use option --check-order.", color=
'yellow')
  1034         message(
"For more infos, see http://wiki.ros.org/xacro#Processing_Order", color=
'yellow')
  1043     except xml.parsers.expat.ExpatError 
as e:
  1044         error(
"XML parsing error: %s" % str(e), alt_text=
None)
  1047             print(file=sys.stderr) 
  1048             print(
"Check that:", file=sys.stderr)
  1049             print(
" - Your XML is well-formed", file=sys.stderr)
  1050             print(
" - You have the xacro xmlns declaration:",
  1051                   "xmlns:xacro=\"http://www.ros.org/wiki/xacro\"", file=sys.stderr)
  1054     except Exception 
as e:
  1056         if not msg: msg = repr(e)
  1061             print(file=sys.stderr)  
  1068         out.write(
" ".join(set(all_includes)))
  1073     out.write(doc.toprettyxml(indent=
'  '))
 
def __init__(self, args, kwargs)
 
def _setitem(self, key, value, unevaluated)
 
def check_deprecated_tag(tag_name)
 
def process_file(input_file_name, kwargs)
 
def remove_previous_comments(node)
 
def parse(inp, filename=None)
 
def process_includes(elt, macros=None, symbols=None)
 
def grab_properties(elt, table)
 
def __init__(self, msg=None, suffix=None, exc=None, macro=None)
 
def eval_text(text, symbols)
 
def __setitem__(self, key, value)
 
def handle_dynamic_macro_call(node, macros, symbols)
 
def next_sibling_element(node)
 
def process_doc(doc, in_order=False, just_deps=False, just_includes=False, mappings=None, xacro_ns=True, kwargs)
 
def handle_macro_call(node, macros, symbols)
 
def get_boolean_value(value, condition)
 
def abs_filename_spec(filename_spec)
 
def open_output(output_filename)
 
def resolve_macro(fullname, macros)
 
def process_include(elt, macros, symbols, func)
 
def restore_filestack(oldstack)
 
def grab_property(elt, table)
 
def __init__(self, args, kwargs)
 
def first_child_element(elt)
 
def import_xml_namespaces(parent, attributes)
 
def grab_macro(elt, macros)
 
def reqd_attrs(tag, attrs)
 
def print_location(filestack, err=None, file=sys.stderr)
 
def message(msg, args, kwargs)
 
def __getattr__(self, item)
 
def eval_default_arg(forward_variable, default, symbols, macro)
 
def replace_node(node, by, content_only=False)
 
def __contains__(self, key)
 
def warning(args, kwargs)
 
def process_args(argv, require_input=True)
 
def __init__(self, parent=None)
 
def grab_macros(elt, macros)
 
def eval_all(node, macros, symbols)
 
def check_attrs(tag, required, optional)
 
def __getitem__(self, key)
 
def __init__(self, parent=None)
 
def deprecated_tag(_issued=[False])
 
def get_include_files(filename_spec, symbols)