Robot Framework Integrated Development Environment (RIDE)
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 robotide.lib.robot.errors import (DataError, ExecutionStatus, HandlerExecutionFailed,
19  VariableError)
20 from robotide.lib.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 "
67  "variable.")
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  if self._seen_dict_seen_dict or is_dict and self._seen_any_var_seen_any_var:
77  raise DataError('Dictionary variable cannot be assigned with '
78  'other variables.')
79  self._seen_list_seen_list += is_list
80  self._seen_dict_seen_dict += is_dict
81  self._seen_any_var_seen_any_var = True
82 
83 
85 
88  _valid_extended_attr = re.compile('^[_a-zA-Z]\w*$')
89 
90  def __init__(self, assignment, context):
91  self._assignment_assignment = assignment
92  self._context_context = context
93 
94  def __enter__(self):
95  return self
96 
97  def __exit__(self, exc_type, exc_val, exc_tb):
98  if exc_val is None:
99  return
100  failure = self._get_failure_get_failure(exc_type, exc_val, exc_tb)
101  if failure.can_continue(self._context_context.in_teardown):
102  self.assignassign(failure.return_value)
103 
104  def _get_failure(self, exc_type, exc_val, exc_tb):
105  if isinstance(exc_val, ExecutionStatus):
106  return exc_val
107  exc_info = (exc_type, exc_val, exc_tb)
108  return HandlerExecutionFailed(ErrorDetails(exc_info))
109 
110  def assign(self, return_value):
111  context = self._context_context
112  context.trace(lambda: 'Return: %s' % prepr(return_value))
113  resolver = ReturnValueResolver(self._assignment_assignment)
114  for name, value in resolver.resolve(return_value):
115  if not self._extended_assign_extended_assign(name, value, context.variables):
116  value = self._normal_assign_normal_assign(name, value, context.variables)
117  context.info(format_assign_message(name, value))
118 
119  def _extended_assign(self, name, value, variables):
120  if name[0] != '$' or '.' not in name or name in variables:
121  return False
122  base, attr = self._split_extended_assign_split_extended_assign(name)
123  try:
124  var = variables[base]
125  except DataError:
126  return False
127  if not (self._variable_supports_extended_assign_variable_supports_extended_assign(var) and
128  self._is_valid_extended_attribute_is_valid_extended_attribute(attr)):
129  return False
130  try:
131  setattr(var, attr, value)
132  except:
133  raise VariableError("Setting attribute '%s' to variable '%s' "
134  "failed: %s" % (attr, base, get_error_message()))
135  return True
136 
137  def _split_extended_assign(self, name):
138  base, attr = name.rsplit('.', 1)
139  return base.strip() + '}', attr[:-1].strip()
140 
142  return not (is_string(var) or is_number(var))
143 
145  return self._valid_extended_attr_valid_extended_attr.match(attr) is not None
146 
147  def _normal_assign(self, name, value, variables):
148  variables[name] = value
149  # Always return the actually assigned value.
150  return value if name[0] == '$' else variables[name]
151 
152 
153 def ReturnValueResolver(assignment):
154  if not assignment:
155  return NoReturnValueResolver()
156  if len(assignment) == 1:
157  return OneReturnValueResolver(assignment[0])
158  if any(a[0] == '@' for a in assignment):
159  return ScalarsAndListReturnValueResolver(assignment)
160  return ScalarsOnlyReturnValueResolver(assignment)
161 
162 
164 
165  def resolve(self, return_value):
166  return []
167 
168 
170 
171  def __init__(self, variable):
172  self._variable_variable = variable
173 
174  def resolve(self, return_value):
175  if return_value is None:
176  identifier = self._variable_variable[0]
177  return_value = {'$': None, '@': [], '&': {}}[identifier]
178  return [(self._variable_variable, return_value)]
179 
180 
182 
183  def __init__(self, variables):
184  self._variables_variables = variables
185  self._min_count_min_count = len(variables)
186 
187  def resolve(self, return_value):
188  return_value = self._convert_to_list_convert_to_list(return_value)
189  self._validate_validate(len(return_value))
190  return self._resolve_resolve(return_value)
191 
192  def _convert_to_list(self, return_value):
193  if return_value is None:
194  return [None] * self._min_count_min_count
195  if is_string(return_value):
196  self._raise_expected_list_raise_expected_list(return_value)
197  try:
198  return list(return_value)
199  except TypeError:
200  self._raise_expected_list_raise_expected_list(return_value)
201 
202  def _raise_expected_list(self, ret):
203  self._raise_raise('Expected list-like value, got %s.' % type_name(ret))
204 
205  def _raise(self, error):
206  raise VariableError('Cannot set variables: %s' % error)
207 
208  def _validate(self, return_count):
209  raise NotImplementedError
210 
211  def _resolve(self, return_value):
212  raise NotImplementedError
213 
214 
216 
217  def _validate(self, return_count):
218  if return_count != self._min_count_min_count:
219  self._raise_raise('Expected %d return values, got %d.'
220  % (self._min_count_min_count, return_count))
221 
222  def _resolve(self, return_value):
223  return list(zip(self._variables_variables, return_value))
224 
225 
227 
228  def __init__(self, variables):
229  _MultiReturnValueResolver.__init__(self, variables)
230  self._min_count_min_count -= 1
231 
232  def _validate(self, return_count):
233  if return_count < self._min_count_min_count:
234  self._raise_raise('Expected %d or more return values, got %d.'
235  % (self._min_count_min_count, return_count))
236 
237  def _resolve(self, return_value):
238  before_vars, list_var, after_vars \
239  = self._split_variables_split_variables(self._variables_variables)
240  before_items, list_items, after_items \
241  = self._split_return_split_return(return_value, before_vars, after_vars)
242  before = list(zip(before_vars, before_items))
243  after = list(zip(after_vars, after_items))
244  return before + [(list_var, list_items)] + after
245 
246  def _split_variables(self, variables):
247  list_index = [v[0] for v in variables].index('@')
248  return (variables[:list_index],
249  variables[list_index],
250  variables[list_index+1:])
251 
252  def _split_return(self, return_value, before_vars, after_vars):
253  list_start = len(before_vars)
254  list_end = len(return_value) - len(after_vars)
255  return (return_value[:list_start],
256  return_value[list_start:list_end],
257  return_value[list_end:])
Used when variable does not exist.
Definition: errors.py:67
Used when no keyword is found or there is more than one match.
Definition: errors.py:75
def _split_return(self, return_value, before_vars, after_vars)
Definition: assigner.py:252
def _get_failure(self, exc_type, exc_val, exc_tb)
Definition: assigner.py:104
def __exit__(self, exc_type, exc_val, exc_tb)
Definition: assigner.py:97
def _normal_assign(self, name, value, variables)
Definition: assigner.py:147
def _extended_assign(self, name, value, variables)
Definition: assigner.py:119
def ErrorDetails(exc_info=None, exclude_robot_traces=EXCLUDE_ROBOT_TRACES)
This factory returns an object that wraps the last occurred exception.
Definition: error.py:57
def get_error_message()
Returns error message of the last occurred exception.
Definition: error.py:41
def format_assign_message(variable, value, cut_long=True)
Definition: text.py:94
def prepr(item, width=80)
Definition: unic.py:69