Robot Framework Integrated Development Environment (RIDE)
replacer.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 from robotide.lib.robot.errors import DataError, VariableError
17 from robotide.lib.robot.output import LOGGER
18 from robotide.lib.robot.utils import (escape, is_dict_like, is_list_like, is_string,
19  type_name, unescape, unic)
20 
21 from .splitter import VariableSplitter
22 
23 
25 
26  def __init__(self, variables):
27  self._variables_variables = variables
28 
29 
40  def replace_list(self, items, replace_until=None, ignore_errors=False):
41  items = list(items or [])
42  if replace_until is not None:
43  return self._replace_list_until_replace_list_until(items, replace_until, ignore_errors)
44  return list(self._replace_list_replace_list(items, ignore_errors))
45 
46  def _replace_list_until(self, items, replace_until, ignore_errors):
47  # @{list} variables can contain more or less arguments than needed.
48  # Therefore we need to go through items one by one, and escape possible
49  # extra items we got.
50  replaced = []
51  while len(replaced) < replace_until and items:
52  replaced.extend(self._replace_list_replace_list([items.pop(0)], ignore_errors))
53  if len(replaced) > replace_until:
54  replaced[replace_until:] = [escape(item)
55  for item in replaced[replace_until:]]
56  return replaced + items
57 
58  def _replace_list(self, items, ignore_errors):
59  for item in items:
60  if self._cannot_have_variables_cannot_have_variables(item):
61  yield unescape(item)
62  else:
63  for value in self._replace_list_item_replace_list_item(item, ignore_errors):
64  yield value
65 
66  def _replace_list_item(self, item, ignore_errors):
67  splitter = VariableSplitter(item)
68  try:
69  value = self._replace_scalar_replace_scalar(item, splitter)
70  except DataError:
71  if ignore_errors:
72  return [item]
73  raise
74  if splitter.is_list_variable():
75  return value
76  return [value]
77 
78 
84  def replace_scalar(self, item, ignore_errors=False):
85  if self._cannot_have_variables_cannot_have_variables(item):
86  return unescape(item)
87  return self._replace_scalar_replace_scalar(item, ignore_errors=ignore_errors)
88 
89  def _replace_scalar(self, item, splitter=None, ignore_errors=False):
90  if not splitter:
91  splitter = VariableSplitter(item)
92  if not splitter.identifier:
93  return unescape(item)
94  if not splitter.is_variable():
95  return self._replace_string_replace_string(item, splitter, ignore_errors)
96  try:
97  return self._get_variable_get_variable(splitter)
98  except DataError:
99  if ignore_errors:
100  return item
101  raise
102 
103  def _cannot_have_variables(self, item):
104  return not (is_string(item) and '{' in item)
105 
106 
107  def replace_string(self, string, ignore_errors=False):
108  if not is_string(string):
109  return unic(string)
110  if self._cannot_have_variables_cannot_have_variables(string):
111  return unescape(string)
112  return self._replace_string_replace_string(string, ignore_errors=ignore_errors)
113 
114  def _replace_string(self, string, splitter=None, ignore_errors=False):
115  if not splitter:
116  splitter = VariableSplitter(string)
117  return ''.join(self._yield_replaced_yield_replaced(string, splitter, ignore_errors))
118 
119  def _yield_replaced(self, string, splitter, ignore_errors=False):
120  while splitter.identifier:
121  yield unescape(string[:splitter.start])
122  try:
123  value = self._get_variable_get_variable(splitter)
124  except DataError:
125  if not ignore_errors:
126  raise
127  value = string[splitter.start:splitter.end]
128  yield unic(value)
129  string = string[splitter.end:]
130  splitter = VariableSplitter(string)
131  yield unescape(string)
132 
133  def _get_variable(self, splitter):
134  if splitter.identifier not in '$@&%':
135  return self._get_reserved_variable_get_reserved_variable(splitter)
136  name = splitter.get_replaced_variable(self)
137  variable = self._variables_variables[name]
138  for item in splitter.items:
139  variable = self._get_variable_item_get_variable_item(name, variable, item)
140  name = '%s[%s]' % (name, item)
141  return variable
142 
143  def _get_variable_item(self, name, variable, item):
144  if is_dict_like(variable):
145  return self._get_dict_variable_item_get_dict_variable_item(name, variable, item)
146  if is_list_like(variable):
147  return self._get_list_variable_item_get_list_variable_item(name, variable, item)
148  raise VariableError("Variable '%s' is %s, not list or dictionary, "
149  "and thus accessing item '%s' from it is not "
150  "possible."
151  % (name, type_name(variable), item))
152 
153  def _get_reserved_variable(self, splitter):
154  value = splitter.get_replaced_variable(self)
155  LOGGER.warn("Syntax '%s' is reserved for future use. Please "
156  "escape it like '\\%s'." % (value, value))
157  return value
158 
159  def _get_list_variable_item(self, name, variable, index):
160  index = self.replace_stringreplace_string(index)
161  try:
162  index = self._parse_list_variable_index_parse_list_variable_index(index, name[0] == '$')
163  except ValueError:
164  raise VariableError("List '%s' used with invalid index '%s'."
165  % (name, index))
166  try:
167  return variable[index]
168  except IndexError:
169  raise VariableError("List '%s' has no item in index %d."
170  % (name, index))
171 
172  def _parse_list_variable_index(self, index, support_slice=True):
173  if ':' not in index:
174  return int(index)
175  if index.count(':') > 2 or not support_slice:
176  raise ValueError
177  return slice(*[int(i) if i else None for i in index.split(':')])
178 
179  def _get_dict_variable_item(self, name, variable, key):
180  key = self.replace_scalarreplace_scalar(key)
181  try:
182  return variable[key]
183  except KeyError:
184  raise VariableError("Dictionary '%s' has no key '%s'."
185  % (name, key))
186  except TypeError as err:
187  raise VariableError("Dictionary '%s' used with invalid key: %s"
188  % (name, err))
Used when no keyword is found or there is more than one match.
Definition: errors.py:75
def _yield_replaced(self, string, splitter, ignore_errors=False)
Definition: replacer.py:119
def replace_string(self, string, ignore_errors=False)
Replaces variables from a string.
Definition: replacer.py:107
def _replace_list_until(self, items, replace_until, ignore_errors)
Definition: replacer.py:46
def _parse_list_variable_index(self, index, support_slice=True)
Definition: replacer.py:172
def _replace_string(self, string, splitter=None, ignore_errors=False)
Definition: replacer.py:114
def _replace_scalar(self, item, splitter=None, ignore_errors=False)
Definition: replacer.py:89
def _get_variable_item(self, name, variable, item)
Definition: replacer.py:143
def _get_list_variable_item(self, name, variable, index)
Definition: replacer.py:159
def _replace_list_item(self, item, ignore_errors)
Definition: replacer.py:66
def replace_scalar(self, item, ignore_errors=False)
Replaces variables from a scalar item.
Definition: replacer.py:84
def replace_list(self, items, replace_until=None, ignore_errors=False)
Replaces variables from a list of items.
Definition: replacer.py:40
def _get_dict_variable_item(self, name, variable, key)
Definition: replacer.py:179
def _replace_list(self, items, ignore_errors)
Definition: replacer.py:58