Robot Framework
parsers.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 import os
17 from ast import NodeVisitor
18 
19 from robot.errors import DataError
20 from robot.output import LOGGER
21 from robot.parsing import get_model, get_resource_model, get_init_model, Token
22 from robot.utils import FileReader, read_rest_data
23 
24 from .settings import Defaults
25 from .transformers import SuiteBuilder, SettingsBuilder, ResourceBuilder
26 from ..model import TestSuite, ResourceFile
27 
28 
29 class BaseParser:
30 
31  def parse_init_file(self, source, defaults=None):
32  raise NotImplementedError
33 
34  def parse_suite_file(self, source, defaults=None):
35  raise NotImplementedError
36 
37  def parse_resource_file(self, source):
38  raise NotImplementedError
39 
40 
42 
43  def __init__(self, lang=None, process_curdir=True):
44  self.langlang = lang
45  self.process_curdirprocess_curdir = process_curdir
46 
47  def parse_init_file(self, source, defaults=None):
48  directory = os.path.dirname(source)
49  suite = TestSuite(name=format_name(directory), source=directory)
50  return self._build_build(suite, source, defaults, get_model=get_init_model)
51 
52  def parse_suite_file(self, source, defaults=None):
53  suite = TestSuite(name=format_name(source), source=source)
54  return self._build_build(suite, source, defaults)
55 
56  def build_suite(self, model, name=None, defaults=None):
57  source = model.source
58  suite = TestSuite(name=name or format_name(source), source=source)
59  return self._build_build(suite, source, defaults, model)
60 
61  def _build(self, suite, source, defaults, model=None, get_model=get_model):
62  if defaults is None:
63  defaults = Defaults()
64  if model is None:
65  model = get_model(self._get_source_get_source(source), data_only=True,
66  curdir=self._get_curdir_get_curdir(source), lang=self.langlang)
67  ErrorReporter(source).visit(model)
68  SettingsBuilder(suite, defaults).visit(model)
69  SuiteBuilder(suite, defaults).visit(model)
70  suite.rpa = self._get_rpa_mode_get_rpa_mode(model)
71  return suite
72 
73  def _get_curdir(self, source):
74  if not self.process_curdirprocess_curdir:
75  return None
76  return os.path.dirname(source).replace('\\', '\\\\')
77 
78  def _get_source(self, source):
79  return source
80 
81  def parse_resource_file(self, source):
82  model = get_resource_model(self._get_source_get_source(source), data_only=True,
83  curdir=self._get_curdir_get_curdir(source), lang=self.langlang)
84  resource = ResourceFile(source=source)
85  ErrorReporter(source).visit(model)
86  ResourceBuilder(resource).visit(model)
87  return resource
88 
89  def _get_rpa_mode(self, data):
90  if not data:
91  return None
92  tasks = [s.tasks for s in data.sections if hasattr(s, 'tasks')]
93  if all(tasks) or not any(tasks):
94  return tasks[0] if tasks else None
95  raise DataError('One file cannot have both tests and tasks.')
96 
97 
99 
100  def _get_source(self, source):
101  with FileReader(source) as reader:
102  return read_rest_data(reader)
103 
104 
106 
107  def parse_init_file(self, source, defaults=None):
108  return TestSuite(name=format_name(source), source=source)
109 
110 
111 def format_name(source):
112  def strip_possible_prefix_from_name(name):
113  result = name.split('__', 1)[-1]
114  if result:
115  return result
116  return name
117 
118  def format_name(name):
119  name = strip_possible_prefix_from_name(name)
120  name = name.replace('_', ' ').strip()
121  return name.title() if name.islower() else name
122 
123  if source is None:
124  return None
125  if os.path.isdir(source):
126  basename = os.path.basename(source)
127  else:
128  basename = os.path.splitext(os.path.basename(source))[0]
129  return format_name(basename)
130 
131 
132 class ErrorReporter(NodeVisitor):
133 
134  def __init__(self, source):
135  self.sourcesource = source
136 
137  def visit_Error(self, node):
138  fatal = node.get_token(Token.FATAL_ERROR)
139  if fatal:
140  raise DataError(self._format_message_format_message(fatal))
141  for error in node.get_tokens(Token.ERROR):
142  LOGGER.error(self._format_message_format_message(error))
143 
144  def _format_message(self, token):
145  return f"Error in file '{self.source}' on line {token.lineno}: {token.error}"
def parse_suite_file(self, source, defaults=None)
Definition: parsers.py:34
def parse_resource_file(self, source)
Definition: parsers.py:37
def parse_init_file(self, source, defaults=None)
Definition: parsers.py:31
def parse_init_file(self, source, defaults=None)
Definition: parsers.py:107
def __init__(self, lang=None, process_curdir=True)
Definition: parsers.py:43
def parse_init_file(self, source, defaults=None)
Definition: parsers.py:47
def parse_suite_file(self, source, defaults=None)
Definition: parsers.py:52
def _build(self, suite, source, defaults, model=None, get_model=get_model)
Definition: parsers.py:61
def build_suite(self, model, name=None, defaults=None)
Definition: parsers.py:56
Represents a single executable test suite.
Definition: model.py:292
def get_model(source, data_only=False, curdir=None, lang=None)
Parses the given source to a model represented as an AST.
Definition: parser.py:49
def get_resource_model(source, data_only=False, curdir=None, lang=None)
Parses the given source to a resource file model.
Definition: parser.py:58
def read_rest_data(rstfile)
Definition: __init__.py:76