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 import json
17 import re
18 from itertools import chain
19 
20 from robot.model import Tags
21 from robot.running import ArgumentSpec
22 from robot.utils import getshortdoc, Sortable, setter
23 
24 from .htmlutils import DocFormatter, DocToHtml, HtmlToText
25 from .writer import LibdocWriter
26 from .output import LibdocOutput, get_generation_time
27 
28 
29 
30 class LibraryDoc:
31 
32  def __init__(self, name='', doc='', version='', type='LIBRARY', scope='TEST',
33  doc_format='ROBOT', source=None, lineno=-1):
34  self.namename = name
35  self._doc_doc = doc
36  self.versionversion = version
37  self.typetype = type
38  self.scopescope = scope
39  self.doc_formatdoc_formatdoc_format = doc_format
40  self.sourcesource = source
41  self.linenolineno = lineno
42  self.initsinitsinits = ()
43  self.keywordskeywordskeywords = ()
44  self.type_docstype_docstype_docs = ()
45 
46  @property
47  doc = property
48 
49  def doc(self):
50  if self.doc_formatdoc_formatdoc_format == 'ROBOT' and '%TOC%' in self._doc_doc:
51  return self._add_toc_add_toc(self._doc_doc)
52  return self._doc_doc
53 
54  def _add_toc(self, doc):
55  toc = self._create_toc_create_toc(doc)
56  return '\n'.join(line if line.strip() != '%TOC%' else toc
57  for line in doc.splitlines())
58 
59  def _create_toc(self, doc):
60  entries = re.findall(r'^\s*=\s+(.+?)\s+=\s*$', doc, flags=re.MULTILINE)
61  if self.initsinitsinits:
62  entries.append('Importing')
63  if self.keywordskeywordskeywords:
64  entries.append('Keywords')
65  return '\n'.join('- `%s`' % entry for entry in entries)
66 
67  @setter
68  def doc_format(self, format):
69  return format or 'ROBOT'
70 
71  @setter
72 
73  def inits(self, inits):
74  return self._process_keywords_process_keywords(inits)
75 
76  @setter
77 
78  def keywords(self, kws):
79  return self._process_keywords_process_keywords(kws)
80 
81  @setter
82  def type_docs(self, type_docs):
83  return set(type_docs)
84 
85  def _process_keywords(self, kws):
86  for keyword in kws:
87  keyword.parent = self
88  return sorted(kws)
89 
90  @property
91  all_tags = property
92 
93  def all_tags(self):
94  return Tags(chain.from_iterable(kw.tags for kw in self.keywordskeywordskeywords))
95 
96  def save(self, output=None, format='HTML', theme=None):
97  with LibdocOutput(output, format) as outfile:
98  LibdocWriter(format, theme).write(self, outfile)
99 
101  formatter = DocFormatter(self.keywordskeywordskeywords, self.type_docstype_docstype_docs, self.docdocdoc, self.doc_formatdoc_formatdoc_format)
102  self._doc_doc = formatter.html(self.docdocdoc, intro=True)
103  for item in self.initsinitsinits + self.keywordskeywordskeywords:
104  # If 'shortdoc' is not set, it is generated automatically based on 'doc'
105  # when accessed. Generate and set it to avoid HTML format affecting it.
106  item.shortdoc = item.shortdoc
107  item.doc = formatter.html(item.doc)
108  for type_doc in self.type_docstype_docstype_docs:
109  # Standard docs are always in ROBOT format ...
110  if type_doc.type == type_doc.STANDARD:
111  # ... unless they have been converted to HTML already.
112  if not type_doc.doc.startswith('<p>'):
113  type_doc.doc = DocToHtml('ROBOT')(type_doc.doc)
114  else:
115  type_doc.doc = formatter.html(type_doc.doc)
116  self.doc_formatdoc_formatdoc_format = 'HTML'
117 
118  def to_dictionary(self, include_private=False, theme=None):
119  data = {
120  'specversion': 1,
121  'name': self.namename,
122  'doc': self.docdocdoc,
123  'version': self.versionversion,
124  'generated': get_generation_time(),
125  'type': self.typetype,
126  'scope': self.scopescope,
127  'docFormat': self.doc_formatdoc_formatdoc_format,
128  'source': self.sourcesource,
129  'lineno': self.linenolineno,
130  'tags': list(self.all_tagsall_tagsall_tags),
131  'inits': [init.to_dictionary() for init in self.initsinitsinits],
132  'keywords': [kw.to_dictionary() for kw in self.keywordskeywordskeywords
133  if include_private or not kw.private],
134  # 'dataTypes' was deprecated in RF 5, 'typedoc' should be used instead.
135  'dataTypes': self._get_data_types_get_data_types(self.type_docstype_docstype_docs),
136  'typedocs': [t.to_dictionary() for t in sorted(self.type_docstype_docstype_docs)]
137  }
138  if theme:
139  data['theme'] = theme.lower()
140  return data
141 
142  def _get_data_types(self, types):
143  enums = sorted(t for t in types if t.type == 'Enum')
144  typed_dicts = sorted(t for t in types if t.type == 'TypedDict')
145  return {
146  'enums': [t.to_dictionary(legacy=True) for t in enums],
147  'typedDicts': [t.to_dictionary(legacy=True) for t in typed_dicts]
148  }
149 
150  def to_json(self, indent=None, include_private=True, theme=None):
151  data = self.to_dictionaryto_dictionary(include_private, theme)
152  return json.dumps(data, indent=indent)
153 
154 
155 
156 class KeywordDoc(Sortable):
157 
158  def __init__(self, name='', args=None, doc='', shortdoc='', tags=(), private=False,
159  deprecated=False, source=None, lineno=-1, parent=None):
160  self.namename = name
161  self.argsargs = args or ArgumentSpec()
162  self.docdoc = doc
163  self._shortdoc_shortdoc = shortdoc
164  self.tagstags = Tags(tags)
165  self.privateprivate = private
166  self.deprecateddeprecated = deprecated
167  self.sourcesource = source
168  self.linenolineno = lineno
169  self.parentparent = parent
170  # Map argument types to type documentations.
171  self.type_docstype_docs = {arg.name: {} for arg in self.argsargs}
172 
173  @property
174  shortdoc = property
175 
176  def shortdoc(self):
177  return self._shortdoc_shortdoc or self._doc_to_shortdoc_doc_to_shortdoc()
178 
179  def _doc_to_shortdoc(self):
180  if self.parentparent and self.parentparent.doc_format == 'HTML':
181  doc = HtmlToText().get_shortdoc_from_html(self.docdoc)
182  else:
183  doc = self.docdoc
184  return ' '.join(getshortdoc(doc).splitlines())
185 
186  @shortdoc.setter
187 
188  def shortdoc(self, shortdoc):
189  self._shortdoc_shortdoc = shortdoc
190 
191  @property
192  _sort_key = property
193 
194  def _sort_key(self):
195  return self.namename.lower()
196 
197  def to_dictionary(self):
198  data = {
199  'name': self.namename,
200  'args': [self._arg_to_dict_arg_to_dict(arg) for arg in self.argsargs],
201  'doc': self.docdoc,
202  'shortdoc': self.shortdocshortdocshortdocshortdoc,
203  'tags': list(self.tagstags),
204  'source': self.sourcesource,
205  'lineno': self.linenolineno
206  }
207  if self.privateprivate:
208  data['private'] = True
209  if self.deprecateddeprecated:
210  data['deprecated'] = True
211  return data
212 
213  def _arg_to_dict(self, arg):
214  return {
215  'name': arg.name,
216  'types': arg.types_reprs,
217  'typedocs': self.type_docstype_docs.get(arg.name, {}),
218  'defaultValue': arg.default_repr,
219  'kind': arg.kind,
220  'required': arg.required,
221  'repr': str(arg)
222  }
Documentation for a single keyword or an initializer.
Definition: model.py:156
def _arg_to_dict(self, arg)
Definition: model.py:213
def shortdoc(self, shortdoc)
Definition: model.py:188
def __init__(self, name='', args=None, doc='', shortdoc='', tags=(), private=False, deprecated=False, source=None, lineno=-1, parent=None)
Definition: model.py:159
Documentation for a library, a resource file or a suite file.
Definition: model.py:30
def inits(self, inits)
Initializer docs as :class:~KeywordDoc instances.
Definition: model.py:73
def doc_format(self, format)
Definition: model.py:68
def _get_data_types(self, types)
Definition: model.py:142
def _process_keywords(self, kws)
Definition: model.py:85
def to_dictionary(self, include_private=False, theme=None)
Definition: model.py:118
def type_docs(self, type_docs)
Definition: model.py:82
def _add_toc(self, doc)
Definition: model.py:54
def _create_toc(self, doc)
Definition: model.py:59
def keywords(self, kws)
Keyword docs as :class:~KeywordDoc instances.
Definition: model.py:78
def __init__(self, name='', doc='', version='', type='LIBRARY', scope='TEST', doc_format='ROBOT', source=None, lineno=-1)
Definition: model.py:33
def save(self, output=None, format='HTML', theme=None)
Definition: model.py:96
def to_json(self, indent=None, include_private=True, theme=None)
Definition: model.py:150
def write(msg, level='INFO', html=False)
Writes the message to the log file using the given level.
Definition: logger.py:84
def get_generation_time()
Return a timestamp that honors SOURCE_DATE_EPOCH.
Definition: output.py:52
def LibdocWriter(format=None, theme=None)
Definition: writer.py:23
def getshortdoc(doc_or_item, linesep='\n')
Definition: text.py:184