Source code for robot.variables.splitter

#  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.

from robot.utils import is_string, py2to3


[docs]class VariableSplitter(object): def __init__(self, string, identifiers='$@%&*'): self.identifier = None self.base = None self.items = [] self.start = -1 self.end = -1 self._identifiers = identifiers self._may_have_internal_variables = False if not is_string(string): self._max_end = -1 return self._max_end = len(string) if self._split(string): self._finalize()
[docs] def get_replaced_variable(self, replacer): if self._may_have_internal_variables: base = replacer.replace_string(self.base) else: base = self.base # This omits possible variable items. return '%s{%s}' % (self.identifier, base)
[docs] def is_variable(self): return bool(self.identifier and self.base and self.start == 0 and self.end == self._max_end)
[docs] def is_list_variable(self): return bool(self.identifier == '@' and self.base and self.start == 0 and self.end == self._max_end and not self.items)
[docs] def is_dict_variable(self): return bool(self.identifier == '&' and self.base and self.start == 0 and self.end == self._max_end and not self.items)
def _finalize(self): self.identifier = self._variable_chars[0] self.base = ''.join(self._variable_chars[2:-1]) self.end = self.start + len(self._variable_chars) if self.items: self.end += len(''.join(self.items)) + 2 * len(self.items) def _split(self, string): start_index, max_index = self._find_variable(string) if start_index == -1: return False self.start = start_index self._open_curly = 1 self._state = self._variable_state self._variable_chars = [string[start_index], '{'] self._item_chars = [] self._string = string start_index += 2 for index, char in enumerate(string[start_index:], start=start_index): try: self._state(char, index) except StopIteration: break if index == max_index and not self._scanning_item(): break return True def _scanning_item(self): return self._state in (self._waiting_item_state, self._item_state) def _find_variable(self, string): max_end_index = string.rfind('}') if max_end_index == -1: return -1, -1 if self._is_escaped(string, max_end_index): return self._find_variable(string[:max_end_index]) start_index = self._find_start_index(string, 1, max_end_index) if start_index == -1: return -1, -1 return start_index, max_end_index def _find_start_index(self, string, start, end): while True: index = string.find('{', start, end) - 1 if index < 0: return -1 if self._start_index_is_ok(string, index): return index start = index + 2 def _start_index_is_ok(self, string, index): return (string[index] in self._identifiers and not self._is_escaped(string, index)) def _is_escaped(self, string, index): escaped = False while index > 0 and string[index-1] == '\\': index -= 1 escaped = not escaped return escaped def _variable_state(self, char, index): self._variable_chars.append(char) if char == '}' and not self._is_escaped(self._string, index): self._open_curly -= 1 if self._open_curly == 0: if not self._can_have_item(): raise StopIteration self._state = self._waiting_item_state elif char in self._identifiers: self._state = self._internal_variable_start_state def _can_have_item(self): return self._variable_chars[0] in '$@&' def _internal_variable_start_state(self, char, index): self._state = self._variable_state if char == '{': self._variable_chars.append(char) self._open_curly += 1 self._may_have_internal_variables = True else: self._variable_state(char, index) def _waiting_item_state(self, char, index): if char != '[': raise StopIteration self._state = self._item_state def _item_state(self, char, index): if char != ']': self._item_chars.append(char) return self.items.append(''.join(self._item_chars)) self._item_chars = [] # Don't support nested item access with olf @ and & syntax. # In RF 3.2 old syntax is to be deprecated and in RF 3.3 it # will be reassigned to mean using variable in list/dict context. if self._variable_chars[0] in '@&': raise StopIteration self._state = self._waiting_item_state
[docs]@py2to3 class VariableIterator(object): def __init__(self, string, identifiers='$@%&*'): self._string = string self._identifiers = identifiers def __iter__(self): string = self._string while True: var = VariableSplitter(string, self._identifiers) if var.identifier is None: break before = string[:var.start] variable = '%s{%s}' % (var.identifier, var.base) string = string[var.end:] yield before, variable, string def __len__(self): return sum(1 for _ in self) def __nonzero__(self): try: next(iter(self)) except StopIteration: return False else: return True