Robot Framework
librarykeywordrunner.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 robot.errors import DataError
17 from robot.output import LOGGER
18 from robot.result import Keyword as KeywordResult
19 from robot.utils import prepr, safe_str
20 from robot.variables import contains_variable, is_list_variable, VariableAssignment
21 
22 from .bodyrunner import BodyRunner
23 from .model import Keyword
24 from .outputcapture import OutputCapturer
25 from .signalhandler import STOP_SIGNAL_MONITOR
26 from .statusreporter import StatusReporter
27 
28 
30 
31  def __init__(self, handler, name=None, languages=None):
32  self._handler_handler = handler
33  self.namename = name or handler.name
34  self.pre_run_messagespre_run_messages = ()
35  self.languageslanguages = languages
36 
37  @property
38  library = property
39 
40  def library(self):
41  return self._handler_handler.library
42 
43  @property
44  libname = property
45 
46  def libname(self):
47  return self._handler_handler.library.name
48 
49  @property
50  longname = property
51 
52  def longname(self):
53  return '%s.%s' % (self.librarylibrarylibrary.name, self.namename)
54 
55  def run(self, kw, context, run=True):
56  assignment = VariableAssignment(kw.assign)
57  result = self._get_result_get_result(kw, assignment)
58  with StatusReporter(kw, result, context, run):
59  if run:
60  with assignment.assigner(context) as assigner:
61  return_value = self._run_run(context, kw.args)
62  assigner.assign(return_value)
63  return return_value
64 
65  def _get_result(self, kw, assignment):
66  handler = self._handler_handler
67  return KeywordResult(kwname=self.namename,
68  libname=handler.libname,
69  doc=handler.shortdoc,
70  args=kw.args,
71  assign=tuple(assignment),
72  tags=handler.tags,
73  type=kw.type)
74 
75  def _run(self, context, args):
76  if self.pre_run_messagespre_run_messages:
77  for message in self.pre_run_messagespre_run_messages:
78  context.output.message(message)
79  variables = context.variables if not context.dry_run else None
80  positional, named = self._handler_handler.resolve_arguments(args, variables,
81  self.languageslanguages)
82  context.output.trace(lambda: self._trace_log_args_trace_log_args(positional, named))
83  runner = self._runner_for_runner_for(context, self._handler_handler.current_handler(),
84  positional, dict(named))
85  return self._run_with_output_captured_and_signal_monitor_run_with_output_captured_and_signal_monitor(runner, context)
86 
87  def _trace_log_args(self, positional, named):
88  args = [prepr(arg) for arg in positional]
89  args += ['%s=%s' % (safe_str(n), prepr(v)) for n, v in named]
90  return 'Arguments: [ %s ]' % ' | '.join(args)
91 
92  def _runner_for(self, context, handler, positional, named):
93  timeout = self._get_timeout_get_timeout(context)
94  if timeout and timeout.active:
95  def runner():
96  with LOGGER.delayed_logging:
97  context.output.debug(timeout.get_message)
98  return timeout.run(handler, args=positional, kwargs=named)
99  return runner
100  return lambda: handler(*positional, **named)
101 
102  def _get_timeout(self, context):
103  return min(context.timeouts) if context.timeouts else None
104 
106  with OutputCapturer():
107  return self._run_with_signal_monitoring_run_with_signal_monitoring(runner, context)
108 
109  def _run_with_signal_monitoring(self, runner, context):
110  try:
111  STOP_SIGNAL_MONITOR.start_running_keyword(context.in_teardown)
112  return runner()
113  finally:
114  STOP_SIGNAL_MONITOR.stop_running_keyword()
115 
116  def dry_run(self, kw, context):
117  assignment = VariableAssignment(kw.assign)
118  result = self._get_result_get_result(kw, assignment)
119  with StatusReporter(kw, result, context, run=False):
120  assignment.validate_assignment()
121  self._dry_run_dry_run(context, kw.args)
122 
123  def _dry_run(self, context, args):
124  if self._executed_in_dry_run_executed_in_dry_run(self._handler_handler):
125  self._run_run(context, args)
126  else:
127  self._handler_handler.resolve_arguments(args, languages=self.languageslanguages)
128 
129  def _executed_in_dry_run(self, handler):
130  keywords_to_execute = ('BuiltIn.Import Library',
131  'BuiltIn.Set Library Search Order',
132  'BuiltIn.Set Tags',
133  'BuiltIn.Remove Tags')
134  return (handler.libname == 'Reserved' or
135  handler.longname in keywords_to_execute)
136 
137 
139 
140  def __init__(self, handler, name):
141  super().__init__(handler, name)
142  self.embedded_argsembedded_args = handler.embedded.match(name).groups()
143 
144  def _run(self, context, args):
145  if args:
146  raise DataError("Positional arguments are not allowed when using "
147  "embedded arguments.")
148  return super()._run(context, self.embedded_argsembedded_args)
149 
150  def _dry_run(self, context, args):
151  return super()._dry_run(context, self.embedded_argsembedded_args)
152 
153  def _get_result(self, kw, assignment):
154  result = super()._get_result(kw, assignment)
155  result.sourcename = self._handler_handler.name
156  return result
157 
158 
160 
161  def __init__(self, handler, execute_in_dry_run=False):
162  super().__init__(handler)
163  self.execute_in_dry_runexecute_in_dry_run = execute_in_dry_run
164 
165  def _get_timeout(self, context):
166  # These keywords are not affected by timeouts. Keywords they execute are.
167  return None
168 
170  return self._run_with_signal_monitoring_run_with_signal_monitoring(runner, context)
171 
172  def _dry_run(self, context, args):
173  super()._dry_run(context, args)
174  keywords = [kw for kw in self._get_dry_run_keywords_get_dry_run_keywords(args)
175  if not contains_variable(kw.name)]
176  BodyRunner(context).run(keywords)
177 
178  def _get_dry_run_keywords(self, args):
179  if not self.execute_in_dry_runexecute_in_dry_run:
180  return []
181  name = self._handler_handler.name
182  if name == 'Run Keyword If':
183  return self._get_dry_run_keywords_for_run_keyword_if_get_dry_run_keywords_for_run_keyword_if(args)
184  if name == 'Run Keywords':
185  return self._get_dry_run_keywords_for_run_keyword_get_dry_run_keywords_for_run_keyword(args)
186  return self._get_dry_run_keywords_based_on_name_argument_get_dry_run_keywords_based_on_name_argument(args)
187 
189  for kw_call in self._get_run_kw_if_calls_get_run_kw_if_calls(given_args):
190  if kw_call:
191  yield Keyword(name=kw_call[0], args=kw_call[1:])
192 
193  def _get_run_kw_if_calls(self, given_args):
194  while 'ELSE IF' in given_args:
195  kw_call, given_args = self._split_run_kw_if_args_split_run_kw_if_args(given_args, 'ELSE IF', 2)
196  yield kw_call
197  if 'ELSE' in given_args:
198  kw_call, else_call = self._split_run_kw_if_args_split_run_kw_if_args(given_args, 'ELSE', 1)
199  yield kw_call
200  yield else_call
201  elif self._validate_kw_call_validate_kw_call(given_args):
202  expr, kw_call = given_args[0], given_args[1:]
203  if not is_list_variable(expr):
204  yield kw_call
205 
206  def _split_run_kw_if_args(self, given_args, control_word, required_after):
207  index = list(given_args).index(control_word)
208  expr_and_call = given_args[:index]
209  remaining = given_args[index+1:]
210  if not (self._validate_kw_call_validate_kw_call(expr_and_call) and
211  self._validate_kw_call_validate_kw_call(remaining, required_after)):
212  raise DataError("Invalid 'Run Keyword If' usage.")
213  if is_list_variable(expr_and_call[0]):
214  return (), remaining
215  return expr_and_call[1:], remaining
216 
217  def _validate_kw_call(self, kw_call, min_length=2):
218  if len(kw_call) >= min_length:
219  return True
220  return any(is_list_variable(item) for item in kw_call)
221 
223  for kw_call in self._get_run_kws_calls_get_run_kws_calls(given_args):
224  yield Keyword(name=kw_call[0], args=kw_call[1:])
225 
226  def _get_run_kws_calls(self, given_args):
227  if 'AND' not in given_args:
228  for kw_call in given_args:
229  yield [kw_call,]
230  else:
231  while 'AND' in given_args:
232  index = list(given_args).index('AND')
233  kw_call, given_args = given_args[:index], given_args[index + 1:]
234  yield kw_call
235  if given_args:
236  yield given_args
237 
239  index = list(self._handler_handler.arguments.positional).index('name')
240  return [Keyword(name=given_args[index], args=given_args[index+1:])]
Represents results of a single keyword.
Definition: model.py:464
def _runner_for(self, context, handler, positional, named)
def __init__(self, handler, name=None, languages=None)
def _run_with_output_captured_and_signal_monitor(self, runner, context)
def _split_run_kw_if_args(self, given_args, control_word, required_after)
def __init__(self, handler, execute_in_dry_run=False)
def prepr(item, width=80)
Definition: unic.py:39
def safe_str(item)
Definition: unic.py:21
def is_list_variable(string)
Definition: search.py:42
def contains_variable(string, identifiers='$@&')
Definition: search.py:28