Robot Framework
assigner.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 import re
17 
18 from robot.errors import (DataError, ExecutionStatus, HandlerExecutionFailed,
19  VariableError)
20 from robot.utils import (ErrorDetails, format_assign_message, get_error_message,
21  is_number, is_string, prepr, type_name)
22 
23 
25 
26  def __init__(self, assignment):
27  validator = AssignmentValidator()
28  try:
29  self.assignmentassignment = [validator.validate(var) for var in assignment]
30  self.errorerror = None
31  except DataError as err:
32  self.assignmentassignment = assignment
33  self.errorerror = err
34 
35  def __iter__(self):
36  return iter(self.assignmentassignment)
37 
38  def __len__(self):
39  return len(self.assignmentassignment)
40 
42  if self.errorerror:
43  raise self.errorerror
44 
45  def assigner(self, context):
46  self.validate_assignmentvalidate_assignment()
47  return VariableAssigner(self.assignmentassignment, context)
48 
49 
51 
52  def __init__(self):
53  self._seen_list_seen_list = False
54  self._seen_dict_seen_dict = False
55  self._seen_any_var_seen_any_var = False
56  self._seen_assign_mark_seen_assign_mark = False
57 
58  def validate(self, variable):
59  variable = self._validate_assign_mark_validate_assign_mark(variable)
60  self._validate_state_validate_state(is_list=variable[0] == '@',
61  is_dict=variable[0] == '&')
62  return variable
63 
64  def _validate_assign_mark(self, variable):
65  if self._seen_assign_mark_seen_assign_mark:
66  raise DataError("Assign mark '=' can be used only with the last variable.",
67  syntax=True)
68  if variable.endswith('='):
69  self._seen_assign_mark_seen_assign_mark = True
70  return variable[:-1].rstrip()
71  return variable
72 
73  def _validate_state(self, is_list, is_dict):
74  if is_list and self._seen_list_seen_list:
75  raise DataError('Assignment can contain only one list variable.',
76  syntax=True)
77  if self._seen_dict_seen_dict or is_dict and self._seen_any_var_seen_any_var:
78  raise DataError('Dictionary variable cannot be assigned with other '
79  'variables.', syntax=True)
80  self._seen_list_seen_list += is_list
81  self._seen_dict_seen_dict += is_dict
82  self._seen_any_var_seen_any_var = True
83 
84 
86 
89  _valid_extended_attr = re.compile(r'^[_a-zA-Z]\w*$')
90 
91  def __init__(self, assignment, context):
92  self._assignment_assignment = assignment
93  self._context_context = context
94 
95  def __enter__(self):
96  return self
97 
98  def __exit__(self, etype, error, tb):
99  if error is None:
100  return
101  if not isinstance(error, ExecutionStatus):
102  error = HandlerExecutionFailed(ErrorDetails(error))
103  if error.can_continue(self._context_context):
104  self.assignassign(error.return_value)
105 
106  def assign(self, return_value):
107  context = self._context_context
108  context.trace(lambda: 'Return: %s' % prepr(return_value))
109  resolver = ReturnValueResolver(self._assignment_assignment)
110  for name, value in resolver.resolve(return_value):
111  if not self._extended_assign_extended_assign(name, value, context.variables):
112  value = self._normal_assign_normal_assign(name, value, context.variables)
113  context.info(format_assign_message(name, value))
114 
115  def _extended_assign(self, name, value, variables):
116  if name[0] != '$' or '.' not in name or name in variables:
117  return False
118  base, attr = [token.strip() for token in name[2:-1].rsplit('.', 1)]
119  try:
120  var = variables.replace_scalar('${%s}' % base)
121  except VariableError:
122  return False
123  if not (self._variable_supports_extended_assign_variable_supports_extended_assign(var) and
124  self._is_valid_extended_attribute_is_valid_extended_attribute(attr)):
125  return False
126  try:
127  setattr(var, attr, value)
128  except:
129  raise VariableError("Setting attribute '%s' to variable '${%s}' failed: %s"
130  % (attr, base, get_error_message()))
131  return True
132 
134  return not (is_string(var) or is_number(var))
135 
137  return self._valid_extended_attr_valid_extended_attr.match(attr) is not None
138 
139  def _normal_assign(self, name, value, variables):
140  variables[name] = value
141  # Always return the actually assigned value.
142  return value if name[0] == '$' else variables[name]
143 
144 
145 def ReturnValueResolver(assignment):
146  if not assignment:
147  return NoReturnValueResolver()
148  if len(assignment) == 1:
149  return OneReturnValueResolver(assignment[0])
150  if any(a[0] == '@' for a in assignment):
151  return ScalarsAndListReturnValueResolver(assignment)
152  return ScalarsOnlyReturnValueResolver(assignment)
153 
154 
156 
157  def resolve(self, return_value):
158  return []
159 
160 
162 
163  def __init__(self, variable):
164  self._variable_variable = variable
165 
166  def resolve(self, return_value):
167  if return_value is None:
168  identifier = self._variable_variable[0]
169  return_value = {'$': None, '@': [], '&': {}}[identifier]
170  return [(self._variable_variable, return_value)]
171 
172 
174 
175  def __init__(self, variables):
176  self._variables_variables = variables
177  self._min_count_min_count = len(variables)
178 
179  def resolve(self, return_value):
180  return_value = self._convert_to_list_convert_to_list(return_value)
181  self._validate_validate(len(return_value))
182  return self._resolve_resolve(return_value)
183 
184  def _convert_to_list(self, return_value):
185  if return_value is None:
186  return [None] * self._min_count_min_count
187  if is_string(return_value):
188  self._raise_expected_list_raise_expected_list(return_value)
189  try:
190  return list(return_value)
191  except TypeError:
192  self._raise_expected_list_raise_expected_list(return_value)
193 
194  def _raise_expected_list(self, ret):
195  self._raise_raise('Expected list-like value, got %s.' % type_name(ret))
196 
197  def _raise(self, error):
198  raise VariableError('Cannot set variables: %s' % error)
199 
200  def _validate(self, return_count):
201  raise NotImplementedError
202 
203  def _resolve(self, return_value):
204  raise NotImplementedError
205 
206 
208 
209  def _validate(self, return_count):
210  if return_count != self._min_count_min_count:
211  self._raise_raise('Expected %d return values, got %d.'
212  % (self._min_count_min_count, return_count))
213 
214  def _resolve(self, return_value):
215  return list(zip(self._variables_variables, return_value))
216 
217 
219 
220  def __init__(self, variables):
221  _MultiReturnValueResolver.__init__(self, variables)
222  self._min_count_min_count -= 1
223 
224  def _validate(self, return_count):
225  if return_count < self._min_count_min_count:
226  self._raise_raise('Expected %d or more return values, got %d.'
227  % (self._min_count_min_count, return_count))
228 
229  def _resolve(self, return_value):
230  before_vars, list_var, after_vars \
231  = self._split_variables_split_variables(self._variables_variables)
232  before_items, list_items, after_items \
233  = self._split_return_split_return(return_value, before_vars, after_vars)
234  before = list(zip(before_vars, before_items))
235  after = list(zip(after_vars, after_items))
236  return before + [(list_var, list_items)] + after
237 
238  def _split_variables(self, variables):
239  list_index = [v[0] for v in variables].index('@')
240  return (variables[:list_index],
241  variables[list_index],
242  variables[list_index+1:])
243 
244  def _split_return(self, return_value, before_vars, after_vars):
245  list_start = len(before_vars)
246  list_end = len(return_value) - len(after_vars)
247  return (return_value[:list_start],
248  return_value[list_start:list_end],
249  return_value[list_end:])
Used when variable does not exist.
Definition: errors.py:72
Object wrapping the last occurred exception.
Definition: error.py:51
def _validate_state(self, is_list, is_dict)
Definition: assigner.py:73
def _split_return(self, return_value, before_vars, after_vars)
Definition: assigner.py:244
def _normal_assign(self, name, value, variables)
Definition: assigner.py:139
def __exit__(self, etype, error, tb)
Definition: assigner.py:98
def _variable_supports_extended_assign(self, var)
Definition: assigner.py:133
def _extended_assign(self, name, value, variables)
Definition: assigner.py:115
def assign(self, return_value)
Definition: assigner.py:106
def __init__(self, assignment, context)
Definition: assigner.py:91
def get_error_message()
Returns error message of the last occurred exception.
Definition: error.py:34
def type_name(item, capitalize=False)
Return "non-technical" type name for objects and types.
Definition: robottypes.py:86
def format_assign_message(variable, value, cut_long=True)
Definition: text.py:91
def prepr(item, width=80)
Definition: unic.py:39
def ReturnValueResolver(assignment)
Definition: assigner.py:145