Robot Framework
xmlelementhandlers.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 
18 
20 
21  def __init__(self, execution_result, root_handler=None):
22  self._stack_stack = [(root_handler or RootHandler(), execution_result)]
23 
24  def start(self, elem):
25  handler, result = self._stack_stack[-1]
26  handler = handler.get_child_handler(elem.tag)
27  # Previous `result` being `None` means child elements should be ignored.
28  if result is not None:
29  result = handler.start(elem, result)
30  self._stack_stack.append((handler, result))
31 
32  def end(self, elem):
33  handler, result = self._stack_stack.pop()
34  if result is not None:
35  handler.end(elem, result)
36 
37 
39  element_handlers = {}
40  tag = None
41  children = frozenset()
42 
43  @classmethod
44  def register(cls, handler):
45  cls.element_handlerselement_handlers[handler.tag] = handler()
46  return handler
47 
48  def get_child_handler(self, tag):
49  if tag not in self.childrenchildren:
50  if not self.tagtag:
51  raise DataError("Incompatible root element '%s'." % tag)
52  raise DataError("Incompatible child element '%s' for '%s'."
53  % (tag, self.tagtag))
54  return self.element_handlerselement_handlers[tag]
55 
56  def start(self, elem, result):
57  return result
58 
59  def end(self, elem, result):
60  pass
61 
62  def _timestamp(self, elem, attr_name):
63  timestamp = elem.get(attr_name)
64  return timestamp if timestamp != 'N/A' else None
65 
66 
68  children = frozenset(('robot',))
69 
70 
71 @ElementHandler.register
73  tag = 'robot'
74  children = frozenset(('suite', 'statistics', 'errors'))
75 
76  def start(self, elem, result):
77  generator = elem.get('generator', 'unknown').split()[0].upper()
78  result.generated_by_robot = generator == 'ROBOT'
79  if result.rpa is None:
80  result.rpa = elem.get('rpa', 'false') == 'true'
81  return result
82 
83 
84 @ElementHandler.register
86  tag = 'suite'
87  # 'metadata' is for RF < 4 compatibility.
88  children = frozenset(('doc', 'metadata', 'meta', 'status', 'kw', 'test', 'suite'))
89 
90  def start(self, elem, result):
91  if hasattr(result, 'suite'): # root
92  return result.suite.config(name=elem.get('name', ''),
93  source=elem.get('source'),
94  rpa=result.rpa)
95  return result.suites.create(name=elem.get('name', ''),
96  source=elem.get('source'),
97  rpa=result.rpa)
98 
99  def get_child_handler(self, tag):
100  if tag == 'status':
101  return StatusHandler(set_status=False)
102  return ElementHandler.get_child_handler(self, tag)
103 
104 
105 @ElementHandler.register
107  tag = 'test'
108  # 'tags' is for RF < 4 compatibility.
109  children = frozenset(('doc', 'tags', 'tag', 'timeout', 'status', 'kw', 'if', 'for',
110  'try', 'while', 'return', 'break', 'continue', 'msg'))
111 
112  def start(self, elem, result):
113  lineno = elem.get('line')
114  if lineno:
115  lineno = int(lineno)
116  return result.tests.create(name=elem.get('name', ''), lineno=lineno)
117 
118 
119 @ElementHandler.register
121  tag = 'kw'
122  # 'arguments', 'assign' and 'tags' are for RF < 4 compatibility.
123  children = frozenset(('doc', 'arguments', 'arg', 'assign', 'var', 'tags', 'tag',
124  'timeout', 'status', 'msg', 'kw', 'if', 'for', 'try',
125  'while', 'return', 'break', 'continue'))
126 
127  def start(self, elem, result):
128  elem_type = elem.get('type')
129  if not elem_type:
130  creator = self._create_keyword_create_keyword
131  else:
132  creator = getattr(self, '_create_%s' % elem_type.lower().replace(' ', '_'))
133  return creator(elem, result)
134 
135  def _create_keyword(self, elem, result):
136  try:
137  body = result.body
138  except AttributeError:
139  body = self._get_body_for_suite_level_keyword_get_body_for_suite_level_keyword(result)
140  return body.create_keyword(kwname=elem.get('name', ''),
141  libname=elem.get('library'),
142  sourcename=elem.get('sourcename'))
143 
145  # Someone, most likely a listener, has created a `<kw>` element on suite level.
146  # Add the keyword into a suite setup or teardown, depending on have we already
147  # seen tests or not. Create an implicit setup/teardown if needed. Possible real
148  # setup/teardown parsed later will reset the implicit one otherwise, but leaves
149  # the added keyword into its body.
150  kw_type = 'teardown' if result.tests or result.suites else 'setup'
151  keyword = getattr(result, kw_type)
152  if not keyword:
153  keyword.config(kwname='Implicit %s' % kw_type, status=keyword.PASS)
154  return keyword.body
155 
156  def _create_setup(self, elem, result):
157  return result.setup.config(kwname=elem.get('name', ''),
158  libname=elem.get('library'))
159 
160  def _create_teardown(self, elem, result):
161  return result.teardown.config(kwname=elem.get('name', ''),
162  libname=elem.get('library'))
163 
164  # RF < 4 compatibility.
165 
166  def _create_for(self, elem, result):
167  return result.body.create_keyword(kwname=elem.get('name'), type='FOR')
168 
169  def _create_foritem(self, elem, result):
170  return result.body.create_keyword(kwname=elem.get('name'), type='ITERATION')
171 
172 
175  _create_iteration = _create_foritem
176 
177 
178 @ElementHandler.register
180  tag = 'for'
181  children = frozenset(('var', 'value', 'iter', 'status', 'doc', 'msg', 'kw'))
182 
183  def start(self, elem, result):
184  return result.body.create_for(flavor=elem.get('flavor'))
185 
186 
187 @ElementHandler.register
189  tag = 'while'
190  children = frozenset(('iter', 'status', 'doc', 'msg', 'kw'))
191 
192  def start(self, elem, result):
193  return result.body.create_while(
194  condition=elem.get('condition'),
195  limit=elem.get('limit')
196  )
197 
198 
199 @ElementHandler.register
201  tag = 'iter'
202  children = frozenset(('var', 'doc', 'status', 'kw', 'if', 'for', 'msg', 'try',
203  'while', 'return', 'break', 'continue'))
204 
205  def start(self, elem, result):
206  return result.body.create_iteration()
207 
208 
209 @ElementHandler.register
211  tag = 'if'
212  children = frozenset(('branch', 'status', 'doc', 'msg', 'kw'))
213 
214  def start(self, elem, result):
215  return result.body.create_if()
216 
217 
218 @ElementHandler.register
220  tag = 'branch'
221  children = frozenset(('status', 'kw', 'if', 'for', 'try', 'while', 'msg', 'doc',
222  'return', 'pattern', 'break', 'continue'))
223 
224  def start(self, elem, result):
225  return result.body.create_branch(**elem.attrib)
226 
227 
228 @ElementHandler.register
230  tag = 'try'
231  children = frozenset(('branch', 'status', 'doc', 'msg', 'kw'))
232 
233  def start(self, elem, result):
234  return result.body.create_try()
235 
236 
237 @ElementHandler.register
239  tag = 'pattern'
240  children = frozenset()
241 
242  def end(self, elem, result):
243  result.patterns += (elem.text or '',)
244 
245 
246 @ElementHandler.register
248  tag = 'return'
249  children = frozenset(('status', 'value', 'msg', 'kw'))
250 
251  def start(self, elem, result):
252  return result.body.create_return()
253 
254 
255 @ElementHandler.register
257  tag = 'continue'
258  children = frozenset(('status', 'msg', 'kw'))
259 
260  def start(self, elem, result):
261  return result.body.create_continue()
262 
263 
264 @ElementHandler.register
266  tag = 'break'
267  children = frozenset(('status', 'msg', 'kw'))
268 
269  def start(self, elem, result):
270  return result.body.create_break()
271 
272 
273 @ElementHandler.register
275  tag = 'msg'
276 
277  def end(self, elem, result):
278  html_true = ('true', 'yes') # 'yes' is compatibility for RF < 4.
279  result.body.create_message(elem.text or '',
280  elem.get('level', 'INFO'),
281  elem.get('html') in html_true,
282  self._timestamp_timestamp(elem, 'timestamp'))
283 
284 
285 @ElementHandler.register
287  tag = 'status'
288 
289  def __init__(self, set_status=True):
290  self.set_statusset_status = set_status
291 
292  def end(self, elem, result):
293  if self.set_statusset_status:
294  result.status = elem.get('status', 'FAIL')
295  result.starttime = self._timestamp_timestamp(elem, 'starttime')
296  result.endtime = self._timestamp_timestamp(elem, 'endtime')
297  if elem.text:
298  result.message = elem.text
299 
300 
301 @ElementHandler.register
303  tag = 'doc'
304 
305  def end(self, elem, result):
306  result.doc = elem.text or ''
307 
308 
309 @ElementHandler.register
310 class MetadataHandler(ElementHandler): # RF < 4 compatibility.
311  tag = 'metadata'
312  children = frozenset(('item',))
313 
314 
315 @ElementHandler.register
316 class MetadataItemHandler(ElementHandler): # RF < 4 compatibility.
317  tag = 'item'
318 
319  def end(self, elem, result):
320  result.metadata[elem.get('name', '')] = elem.text or ''
321 
322 
323 @ElementHandler.register
325  tag = 'meta'
326 
327  def end(self, elem, result):
328  result.metadata[elem.get('name', '')] = elem.text or ''
329 
330 
331 @ElementHandler.register
332 class TagsHandler(ElementHandler): # RF < 4 compatibility.
333  tag = 'tags'
334  children = frozenset(('tag',))
335 
336 
337 @ElementHandler.register
339  tag = 'tag'
340 
341  def end(self, elem, result):
342  result.tags.add(elem.text or '')
343 
344 
345 @ElementHandler.register
347  tag = 'timeout'
348 
349  def end(self, elem, result):
350  result.timeout = elem.get('value')
351 
352 
353 @ElementHandler.register
354 class AssignHandler(ElementHandler): # RF < 4 compatibility.
355  tag = 'assign'
356  children = frozenset(('var',))
357 
358 
359 @ElementHandler.register
361  tag = 'var'
362 
363  def end(self, elem, result):
364  value = elem.text or ''
365  if result.type == result.KEYWORD:
366  result.assign += (value,)
367  elif result.type == result.FOR:
368  result.variables += (value,)
369  elif result.type == result.ITERATION:
370  result.variables[elem.get('name')] = value
371  else:
372  raise DataError("Invalid element '%s' for result '%r'." % (elem, result))
373 
374 
375 @ElementHandler.register
376 class ArgumentsHandler(ElementHandler): # RF < 4 compatibility.
377  tag = 'arguments'
378  children = frozenset(('arg',))
379 
380 
381 @ElementHandler.register
383  tag = 'arg'
384 
385  def end(self, elem, result):
386  result.args += (elem.text or '',)
387 
388 
389 @ElementHandler.register
391  tag = 'value'
392 
393  def end(self, elem, result):
394  result.values += (elem.text or '',)
395 
396 
397 @ElementHandler.register
399  tag = 'errors'
400 
401  def start(self, elem, result):
402  return result.errors
403 
404  def get_child_handler(self, tag):
405  return ErrorMessageHandler()
406 
407 
409 
410  def end(self, elem, result):
411  html_true = ('true', 'yes') # 'yes' is compatibility for RF < 4.
412  result.messages.create(elem.text or '',
413  elem.get('level', 'INFO'),
414  elem.get('html') in html_true,
415  self._timestamp_timestamp(elem, 'timestamp'))
416 
417 
418 @ElementHandler.register
420  tag = 'statistics'
421 
422  def get_child_handler(self, tag):
423  return self
def __init__(self, execution_result, root_handler=None)