# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re
from robot.errors import DataError
from robot.utils import get_error_message, py2to3
from robot.variables import VariableIterator
[docs]@py2to3
class EmbeddedArguments(object):
def __init__(self, name):
if '${' in name:
self.name, self.args = EmbeddedArgumentParser().parse(name)
else:
self.name, self.args = None, []
def __nonzero__(self):
return self.name is not None
[docs]class EmbeddedArgumentParser(object):
_regexp_extension = re.compile(r'(?<!\\)\(\?.+\)')
_regexp_group_start = re.compile(r'(?<!\\)\((.*?)\)')
_escaped_curly = re.compile(r'(\\+)([{}])')
_regexp_group_escape = r'(?:\1)'
_default_pattern = '.*?'
_variable_pattern = r'\$\{[^\}]+\}'
[docs] def parse(self, string):
args = []
name_regexp = ['^']
for before, variable, string in VariableIterator(string, identifiers='$'):
name, pattern = self._get_name_and_pattern(variable[2:-1])
args.append(name)
name_regexp.extend([re.escape(before), '(%s)' % pattern])
name_regexp.extend([re.escape(string), '$'])
name = self._compile_regexp(name_regexp) if args else None
return name, args
def _get_name_and_pattern(self, name):
if ':' not in name:
return name, self._default_pattern
name, pattern = name.split(':', 1)
return name, self._format_custom_regexp(pattern)
def _format_custom_regexp(self, pattern):
for formatter in (self._regexp_extensions_are_not_allowed,
self._make_groups_non_capturing,
self._unescape_curly_braces,
self._add_automatic_variable_pattern):
pattern = formatter(pattern)
return pattern
def _regexp_extensions_are_not_allowed(self, pattern):
if not self._regexp_extension.search(pattern):
return pattern
raise DataError('Regexp extensions are not allowed in embedded '
'arguments.')
def _make_groups_non_capturing(self, pattern):
return self._regexp_group_start.sub(self._regexp_group_escape, pattern)
def _unescape_curly_braces(self, pattern):
def unescaper(match):
backslashes = len(match.group(1))
return '\\' * (backslashes // 2 * 2) + match.group(2)
return self._escaped_curly.sub(unescaper, pattern)
def _add_automatic_variable_pattern(self, pattern):
return '%s|%s' % (pattern, self._variable_pattern)
def _compile_regexp(self, pattern):
try:
return re.compile(''.join(pattern), re.IGNORECASE)
except:
raise DataError("Compiling embedded arguments regexp failed: %s"
% get_error_message())