Robot Framework
model.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 
35 
36 import os
37 
38 from robot import model
39 from robot.conf import RobotSettings
40 from robot.errors import BreakLoop, ContinueLoop, ReturnFromKeyword, DataError
41 from robot.model import Keywords, BodyItem
42 from robot.output import LOGGER, Output, pyloggingconf
43 from robot.result import (Break as BreakResult, Continue as ContinueResult,
44  Return as ReturnResult)
45 from robot.utils import seq2str, setter
46 
47 from .bodyrunner import ForRunner, IfRunner, KeywordRunner, TryRunner, WhileRunner
48 from .randomizer import Randomizer
49 from .statusreporter import StatusReporter
50 
51 
53  __slots__ = []
54 
55 
56 @Body.register
57 
65  __slots__ = ['lineno']
66 
67  def __init__(self, name='', doc='', args=(), assign=(), tags=(), timeout=None,
68  type=BodyItem.KEYWORD, parent=None, lineno=None):
69  super().__init__(name, doc, args, assign, tags, timeout, type, parent)
70  self.linenolineno = lineno
71 
72  @property
73  source = property
74 
75  def source(self):
76  return self.parentparent.source if self.parentparent is not None else None
77 
78  def run(self, context, run=True, templated=None):
79  return KeywordRunner(context, run).run(self)
80 
81 
82 @Body.register
83 class For(model.For):
84  __slots__ = ['lineno', 'error']
85  body_class = Body
86 
87  def __init__(self, variables, flavor, values, parent=None, lineno=None, error=None):
88  super().__init__(variables, flavor, values, parent)
89  self.linenolineno = lineno
90  self.errorerror = error
91 
92  @property
93  source = property
94 
95  def source(self):
96  return self.parentparent.source if self.parentparent is not None else None
97 
98  def run(self, context, run=True, templated=False):
99  return ForRunner(context, self.flavorflavor, run, templated).run(self)
100 
101 
102 @Body.register
104  __slots__ = ['lineno', 'error']
105  body_class = Body
106 
107  def __init__(self, condition=None, limit=None, parent=None, lineno=None, error=None):
108  super().__init__(condition, limit, parent)
109  self.linenolineno = lineno
110  self.errorerror = error
111 
112  @property
113  source = property
114 
115  def source(self):
116  return self.parentparent.source if self.parentparent is not None else None
117 
118  def run(self, context, run=True, templated=False):
119  return WhileRunner(context, run, templated).run(self)
120 
121 
123  __slots__ = ['lineno']
124  body_class = Body
125 
126  def __init__(self, type=BodyItem.IF, condition=None, parent=None, lineno=None):
127  super().__init__(type, condition, parent)
128  self.linenolineno = lineno
129 
130  @property
131  source = property
132 
133  def source(self):
134  return self.parentparent.source if self.parentparent is not None else None
135 
136 
137 @Body.register
138 class If(model.If):
139  __slots__ = ['lineno', 'error']
140  branch_class = IfBranch
141 
142  def __init__(self, parent=None, lineno=None, error=None):
143  super().__init__(parent)
144  self.linenolineno = lineno
145  self.errorerror = error
146 
147  @property
148  source = property
149 
150  def source(self):
151  return self.parentparent.source if self.parentparent is not None else None
152 
153  def run(self, context, run=True, templated=False):
154  return IfRunner(context, run, templated).run(self)
155 
156 
158  __slots__ = ['lineno']
159  body_class = Body
160 
161  def __init__(self, type=BodyItem.TRY, patterns=(), pattern_type=None,
162  variable=None, parent=None, lineno=None):
163  super().__init__(type, patterns, pattern_type, variable, parent)
164  self.linenolineno = lineno
165 
166  @property
167  source = property
168 
169  def source(self):
170  return self.parentparent.source if self.parentparent is not None else None
171 
172 
173 @Body.register
174 class Try(model.Try):
175  __slots__ = ['lineno', 'error']
176  branch_class = TryBranch
177 
178  def __init__(self, parent=None, lineno=None, error=None):
179  super().__init__(parent)
180  self.linenolineno = lineno
181  self.errorerror = error
182 
183  @property
184  source = property
185 
186  def source(self):
187  return self.parentparent.source if self.parentparent is not None else None
188 
189  def run(self, context, run=True, templated=False):
190  return TryRunner(context, run, templated).run(self)
191 
192 
193 @Body.register
195  __slots__ = ['lineno', 'error']
196 
197  def __init__(self, values=(), parent=None, lineno=None, error=None):
198  super().__init__(values, parent)
199  self.linenolineno = lineno
200  self.errorerror = error
201 
202  @property
203  source = property
204 
205  def source(self):
206  return self.parentparent.source if self.parentparent is not None else None
207 
208  def run(self, context, run=True, templated=False):
209  with StatusReporter(self, ReturnResult(self.valuesvalues), context, run):
210  if run:
211  if self.errorerror:
212  raise DataError(self.errorerror, syntax=True)
213  if not context.dry_run:
214  raise ReturnFromKeyword(self.valuesvalues)
215 
216 
217 @Body.register
219  __slots__ = ['lineno', 'error']
220 
221  def __init__(self, parent=None, lineno=None, error=None):
222  super().__init__(parent)
223  self.linenolineno = lineno
224  self.errorerror = error
225 
226  @property
227  source = property
228 
229  def source(self):
230  return self.parentparent.source if self.parentparent is not None else None
231 
232  def run(self, context, run=True, templated=False):
233  with StatusReporter(self, ContinueResult(), context, run):
234  if run:
235  if self.errorerror:
236  raise DataError(self.errorerror, syntax=True)
237  if not context.dry_run:
238  raise ContinueLoop()
239 
240 
241 @Body.register
243  __slots__ = ['lineno', 'error']
244 
245  def __init__(self, parent=None, lineno=None, error=None):
246  super().__init__(parent)
247  self.linenolineno = lineno
248  self.errorerror = error
249 
250  @property
251  source = property
252 
253  def source(self):
254  return self.parentparent.source if self.parentparent is not None else None
255 
256  def run(self, context, run=True, templated=False):
257  with StatusReporter(self, BreakResult(), context, run):
258  if run:
259  if self.errorerror:
260  raise DataError(self.errorerror, syntax=True)
261  if not context.dry_run:
262  raise BreakLoop()
263 
264 
265 
270  __slots__ = ['template']
271  body_class = Body #: Internal usage only.
272  fixture_class = Keyword #: Internal usage only.
273 
274  def __init__(self, name='', doc='', tags=None, timeout=None, template=None,
275  lineno=None):
276  super().__init__(name, doc, tags, timeout, lineno)
277  #: Name of the keyword that has been used as a template when building the test.
278  # ``None`` if template is not used.
279  self.templatetemplate = template
280 
281  @property
282  source = property
283 
284  def source(self):
285  return self.parentparent.source if self.parentparent is not None else None
286 
287 
288 
293  __slots__ = ['resource']
294  test_class = TestCase #: Internal usage only.
295  fixture_class = Keyword #: Internal usage only.
296 
297  def __init__(self, name='', doc='', metadata=None, source=None, rpa=None):
298  super().__init__(name, doc, metadata, source, rpa)
299  #: :class:`ResourceFile` instance containing imports, variables and
300  #: keywords the suite owns. When data is parsed from the file system,
301  #: this data comes from the same test case file that creates the suite.
302  self.resourceresource = ResourceFile(source=source)
303 
304  @classmethod
305 
314  def from_file_system(cls, *paths, **config):
315  from .builder import TestSuiteBuilder
316  return TestSuiteBuilder(**config).build(*paths)
317 
318  @classmethod
319 
327  def from_model(cls, model, name=None):
328  from .builder import RobotParser
329  return RobotParser().build_suite(model, name)
330 
331 
349  def configure(self, randomize_suites=False, randomize_tests=False,
350  randomize_seed=None, **options):
351  model.TestSuite.configure(self, **options)
352  self.randomizerandomize(randomize_suites, randomize_tests, randomize_seed)
353 
354 
361  def randomize(self, suites=True, tests=True, seed=None):
362  self.visitvisit(Randomizer(suites, tests, seed))
363 
364 
417  def run(self, settings=None, **options):
418  from .namespace import IMPORTER
419  from .signalhandler import STOP_SIGNAL_MONITOR
420  from .suiterunner import SuiteRunner
421 
422  with LOGGER:
423  if not settings:
424  settings = RobotSettings(options)
425  LOGGER.register_console_logger(**settings.console_output_config)
426  with pyloggingconf.robot_handler_enabled(settings.log_level):
427  with STOP_SIGNAL_MONITOR:
428  IMPORTER.reset()
429  output = Output(settings)
430  runner = SuiteRunner(output, settings)
431  self.visitvisit(runner)
432  output.close(runner.result)
433  return runner.result
434 
435 
436 class Variable:
437 
438  def __init__(self, name, value, source=None, lineno=None, error=None):
439  self.namename = name
440  self.valuevalue = value
441  self.sourcesource = source
442  self.linenolineno = lineno
443  self.errorerror = error
444 
445  def report_invalid_syntax(self, message, level='ERROR'):
446  source = self.sourcesource or '<unknown>'
447  line = f' on line {self.lineno}' if self.linenolineno else ''
448  LOGGER.write(f"Error in file '{source}'{line}: "
449  f"Setting variable '{self.name}' failed: {message}", level)
450 
451 
453 
454  def __init__(self, doc='', source=None):
455  self.docdoc = doc
456  self.sourcesource = source
457  self.importsimportsimports = []
458  self.keywordskeywordskeywords = []
459  self.variablesvariablesvariables = []
460 
461  @setter
462  def imports(self, imports):
463  return Imports(self.sourcesource, imports)
464 
465  @setter
466  def keywords(self, keywords):
467  return model.ItemList(UserKeyword, {'parent': self}, items=keywords)
468 
469  @setter
470  def variables(self, variables):
471  return model.ItemList(Variable, {'source': self.sourcesource}, items=variables)
472 
473 
475 
476  def __init__(self, name, args=(), doc='', tags=(), return_=None,
477  timeout=None, lineno=None, parent=None, error=None):
478  self.namename = name
479  self.argsargs = args
480  self.docdoc = doc
481  self.tagstagstags = tags
482  self.return_return_ = return_ or ()
483  self.timeouttimeout = timeout
484  self.linenolineno = lineno
485  self.parentparent = parent
486  self.errorerror = error
487  self.bodybodybody = None
488  self._teardown_teardown = None
489 
490  @setter
491 
492  def body(self, body):
493  return Body(self, body)
494 
495  @property
496 
500  keywords = property
501 
502  def keywords(self):
503  kws = list(self.bodybodybody)
504  if self.teardownteardownteardown:
505  kws.append(self.teardownteardownteardown)
506  return Keywords(self, kws)
507 
508  @keywords.setter
509 
510  def keywords(self, keywords):
511  Keywords.raise_deprecation_error()
512 
513  @property
514  teardown = property
515 
516  def teardown(self):
517  if self._teardown_teardown is None:
518  self._teardown_teardown = Keyword(None, parent=self, type=Keyword.TEARDOWN)
519  return self._teardown_teardown
520 
521  @setter
522  def tags(self, tags):
523  return model.Tags(tags)
524 
525  @property
526  source = property
527 
528  def source(self):
529  return self.parentparent.source if self.parentparent is not None else None
530 
531 
532 class Import:
533  ALLOWED_TYPES = ('Library', 'Resource', 'Variables')
534 
535  def __init__(self, type, name, args=(), alias=None, source=None, lineno=None):
536  if type not in self.ALLOWED_TYPESALLOWED_TYPES:
537  raise ValueError(f"Invalid import type '{type}'. Should be one of "
538  f"{seq2str(self.ALLOWED_TYPES, lastsep=' or ')}.")
539  self.typetype = type
540  self.namename = name
541  self.argsargs = args
542  self.aliasalias = alias
543  self.sourcesource = source
544  self.linenolineno = lineno
545 
546  @property
547  directory = property
548 
549  def directory(self):
550  if not self.sourcesource:
551  return None
552  if os.path.isdir(self.sourcesource):
553  return self.sourcesource
554  return os.path.dirname(self.sourcesource)
555 
556  def report_invalid_syntax(self, message, level='ERROR'):
557  source = self.sourcesource or '<unknown>'
558  line = f' on line {self.lineno}' if self.linenolineno else ''
559  LOGGER.write(f"Error in file '{source}'{line}: {message}", level)
560 
561 
563 
564  def __init__(self, source, imports=None):
565  super().__init__(Import, {'source': source}, items=imports)
566 
567  def library(self, name, args=(), alias=None, lineno=None):
568  self.createcreate('Library', name, args, alias, lineno)
569 
570  def resource(self, path, lineno=None):
571  self.createcreate('Resource', path, lineno)
572 
573  def variables(self, path, args=(), lineno=None):
574  self.createcreate('Variables', path, args, lineno)
Used by BREAK statement.
Definition: errors.py:316
Used by CONTINUE statement.
Definition: errors.py:309
Used by 'RETURN' statement.
Definition: errors.py:323
def create(self, *args, **kwargs)
Definition: itemlist.py:33
A list-like object representing keywords in a suite, a test or a keyword.
Definition: keyword.py:137
def visit(self, visitor)
:mod:Visitor interface <robot.model.visitor> entry-point.
Definition: testsuite.py:288
def __init__(self, status='FAIL', starttime=None, endtime=None, parent=None)
Definition: model.py:425
def __init__(self, status='FAIL', starttime=None, endtime=None, parent=None)
Definition: model.py:388
def __init__(self, values=(), status='FAIL', starttime=None, endtime=None, parent=None)
Definition: model.py:351
def __init__(self, variables, flavor, values, parent=None, lineno=None, error=None)
Definition: model.py:87
def run(self, context, run=True, templated=False)
Definition: model.py:98
def __init__(self, type=BodyItem.IF, condition=None, parent=None, lineno=None)
Definition: model.py:126
def __init__(self, parent=None, lineno=None, error=None)
Definition: model.py:142
def run(self, context, run=True, templated=False)
Definition: model.py:153
def __init__(self, type, name, args=(), alias=None, source=None, lineno=None)
Definition: model.py:535
def report_invalid_syntax(self, message, level='ERROR')
Definition: model.py:556
def __init__(self, source, imports=None)
Definition: model.py:564
def resource(self, path, lineno=None)
Definition: model.py:570
def variables(self, path, args=(), lineno=None)
Definition: model.py:573
def library(self, name, args=(), alias=None, lineno=None)
Definition: model.py:567
Represents a single executable keyword.
Definition: model.py:64
def run(self, context, run=True, templated=None)
Definition: model.py:78
def __init__(self, name='', doc='', args=(), assign=(), tags=(), timeout=None, type=BodyItem.KEYWORD, parent=None, lineno=None)
Definition: model.py:68
def __init__(self, doc='', source=None)
Definition: model.py:454
def imports(self, imports)
Definition: model.py:462
def keywords(self, keywords)
Definition: model.py:466
def variables(self, variables)
Definition: model.py:470
Represents a single executable test case.
Definition: model.py:269
def __init__(self, name='', doc='', tags=None, timeout=None, template=None, lineno=None)
Definition: model.py:275
Represents a single executable test suite.
Definition: model.py:292
def configure(self, randomize_suites=False, randomize_tests=False, randomize_seed=None, **options)
A shortcut to configure a suite using one method call.
Definition: model.py:350
def __init__(self, name='', doc='', metadata=None, source=None, rpa=None)
Definition: model.py:297
def run(self, settings=None, **options)
Executes the suite based based the given settings or options.
Definition: model.py:417
def from_file_system(cls, *paths, **config)
Create a :class:TestSuite object based on the given paths.
Definition: model.py:314
def from_model(cls, model, name=None)
Create a :class:TestSuite object based on the given model.
Definition: model.py:327
def randomize(self, suites=True, tests=True, seed=None)
Randomizes the order of suites and/or tests, recursively.
Definition: model.py:361
def __init__(self, type=BodyItem.TRY, patterns=(), pattern_type=None, variable=None, parent=None, lineno=None)
Definition: model.py:162
def __init__(self, parent=None, lineno=None, error=None)
Definition: model.py:178
def run(self, context, run=True, templated=False)
Definition: model.py:189
def body(self, body)
Child keywords as a :class:~.Body object.
Definition: model.py:492
def __init__(self, name, args=(), doc='', tags=(), return_=None, timeout=None, lineno=None, parent=None, error=None)
Definition: model.py:477
keywords
Deprecated since Robot Framework 4.0.
Definition: model.py:500
def tags(self, tags)
Definition: model.py:522
def report_invalid_syntax(self, message, level='ERROR')
Definition: model.py:445
def __init__(self, name, value, source=None, lineno=None, error=None)
Definition: model.py:438
def run(self, context, run=True, templated=False)
Definition: model.py:118
def __init__(self, condition=None, limit=None, parent=None, lineno=None, error=None)
Definition: model.py:107
def run(*tests, **options)
Programmatic entry point for running tests.
Definition: run.py:557
def ForRunner(context, flavor='IN', run=True, templated=False)
Definition: bodyrunner.py:78