Robot Framework
robotbuilder.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 import sys
18 import re
19 
20 from robot.errors import DataError
21 from robot.running import (ResourceFileBuilder, TestLibrary, TestSuiteBuilder,
22  UserLibrary, UserErrorHandler)
23 from robot.utils import is_string, split_tags_from_doc, type_repr, unescape
24 from robot.variables import search_variable
25 
26 from .datatypes import TypeDoc
27 from .model import LibraryDoc, KeywordDoc
28 
29 
31 
34  _argument_separator = '::'
35 
36  def build(self, library):
37  name, args = self._split_library_name_and_args_split_library_name_and_args(library)
38  lib = TestLibrary(name, args)
39  libdoc = LibraryDoc(name=lib.name,
40  doc=self._get_doc_get_doc(lib),
41  version=lib.version,
42  scope=str(lib.scope),
43  doc_format=lib.doc_format,
44  source=lib.source,
45  lineno=lib.lineno)
46  libdoc.inits = self._get_initializers_get_initializers(lib)
47  libdoc.keywords = KeywordDocBuilder().build_keywords(lib)
48  libdoc.type_docs = self._get_type_docs_get_type_docs(libdoc.inits + libdoc.keywords,
49  lib.converters)
50  return libdoc
51 
52  def _split_library_name_and_args(self, library):
53  args = library.split(self._argument_separator_argument_separator)
54  name = args.pop(0)
55  return self._normalize_library_path_normalize_library_path(name), args
56 
57  def _normalize_library_path(self, library):
58  path = library.replace('/', os.sep)
59  if os.path.exists(path):
60  return os.path.abspath(path)
61  return library
62 
63  def _get_doc(self, lib):
64  return lib.doc or f"Documentation for library ``{lib.name}``."
65 
66  def _get_initializers(self, lib):
67  if lib.init.arguments.maxargs:
68  return [KeywordDocBuilder().build_keyword(lib.init)]
69  return []
70 
71  def _get_type_docs(self, keywords, custom_converters):
72  type_docs = {}
73  for kw in keywords:
74  for arg in kw.args:
75  kw.type_docs[arg.name] = {}
76  for typ in arg.types:
77  type_doc = TypeDoc.for_type(typ, custom_converters)
78  if type_doc:
79  kw.type_docs[arg.name][type_repr(typ)] = type_doc.name
80  type_docs.setdefault(type_doc, set()).add(kw.name)
81  for type_doc, usages in type_docs.items():
82  type_doc.usages = sorted(usages, key=str.lower)
83  return set(type_docs)
84 
85 
87  type = 'RESOURCE'
88 
89  def build(self, path):
90  path = self._find_resource_file_find_resource_file(path)
91  res, name = self._import_resource_import_resource(path)
92  libdoc = LibraryDoc(name=name,
93  doc=self._get_doc_get_doc(res, name),
94  type=self.typetype,
95  scope='GLOBAL',
96  source=res.source,
97  lineno=1)
98  libdoc.keywords = KeywordDocBuilder(resource=True).build_keywords(res)
99  return libdoc
100 
101  def _import_resource(self, path):
102  model = ResourceFileBuilder(process_curdir=False).build(path)
103  resource = UserLibrary(model)
104  return resource, resource.name
105 
106  def _find_resource_file(self, path):
107  if os.path.isfile(path):
108  return os.path.normpath(os.path.abspath(path))
109  for dire in [item for item in sys.path if os.path.isdir(item)]:
110  candidate = os.path.normpath(os.path.join(dire, path))
111  if os.path.isfile(candidate):
112  return os.path.abspath(candidate)
113  raise DataError(f"Resource file '{path}' does not exist.")
114 
115  def _get_doc(self, resource, name):
116  if resource.doc:
117  return unescape(resource.doc)
118  return f"Documentation for resource file ``{name}``."
119 
120 
122  type = 'SUITE'
123 
124  def _import_resource(self, path):
125  builder = TestSuiteBuilder(process_curdir=False)
126  if os.path.basename(path).lower() == '__init__.robot':
127  path = os.path.dirname(path)
128  builder.included_suites = ()
129  builder.allow_empty_suite = True
130  suite = builder.build(path)
131  return UserLibrary(suite.resource), suite.name
132 
133  def _get_doc(self, resource, name):
134  return f"Documentation for keywords in suite ``{name}``."
135 
136 
138 
139  def __init__(self, resource=False):
140  self._resource_resource = resource
141 
142  def build_keywords(self, lib):
143  return [self.build_keywordbuild_keyword(kw) for kw in lib.handlers]
144 
145  def build_keyword(self, kw):
146  doc, tags = self._get_doc_and_tags_get_doc_and_tags(kw)
147  if not self._resource_resource:
148  self._escape_strings_in_defaults_escape_strings_in_defaults(kw.arguments.defaults)
149  return KeywordDoc(name=kw.name,
150  args=kw.arguments,
151  doc=doc,
152  tags=tags,
153  private=tags.robot('private'),
154  deprecated=doc.startswith('*DEPRECATED') and '*' in doc[1:],
155  source=kw.source,
156  lineno=kw.lineno)
157 
158  def _escape_strings_in_defaults(self, defaults):
159  for name, value in defaults.items():
160  if is_string(value):
161  value = re.sub(r'[\\\r\n\t]', lambda x: repr(str(x.group()))[1:-1], value)
162  value = self._escape_variables_escape_variables(value)
163  defaults[name] = re.sub('^(?= )|(?<= )$|(?<= )(?= )', r'\\', value)
164 
165  def _escape_variables(self, value):
166  result = ''
167  match = search_variable(value)
168  while match:
169  result += r'%s\%s{%s}' % (match.before, match.identifier,
170  self._escape_variables_escape_variables(match.base))
171  for item in match.items:
172  result += '[%s]' % self._escape_variables_escape_variables(item)
173  match = search_variable(match.after)
174  return result + match.string
175 
176  def _get_doc_and_tags(self, kw):
177  doc = self._get_doc_get_doc(kw)
178  doc, tags = split_tags_from_doc(doc)
179  return doc, kw.tags + tags
180 
181  def _get_doc(self, kw):
182  if self._resource_resource and not isinstance(kw, UserErrorHandler):
183  return unescape(kw.doc)
184  return kw.doc
Documentation for a single keyword or an initializer.
Definition: model.py:156
Documentation for a library, a resource file or a suite file.
Definition: model.py:30
def _get_type_docs(self, keywords, custom_converters)
Definition: robotbuilder.py:71
def TestLibrary(name, args=None, variables=None, create_handlers=True, logger=LOGGER)
def type_repr(typ)
Return string representation for types.
Definition: robottypes.py:116
def split_tags_from_doc(doc)
Definition: text.py:167
def search_variable(string, identifiers='$@&% *', ignore_errors=False)
Definition: search.py:22