Robot Framework Integrated Development Environment (RIDE)
userkeywordrunner.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 itertools import chain
17 
18 from robotide.lib.robot.errors import (ExecutionFailed, ExecutionPassed, ExecutionStatus,
19  ExitForLoop, ContinueForLoop, DataError,
20  PassExecution, ReturnFromKeyword,
21  UserKeywordExecutionFailed, VariableError)
22 from robotide.lib.robot.result import Keyword as KeywordResult
23 from robotide.lib.robot.utils import getshortdoc, DotDict, prepr, split_tags_from_doc
24 from robotide.lib.robot.variables import is_list_var, VariableAssignment
25 
26 from .arguments import DefaultValue
27 from .statusreporter import StatusReporter
28 from .steprunner import StepRunner
29 from .timeouts import KeywordTimeout
30 
31 
33 
34  def __init__(self, handler, name=None):
35  self._handler_handler = handler
36  self.namename = name or handler.name
37 
38  @property
39  longname = property
40 
41  def longname(self):
42  libname = self._handler_handler.libname
43  return '%s.%s' % (libname, self.namename) if libname else self.namename
44 
45  @property
46  libname = property
47 
48  def libname(self):
49  return self._handler_handler.libname
50 
51  @property
52  arguments = property
53 
54  def arguments(self):
55  return self._handler_handler.arguments
56 
57  def run(self, kw, context):
58  assignment = VariableAssignment(kw.assign)
59  result = self._get_result_get_result(kw, assignment, context.variables)
60  with StatusReporter(context, result):
61  with assignment.assigner(context) as assigner:
62  return_value = self._run_run(context, kw.args, result)
63  assigner.assign(return_value)
64  return return_value
65 
66  def _get_result(self, kw, assignment, variables):
67  handler = self._handler_handler
68  doc = variables.replace_string(handler.doc, ignore_errors=True)
69  doc, tags = split_tags_from_doc(doc)
70  tags = variables.replace_list(handler.tags, ignore_errors=True) + tags
71  return KeywordResult(kwname=self.namename,
72  libname=handler.libname,
73  doc=getshortdoc(doc),
74  args=kw.args,
75  assign=tuple(assignment),
76  tags=tags,
77  type=kw.type)
78 
79  def _run(self, context, args, result):
80  variables = context.variables
81  args = self._resolve_arguments_resolve_arguments(args, variables)
82  with context.user_keyword:
83  self._set_arguments_set_arguments(args, context)
84  timeout = self._get_timeout_get_timeout(variables)
85  if timeout is not None:
86  result.timeout = str(timeout)
87  with context.timeout(timeout):
88  exception, return_ = self._execute_execute(context)
89  if exception and not exception.can_continue(context.in_teardown):
90  raise exception
91  return_value = self._get_return_value_get_return_value(variables, return_)
92  if exception:
93  exception.return_value = return_value
94  raise exception
95  return return_value
96 
97  def _get_timeout(self, variables=None):
98  timeout = self._handler_handler.timeout
99  if not timeout:
100  return None
101  timeout = KeywordTimeout(timeout.value, timeout.message, variables)
102  return timeout
103 
104  def _resolve_arguments(self, arguments, variables=None):
105  return self.argumentsargumentsarguments.resolve(arguments, variables)
106 
107  def _set_arguments(self, arguments, context):
108  positional, named = arguments
109  variables = context.variables
110  args, kwargs = self.argumentsargumentsarguments.map(positional, named,
111  replace_defaults=False)
112  self._set_variables_set_variables(args, kwargs, variables)
113  context.output.trace(lambda: self._trace_log_args_message_trace_log_args_message(variables))
114 
115  def _set_variables(self, positional, kwargs, variables):
116  spec = self.argumentsargumentsarguments
117  args, varargs = self._split_args_and_varargs_split_args_and_varargs(positional)
118  kwonly, kwargs = self._split_kwonly_and_kwargs_split_kwonly_and_kwargs(kwargs)
119  for name, value in chain(zip(spec.positional, args), kwonly):
120  if isinstance(value, DefaultValue):
121  value = value.resolve(variables)
122  variables['${%s}' % name] = value
123  if spec.varargs:
124  variables['@{%s}' % spec.varargs] = varargs
125  if spec.kwargs:
126  variables['&{%s}' % spec.kwargs] = DotDict(kwargs)
127 
128  def _split_args_and_varargs(self, args):
129  if not self.argumentsargumentsarguments.varargs:
130  return args, []
131  positional = len(self.argumentsargumentsarguments.positional)
132  return args[:positional], args[positional:]
133 
134  def _split_kwonly_and_kwargs(self, all_kwargs):
135  kwonly = []
136  kwargs = []
137  for name, value in all_kwargs:
138  target = kwonly if name in self.argumentsargumentsarguments.kwonlyargs else kwargs
139  target.append((name, value))
140  return kwonly, kwargs
141 
142  def _trace_log_args_message(self, variables):
143  args = ['${%s}' % arg for arg in self.argumentsargumentsarguments.positional]
144  if self.argumentsargumentsarguments.varargs:
145  args.append('@{%s}' % self.argumentsargumentsarguments.varargs)
146  if self.argumentsargumentsarguments.kwargs:
147  args.append('&{%s}' % self.argumentsargumentsarguments.kwargs)
148  return self._format_trace_log_args_message_format_trace_log_args_message(args, variables)
149 
150  def _format_trace_log_args_message(self, args, variables):
151  args = ['%s=%s' % (name, prepr(variables[name])) for name in args]
152  return 'Arguments: [ %s ]' % ' | '.join(args)
153 
154  def _execute(self, context):
155  handler = self._handler_handler
156  if not (handler.keywords or handler.return_value):
157  raise DataError("User keyword '%s' contains no keywords." % self.namename)
158  if context.dry_run and 'robot:no-dry-run' in handler.tags:
159  return None, None
160  error = return_ = pass_ = None
161  try:
162  StepRunner(context).run_steps(handler.keywords)
163  except ReturnFromKeyword as exception:
164  return_ = exception
165  error = exception.earlier_failures
166  except (ExitForLoop, ContinueForLoop) as exception:
167  pass_ = exception
168  except ExecutionPassed as exception:
169  pass_ = exception
170  error = exception.earlier_failures
171  if error:
172  error.continue_on_failure = False
173  except ExecutionFailed as exception:
174  error = exception
175  with context.keyword_teardown(error):
176  td_error = self._run_teardown_run_teardown(context)
177  if error or td_error:
178  error = UserKeywordExecutionFailed(error, td_error)
179  return error or pass_, return_
180 
181  def _get_return_value(self, variables, return_):
182  ret = self._handler_handler.return_value if not return_ else return_.return_value
183  if not ret:
184  return None
185  contains_list_var = any(is_list_var(item) for item in ret)
186  try:
187  ret = variables.replace_list(ret)
188  except DataError as err:
189  raise VariableError('Replacing variables from keyword return value '
190  'failed: %s' % err.message)
191  if len(ret) != 1 or contains_list_var:
192  return ret
193  return ret[0]
194 
195  def _run_teardown(self, context):
196  if not self._handler_handler.teardown:
197  return None
198  try:
199  name = context.variables.replace_string(self._handler_handler.teardown.name)
200  except DataError as err:
201  return ExecutionFailed(err.message, syntax=True)
202  if name.upper() in ('', 'NONE'):
203  return None
204  try:
205  StepRunner(context).run_step(self._handler_handler.teardown, name)
206  except PassExecution:
207  return None
208  except ExecutionStatus as err:
209  return err
210  return None
211 
212  def dry_run(self, kw, context):
213  assignment = VariableAssignment(kw.assign)
214  result = self._get_result_get_result(kw, assignment, context.variables)
215  with StatusReporter(context, result):
216  assignment.validate_assignment()
217  self._dry_run_dry_run(context, kw.args, result)
218 
219  def _dry_run(self, context, args, result):
220  self._resolve_arguments_resolve_arguments(args)
221  with context.user_keyword:
222  timeout = self._get_timeout_get_timeout()
223  if timeout:
224  result.timeout = str(timeout)
225  error, _ = self._execute_execute(context)
226  if error:
227  raise error
228 
229 
231 
232  def __init__(self, handler, name):
233  UserKeywordRunner.__init__(self, handler, name)
234  match = handler.embedded_name.match(name)
235  if not match:
236  raise ValueError('Does not match given name')
237  self.embedded_argsembedded_args = list(zip(handler.embedded_args, match.groups()))
238 
239  def _resolve_arguments(self, args, variables=None):
240  # Validates that no arguments given.
241  self.argumentsargumentsarguments.resolve(args, variables)
242  if not variables:
243  return []
244  return [(n, variables.replace_scalar(v)) for n, v in self.embedded_argsembedded_args]
245 
246  def _set_arguments(self, embedded_args, context):
247  variables = context.variables
248  for name, value in embedded_args:
249  variables['${%s}' % name] = value
250  context.output.trace(lambda: self._trace_log_args_message_trace_log_args_message_trace_log_args_message(variables))
251 
252  def _trace_log_args_message(self, variables):
253  args = ['${%s}' % arg for arg, _ in self.embedded_argsembedded_args]
254  return self._format_trace_log_args_message_format_trace_log_args_message(args, variables)
Used when variable does not exist.
Definition: errors.py:67
Used for communicating failures in test execution.
Definition: errors.py:177
Used when no keyword is found or there is more than one match.
Definition: errors.py:75
def getshortdoc(doc_or_item, linesep='\n')
Definition: text.py:181
def split_tags_from_doc(doc)
Definition: text.py:158
def prepr(item, width=80)
Definition: unic.py:69