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