|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2003 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the builtin documentation generator. |
|
8 |
|
9 The different parts of the module document are assembled from the parsed |
|
10 Python file. The appearance is determined by several templates defined within |
|
11 this module. |
|
12 """ |
|
13 |
|
14 import sys |
|
15 import re |
|
16 import contextlib |
|
17 |
|
18 from Utilities import html_uencode |
|
19 from Utilities.ModuleParser import RB_SOURCE, Function |
|
20 |
|
21 _signal = re.compile( |
|
22 r""" |
|
23 ^@signal [ \t]+ |
|
24 (?P<SignalName1> |
|
25 [a-zA-Z_] \w* [ \t]* \( [^)]* \) |
|
26 ) |
|
27 [ \t]* (?P<SignalDescription1> .*) |
|
28 | |
|
29 ^@signal [ \t]+ |
|
30 (?P<SignalName2> |
|
31 [a-zA-Z_] \w* |
|
32 ) |
|
33 [ \t]+ (?P<SignalDescription2> .*) |
|
34 """, re.VERBOSE | re.DOTALL | re.MULTILINE).search |
|
35 |
|
36 _event = re.compile( |
|
37 r""" |
|
38 ^@event [ \t]+ |
|
39 (?P<EventName1> |
|
40 [a-zA-Z_] \w* [ \t]* \( [^)]* \) |
|
41 ) |
|
42 [ \t]* (?P<EventDescription1> .*) |
|
43 | |
|
44 ^@event [ \t]+ |
|
45 (?P<EventName2> |
|
46 [a-zA-Z_] \w* |
|
47 ) |
|
48 [ \t]+ (?P<EventDescription2> .*) |
|
49 """, re.VERBOSE | re.DOTALL | re.MULTILINE).search |
|
50 |
|
51 |
|
52 class TagError(Exception): |
|
53 """ |
|
54 Exception class raised, if an invalid documentation tag was found. |
|
55 """ |
|
56 pass |
|
57 |
|
58 |
|
59 class ModuleDocument: |
|
60 """ |
|
61 Class implementing the builtin documentation generator. |
|
62 """ |
|
63 def __init__(self, module, colors, stylesheet=None): |
|
64 """ |
|
65 Constructor |
|
66 |
|
67 @param module the information of the parsed Python file |
|
68 @param colors dictionary specifying the various colors for the output |
|
69 (dictionary of strings) |
|
70 @param stylesheet the style to be used for the generated pages (string) |
|
71 """ |
|
72 self.module = module |
|
73 self.empty = True |
|
74 |
|
75 self.stylesheet = stylesheet |
|
76 |
|
77 if self.stylesheet: |
|
78 from . import TemplatesListsStyleCSS |
|
79 self.headerTemplate = TemplatesListsStyleCSS.headerTemplate |
|
80 self.footerTemplate = TemplatesListsStyleCSS.footerTemplate |
|
81 self.moduleTemplate = TemplatesListsStyleCSS.moduleTemplate |
|
82 self.rbFileTemplate = TemplatesListsStyleCSS.rbFileTemplate |
|
83 self.classTemplate = TemplatesListsStyleCSS.classTemplate |
|
84 self.methodTemplate = TemplatesListsStyleCSS.methodTemplate |
|
85 self.constructorTemplate = ( |
|
86 TemplatesListsStyleCSS.constructorTemplate) |
|
87 self.rbModuleTemplate = TemplatesListsStyleCSS.rbModuleTemplate |
|
88 self.rbModulesClassTemplate = ( |
|
89 TemplatesListsStyleCSS.rbModulesClassTemplate) |
|
90 self.functionTemplate = TemplatesListsStyleCSS.functionTemplate |
|
91 self.listTemplate = TemplatesListsStyleCSS.listTemplate |
|
92 self.listEntryTemplate = TemplatesListsStyleCSS.listEntryTemplate |
|
93 self.listEntryNoneTemplate = ( |
|
94 TemplatesListsStyleCSS.listEntryNoneTemplate) |
|
95 self.listEntryDeprecatedTemplate = ( |
|
96 TemplatesListsStyleCSS.listEntryDeprecatedTemplate) |
|
97 self.listEntrySimpleTemplate = ( |
|
98 TemplatesListsStyleCSS.listEntrySimpleTemplate) |
|
99 self.paragraphTemplate = TemplatesListsStyleCSS.paragraphTemplate |
|
100 self.parametersListTemplate = ( |
|
101 TemplatesListsStyleCSS.parametersListTemplate) |
|
102 self.parameterTypesListEntryTemplate = ( |
|
103 TemplatesListsStyleCSS.parameterTypesListEntryTemplate) |
|
104 self.parametersListEntryTemplate = ( |
|
105 TemplatesListsStyleCSS.parametersListEntryTemplate) |
|
106 self.returnsTemplate = TemplatesListsStyleCSS.returnsTemplate |
|
107 self.returnTypesTemplate = ( |
|
108 TemplatesListsStyleCSS.returnTypesTemplate) |
|
109 self.yieldsTemplate = TemplatesListsStyleCSS.yieldsTemplate |
|
110 self.yieldTypesTemplate = ( |
|
111 TemplatesListsStyleCSS.yieldTypesTemplate) |
|
112 self.exceptionsListTemplate = ( |
|
113 TemplatesListsStyleCSS.exceptionsListTemplate) |
|
114 self.exceptionsListEntryTemplate = ( |
|
115 TemplatesListsStyleCSS.exceptionsListEntryTemplate) |
|
116 self.signalsListTemplate = ( |
|
117 TemplatesListsStyleCSS.signalsListTemplate) |
|
118 self.signalsListEntryTemplate = ( |
|
119 TemplatesListsStyleCSS.signalsListEntryTemplate) |
|
120 self.eventsListTemplate = TemplatesListsStyleCSS.eventsListTemplate |
|
121 self.eventsListEntryTemplate = ( |
|
122 TemplatesListsStyleCSS.eventsListEntryTemplate) |
|
123 self.deprecatedTemplate = TemplatesListsStyleCSS.deprecatedTemplate |
|
124 self.authorInfoTemplate = TemplatesListsStyleCSS.authorInfoTemplate |
|
125 self.seeListTemplate = TemplatesListsStyleCSS.seeListTemplate |
|
126 self.seeListEntryTemplate = ( |
|
127 TemplatesListsStyleCSS.seeListEntryTemplate) |
|
128 self.seeLinkTemplate = TemplatesListsStyleCSS.seeLinkTemplate |
|
129 self.sinceInfoTemplate = TemplatesListsStyleCSS.sinceInfoTemplate |
|
130 else: |
|
131 from . import TemplatesListsStyle |
|
132 self.headerTemplate = ( |
|
133 TemplatesListsStyle.headerTemplate.format(**colors)) |
|
134 self.footerTemplate = ( |
|
135 TemplatesListsStyle.footerTemplate.format(**colors)) |
|
136 self.moduleTemplate = ( |
|
137 TemplatesListsStyle.moduleTemplate.format(**colors)) |
|
138 self.rbFileTemplate = ( |
|
139 TemplatesListsStyle.rbFileTemplate.format(**colors)) |
|
140 self.classTemplate = ( |
|
141 TemplatesListsStyle.classTemplate.format(**colors)) |
|
142 self.methodTemplate = ( |
|
143 TemplatesListsStyle.methodTemplate.format(**colors)) |
|
144 self.constructorTemplate = ( |
|
145 TemplatesListsStyle.constructorTemplate.format(**colors)) |
|
146 self.rbModuleTemplate = ( |
|
147 TemplatesListsStyle.rbModuleTemplate.format(**colors)) |
|
148 self.rbModulesClassTemplate = ( |
|
149 TemplatesListsStyle.rbModulesClassTemplate.format(**colors)) |
|
150 self.functionTemplate = ( |
|
151 TemplatesListsStyle.functionTemplate.format(**colors)) |
|
152 self.listTemplate = ( |
|
153 TemplatesListsStyle.listTemplate.format(**colors)) |
|
154 self.listEntryTemplate = ( |
|
155 TemplatesListsStyle.listEntryTemplate.format(**colors)) |
|
156 self.listEntryNoneTemplate = ( |
|
157 TemplatesListsStyle.listEntryNoneTemplate.format(**colors)) |
|
158 self.listEntryDeprecatedTemplate = ( |
|
159 TemplatesListsStyle.listEntryDeprecatedTemplate.format( |
|
160 **colors)) |
|
161 self.listEntrySimpleTemplate = ( |
|
162 TemplatesListsStyle.listEntrySimpleTemplate.format(**colors)) |
|
163 self.paragraphTemplate = ( |
|
164 TemplatesListsStyle.paragraphTemplate.format(**colors)) |
|
165 self.parametersListTemplate = ( |
|
166 TemplatesListsStyle.parametersListTemplate.format(**colors)) |
|
167 self.parametersListEntryTemplate = ( |
|
168 TemplatesListsStyle.parametersListEntryTemplate.format( |
|
169 **colors)) |
|
170 self.parameterTypesListEntryTemplate = ( |
|
171 TemplatesListsStyle.parameterTypesListEntryTemplate.format( |
|
172 **colors)) |
|
173 self.returnsTemplate = ( |
|
174 TemplatesListsStyle.returnsTemplate.format(**colors)) |
|
175 self.returnTypesTemplate = ( |
|
176 TemplatesListsStyle.returnTypesTemplate.format(**colors)) |
|
177 self.yieldsTemplate = ( |
|
178 TemplatesListsStyle.yieldsTemplate.format(**colors)) |
|
179 self.yieldTypesTemplate = ( |
|
180 TemplatesListsStyle.yieldTypesTemplate.format(**colors)) |
|
181 self.exceptionsListTemplate = ( |
|
182 TemplatesListsStyle.exceptionsListTemplate.format(**colors)) |
|
183 self.exceptionsListEntryTemplate = ( |
|
184 TemplatesListsStyle.exceptionsListEntryTemplate.format( |
|
185 **colors)) |
|
186 self.signalsListTemplate = ( |
|
187 TemplatesListsStyle.signalsListTemplate.format(**colors)) |
|
188 self.signalsListEntryTemplate = ( |
|
189 TemplatesListsStyle.signalsListEntryTemplate.format(**colors)) |
|
190 self.eventsListTemplate = ( |
|
191 TemplatesListsStyle.eventsListTemplate.format(**colors)) |
|
192 self.eventsListEntryTemplate = ( |
|
193 TemplatesListsStyle.eventsListEntryTemplate.format(**colors)) |
|
194 self.deprecatedTemplate = ( |
|
195 TemplatesListsStyle.deprecatedTemplate.format(**colors)) |
|
196 self.authorInfoTemplate = ( |
|
197 TemplatesListsStyle.authorInfoTemplate.format(**colors)) |
|
198 self.seeListTemplate = ( |
|
199 TemplatesListsStyle.seeListTemplate.format(**colors)) |
|
200 self.seeListEntryTemplate = ( |
|
201 TemplatesListsStyle.seeListEntryTemplate.format(**colors)) |
|
202 self.seeLinkTemplate = ( |
|
203 TemplatesListsStyle.seeLinkTemplate.format(**colors)) |
|
204 self.sinceInfoTemplate = ( |
|
205 TemplatesListsStyle.sinceInfoTemplate.format(**colors)) |
|
206 |
|
207 self.keywords = [] |
|
208 # list of tuples containing the name (string) and |
|
209 # the ref (string). The ref is without the filename part. |
|
210 self.generated = False |
|
211 |
|
212 def isEmpty(self): |
|
213 """ |
|
214 Public method to determine, if the module contains any classes or |
|
215 functions. |
|
216 |
|
217 @return Flag indicating an empty module (i.e. __init__.py without |
|
218 any contents) |
|
219 """ |
|
220 return self.empty |
|
221 |
|
222 def name(self): |
|
223 """ |
|
224 Public method used to get the module name. |
|
225 |
|
226 @return The name of the module. (string) |
|
227 """ |
|
228 return self.module.name |
|
229 |
|
230 def description(self): |
|
231 """ |
|
232 Public method used to get the description of the module. |
|
233 |
|
234 @return The description of the module. (string) |
|
235 """ |
|
236 return self.__formatDescription(self.module.description) |
|
237 |
|
238 def shortDescription(self): |
|
239 """ |
|
240 Public method used to get the short description of the module. |
|
241 |
|
242 The short description is just the first line of the modules |
|
243 description. |
|
244 |
|
245 @return The short description of the module. (string) |
|
246 """ |
|
247 return self.__getShortDescription(self.module.description) |
|
248 |
|
249 def genDocument(self): |
|
250 """ |
|
251 Public method to generate the source code documentation. |
|
252 |
|
253 @return The source code documentation. (string) |
|
254 """ |
|
255 doc = ( |
|
256 self.headerTemplate.format( |
|
257 **{'Title': self.module.name, |
|
258 'Style': self.stylesheet} |
|
259 ) + |
|
260 self.__genModuleSection() + |
|
261 self.footerTemplate |
|
262 ) |
|
263 self.generated = True |
|
264 return doc |
|
265 |
|
266 def __genModuleSection(self): |
|
267 """ |
|
268 Private method to generate the body of the document. |
|
269 |
|
270 @return The body of the document. (string) |
|
271 """ |
|
272 globalsList = self.__genGlobalsListSection() |
|
273 classList = self.__genClassListSection() |
|
274 functionList = self.__genFunctionListSection() |
|
275 try: |
|
276 if self.module.type == RB_SOURCE: |
|
277 rbModulesList = self.__genRbModulesListSection() |
|
278 modBody = self.rbFileTemplate.format( |
|
279 **{'Module': self.module.name, |
|
280 'ModuleDescription': |
|
281 self.__formatDescription(self.module.description), |
|
282 'GlobalsList': globalsList, |
|
283 'ClassList': classList, |
|
284 'RbModulesList': rbModulesList, |
|
285 'FunctionList': functionList, |
|
286 }) |
|
287 else: |
|
288 modBody = self.moduleTemplate.format( |
|
289 **{'Module': self.module.name, |
|
290 'ModuleDescription': |
|
291 self.__formatDescription(self.module.description), |
|
292 'GlobalsList': globalsList, |
|
293 'ClassList': classList, |
|
294 'FunctionList': functionList, |
|
295 }) |
|
296 except TagError as e: |
|
297 sys.stderr.write( |
|
298 "Error processing {0}.\n".format(self.module.file)) |
|
299 sys.stderr.write( |
|
300 "Error in tags of description of module {0}.\n".format( |
|
301 self.module.name)) |
|
302 sys.stderr.write("{0}\n".format(e)) |
|
303 return "" |
|
304 |
|
305 classesSection = self.__genClassesSection() |
|
306 functionsSection = self.__genFunctionsSection() |
|
307 rbModulesSection = ( |
|
308 self.__genRbModulesSection() |
|
309 if self.module.type == RB_SOURCE else |
|
310 "" |
|
311 ) |
|
312 return "{0}{1}{2}{3}".format( |
|
313 modBody, classesSection, rbModulesSection, functionsSection) |
|
314 |
|
315 def __genListSection(self, names, sectionDict, kwSuffix=""): |
|
316 """ |
|
317 Private method to generate a list section of the document. |
|
318 |
|
319 @param names The names to appear in the list. (list of strings) |
|
320 @param sectionDict dictionary containing all relevant information |
|
321 (dict) |
|
322 @param kwSuffix suffix to be used for the QtHelp keywords (string) |
|
323 @return list section (string) |
|
324 """ |
|
325 lst = [] |
|
326 for name in names: |
|
327 lst.append(self.listEntryTemplate.format( |
|
328 **{'Link': "{0}".format(name), |
|
329 'Name': sectionDict[name].name, |
|
330 'Description': |
|
331 self.__getShortDescription(sectionDict[name].description), |
|
332 'Deprecated': |
|
333 self.__checkDeprecated(sectionDict[name].description) and |
|
334 self.listEntryDeprecatedTemplate or "", |
|
335 })) |
|
336 n = ("{0} ({1})".format(name, kwSuffix) if kwSuffix |
|
337 else "{0}".format(name)) |
|
338 self.keywords.append((n, "#{0}".format(name))) |
|
339 return ''.join(lst) |
|
340 |
|
341 def __genGlobalsListSection(self, class_=None): |
|
342 """ |
|
343 Private method to generate the section listing all global attributes of |
|
344 the module. |
|
345 |
|
346 @param class_ reference to a class object (Class) |
|
347 @return The globals list section. (string) |
|
348 """ |
|
349 attrNames = [] |
|
350 scope = class_ if class_ is not None else self.module |
|
351 attrNames = sorted(attr for attr in scope.globals.keys() |
|
352 if not scope.globals[attr].isSignal) |
|
353 s = ( |
|
354 ''.join( |
|
355 [self.listEntrySimpleTemplate.format(**{'Name': name}) |
|
356 for name in attrNames]) |
|
357 if attrNames else |
|
358 self.listEntryNoneTemplate |
|
359 ) |
|
360 return self.listTemplate.format(**{'Entries': s}) |
|
361 |
|
362 def __genClassListSection(self): |
|
363 """ |
|
364 Private method to generate the section listing all classes of the |
|
365 module. |
|
366 |
|
367 @return The classes list section. (string) |
|
368 """ |
|
369 names = sorted(list(self.module.classes.keys())) |
|
370 if names: |
|
371 self.empty = False |
|
372 s = self.__genListSection(names, self.module.classes) |
|
373 else: |
|
374 s = self.listEntryNoneTemplate |
|
375 return self.listTemplate.format(**{'Entries': s}) |
|
376 |
|
377 def __genRbModulesListSection(self): |
|
378 """ |
|
379 Private method to generate the section listing all modules of the file |
|
380 (Ruby only). |
|
381 |
|
382 @return The modules list section. (string) |
|
383 """ |
|
384 names = sorted(list(self.module.modules.keys())) |
|
385 if names: |
|
386 self.empty = False |
|
387 s = self.__genListSection(names, self.module.modules) |
|
388 else: |
|
389 s = self.listEntryNoneTemplate |
|
390 return self.listTemplate.format(**{'Entries': s}) |
|
391 |
|
392 def __genFunctionListSection(self): |
|
393 """ |
|
394 Private method to generate the section listing all functions of the |
|
395 module. |
|
396 |
|
397 @return The functions list section. (string) |
|
398 """ |
|
399 names = sorted(list(self.module.functions.keys())) |
|
400 if names: |
|
401 self.empty = False |
|
402 s = self.__genListSection(names, self.module.functions) |
|
403 else: |
|
404 s = self.listEntryNoneTemplate |
|
405 return self.listTemplate.format(**{'Entries': s}) |
|
406 |
|
407 def __genClassesSection(self): |
|
408 """ |
|
409 Private method to generate the document section with details about |
|
410 classes. |
|
411 |
|
412 @return The classes details section. (string) |
|
413 """ |
|
414 classNames = sorted(list(self.module.classes.keys())) |
|
415 classes = [] |
|
416 for className in classNames: |
|
417 _class = self.module.classes[className] |
|
418 supers = _class.super |
|
419 supers = ', '.join(supers) if len(supers) > 0 else "None" |
|
420 |
|
421 globalsList = self.__genGlobalsListSection(_class) |
|
422 classMethList, classMethBodies = self.__genMethodSection( |
|
423 _class, className, Function.Class) |
|
424 methList, methBodies = self.__genMethodSection( |
|
425 _class, className, Function.General) |
|
426 staticMethList, staticMethBodies = self.__genMethodSection( |
|
427 _class, className, Function.Static) |
|
428 |
|
429 try: |
|
430 clsBody = self.classTemplate.format( |
|
431 **{'Anchor': className, |
|
432 'Class': _class.name, |
|
433 'ClassSuper': supers, |
|
434 'ClassDescription': |
|
435 self.__formatDescription(_class.description), |
|
436 'GlobalsList': globalsList, |
|
437 'ClassMethodList': classMethList, |
|
438 'MethodList': methList, |
|
439 'StaticMethodList': staticMethList, |
|
440 'MethodDetails': |
|
441 classMethBodies + methBodies + staticMethBodies, |
|
442 }) |
|
443 except TagError as e: |
|
444 sys.stderr.write( |
|
445 "Error processing {0}.\n".format(self.module.file)) |
|
446 sys.stderr.write( |
|
447 "Error in tags of description of class {0}.\n".format( |
|
448 className)) |
|
449 sys.stderr.write("{0}\n".format(e)) |
|
450 clsBody = "" |
|
451 |
|
452 classes.append(clsBody) |
|
453 |
|
454 return ''.join(classes) |
|
455 |
|
456 def __genMethodsListSection(self, names, sectionDict, className, clsName, |
|
457 includeInit=True): |
|
458 """ |
|
459 Private method to generate the methods list section of a class. |
|
460 |
|
461 @param names names to appear in the list (list of strings) |
|
462 @param sectionDict dictionary containing all relevant information |
|
463 (dict) |
|
464 @param className class name containing the names |
|
465 @param clsName visible class name containing the names |
|
466 @param includeInit flag indicating to include the __init__ method |
|
467 (boolean) |
|
468 @return methods list section (string) |
|
469 """ |
|
470 lst = [] |
|
471 if includeInit: |
|
472 with contextlib.suppress(KeyError): |
|
473 lst.append(self.listEntryTemplate.format( |
|
474 **{'Link': "{0}.{1}".format(className, '__init__'), |
|
475 'Name': clsName, |
|
476 'Description': self.__getShortDescription( |
|
477 sectionDict['__init__'].description), |
|
478 'Deprecated': self.__checkDeprecated( |
|
479 sectionDict['__init__'].description) and |
|
480 self.listEntryDeprecatedTemplate or "", |
|
481 })) |
|
482 self.keywords.append( |
|
483 ("{0} (Constructor)".format(className), |
|
484 "#{0}.{1}".format(className, '__init__'))) |
|
485 |
|
486 for name in names: |
|
487 lst.append(self.listEntryTemplate.format( |
|
488 **{'Link': "{0}.{1}".format(className, name), |
|
489 'Name': sectionDict[name].name, |
|
490 'Description': |
|
491 self.__getShortDescription(sectionDict[name].description), |
|
492 'Deprecated': |
|
493 self.__checkDeprecated(sectionDict[name].description) and |
|
494 self.listEntryDeprecatedTemplate or "", |
|
495 })) |
|
496 self.keywords.append(("{0}.{1}".format(className, name), |
|
497 "#{0}.{1}".format(className, name))) |
|
498 return ''.join(lst) |
|
499 |
|
500 def __genMethodSection(self, obj, className, modifierFilter): |
|
501 """ |
|
502 Private method to generate the method details section. |
|
503 |
|
504 @param obj reference to the object being formatted |
|
505 @param className name of the class containing the method (string) |
|
506 @param modifierFilter filter value designating the method types |
|
507 @return method list and method details section (tuple of two string) |
|
508 """ |
|
509 methList = [] |
|
510 methBodies = [] |
|
511 methods = sorted(k for k in obj.methods.keys() |
|
512 if obj.methods[k].modifier == modifierFilter) |
|
513 if '__init__' in methods: |
|
514 methods.remove('__init__') |
|
515 try: |
|
516 methBody = self.constructorTemplate.format( |
|
517 **{'Anchor': className, |
|
518 'Class': obj.name, |
|
519 'Method': '__init__', |
|
520 'MethodDescription': |
|
521 self.__formatDescription( |
|
522 obj.methods['__init__'].description), |
|
523 'Params': |
|
524 ', '.join(obj.methods['__init__'].parameters[1:]), |
|
525 }) |
|
526 except TagError as e: |
|
527 sys.stderr.write( |
|
528 "Error processing {0}.\n".format(self.module.file)) |
|
529 sys.stderr.write( |
|
530 "Error in tags of description of method {0}.{1}.\n".format( |
|
531 className, '__init__')) |
|
532 sys.stderr.write("{0}\n".format(e)) |
|
533 methBody = "" |
|
534 methBodies.append(methBody) |
|
535 |
|
536 if modifierFilter == Function.Class: |
|
537 methodClassifier = " (class method)" |
|
538 elif modifierFilter == Function.Static: |
|
539 methodClassifier = " (static)" |
|
540 else: |
|
541 methodClassifier = "" |
|
542 for method in methods: |
|
543 try: |
|
544 methBody = self.methodTemplate.format( |
|
545 **{'Anchor': className, |
|
546 'Class': obj.name, |
|
547 'Method': obj.methods[method].name, |
|
548 'MethodClassifier': methodClassifier, |
|
549 'MethodDescription': |
|
550 self.__formatDescription( |
|
551 obj.methods[method].description), |
|
552 'Params': ', '.join(obj.methods[method].parameters[1:]), |
|
553 }) |
|
554 except TagError as e: |
|
555 sys.stderr.write( |
|
556 "Error processing {0}.\n".format(self.module.file)) |
|
557 sys.stderr.write( |
|
558 "Error in tags of description of method {0}.{1}.\n".format( |
|
559 className, method)) |
|
560 sys.stderr.write("{0}\n".format(e)) |
|
561 methBody = "" |
|
562 methBodies.append(methBody) |
|
563 |
|
564 methList = self.__genMethodsListSection( |
|
565 methods, obj.methods, className, obj.name, |
|
566 includeInit=modifierFilter == Function.General) |
|
567 |
|
568 if not methList: |
|
569 methList = self.listEntryNoneTemplate |
|
570 return (self.listTemplate.format(**{'Entries': methList}), |
|
571 ''.join(methBodies)) |
|
572 |
|
573 def __genRbModulesSection(self): |
|
574 """ |
|
575 Private method to generate the document section with details about |
|
576 Ruby modules. |
|
577 |
|
578 @return The Ruby modules details section. (string) |
|
579 """ |
|
580 rbModulesNames = sorted(list(self.module.modules.keys())) |
|
581 rbModules = [] |
|
582 for rbModuleName in rbModulesNames: |
|
583 rbModule = self.module.modules[rbModuleName] |
|
584 globalsList = self.__genGlobalsListSection(rbModule) |
|
585 methList, methBodies = self.__genMethodSection( |
|
586 rbModule, rbModuleName, Function.General) |
|
587 classList, classBodies = self.__genRbModulesClassesSection( |
|
588 rbModule, rbModuleName) |
|
589 |
|
590 try: |
|
591 rbmBody = self.rbModuleTemplate.format( |
|
592 **{'Anchor': rbModuleName, |
|
593 'Module': rbModule.name, |
|
594 'ModuleDescription': |
|
595 self.__formatDescription(rbModule.description), |
|
596 'GlobalsList': globalsList, |
|
597 'ClassesList': classList, |
|
598 'ClassesDetails': classBodies, |
|
599 'FunctionsList': methList, |
|
600 'FunctionsDetails': methBodies, |
|
601 }) |
|
602 except TagError as e: |
|
603 sys.stderr.write( |
|
604 "Error processing {0}.\n".format(self.module.file)) |
|
605 sys.stderr.write( |
|
606 "Error in tags of description of Ruby module {0}.\n" |
|
607 .format(rbModuleName)) |
|
608 sys.stderr.write("{0}\n".format(e)) |
|
609 rbmBody = "" |
|
610 |
|
611 rbModules.append(rbmBody) |
|
612 |
|
613 return ''.join(rbModules) |
|
614 |
|
615 def __genRbModulesClassesSection(self, obj, modName): |
|
616 """ |
|
617 Private method to generate the Ruby module classes details section. |
|
618 |
|
619 @param obj Reference to the object being formatted. |
|
620 @param modName Name of the Ruby module containing the classes. (string) |
|
621 @return The classes list and classes details section. |
|
622 (tuple of two string) |
|
623 """ |
|
624 classNames = sorted(list(obj.classes.keys())) |
|
625 classes = [] |
|
626 for className in classNames: |
|
627 _class = obj.classes[className] |
|
628 supers = _class.super |
|
629 supers = ', '.join(supers) if len(supers) > 0 else "None" |
|
630 |
|
631 methList, methBodies = self.__genMethodSection( |
|
632 _class, className, Function.General) |
|
633 |
|
634 try: |
|
635 clsBody = self.rbModulesClassTemplate.format( |
|
636 **{'Anchor': className, |
|
637 'Class': _class.name, |
|
638 'ClassSuper': supers, |
|
639 'ClassDescription': |
|
640 self.__formatDescription(_class.description), |
|
641 'MethodList': methList, |
|
642 'MethodDetails': methBodies, |
|
643 }) |
|
644 except TagError as e: |
|
645 sys.stderr.write( |
|
646 "Error processing {0}.\n".format(self.module.file)) |
|
647 sys.stderr.write( |
|
648 "Error in tags of description of class {0}.\n".format( |
|
649 className)) |
|
650 sys.stderr.write("{0}\n".format(e)) |
|
651 clsBody = "" |
|
652 |
|
653 classes.append(clsBody) |
|
654 |
|
655 classesList = self.__genRbModulesClassesListSection( |
|
656 classNames, obj.classes, modName) |
|
657 |
|
658 if not classesList: |
|
659 classesList = self.listEntryNoneTemplate |
|
660 return (self.listTemplate.format(**{'Entries': classesList}), |
|
661 ''.join(classes)) |
|
662 |
|
663 def __genRbModulesClassesListSection(self, names, sectionDict, moduleName): |
|
664 """ |
|
665 Private method to generate the classes list section of a Ruby module. |
|
666 |
|
667 @param names The names to appear in the list. (list of strings) |
|
668 @param sectionDict dictionary containing all relevant information |
|
669 (dict) |
|
670 @param moduleName name of the Ruby module containing the classes |
|
671 (string) |
|
672 @return The list section. (string) |
|
673 """ |
|
674 lst = [] |
|
675 for name in names: |
|
676 lst.append(self.listEntryTemplate.format( |
|
677 **{'Link': "{0}.{1}".format(moduleName, name), |
|
678 'Name': sectionDict[name].name, |
|
679 'Description': |
|
680 self.__getShortDescription(sectionDict[name].description), |
|
681 'Deprecated': |
|
682 self.__checkDeprecated(sectionDict[name].description) and |
|
683 self.listEntryDeprecatedTemplate or "", |
|
684 })) |
|
685 self.keywords.append(("{0}.{1}".format(moduleName, name), |
|
686 "#{0}.{1}".format(moduleName, name))) |
|
687 return ''.join(lst) |
|
688 |
|
689 def __genFunctionsSection(self): |
|
690 """ |
|
691 Private method to generate the document section with details about |
|
692 functions. |
|
693 |
|
694 @return The functions details section. (string) |
|
695 """ |
|
696 funcBodies = [] |
|
697 funcNames = sorted(list(self.module.functions.keys())) |
|
698 for funcName in funcNames: |
|
699 try: |
|
700 funcBody = self.functionTemplate.format( |
|
701 **{'Anchor': funcName, |
|
702 'Function': self.module.functions[funcName].name, |
|
703 'FunctionDescription': self.__formatDescription( |
|
704 self.module.functions[funcName].description), |
|
705 'Params': |
|
706 ', '.join(self.module.functions[funcName].parameters), |
|
707 }) |
|
708 except TagError as e: |
|
709 sys.stderr.write( |
|
710 "Error processing {0}.\n".format(self.module.file)) |
|
711 sys.stderr.write( |
|
712 "Error in tags of description of function {0}.\n".format( |
|
713 funcName)) |
|
714 sys.stderr.write("{0}\n".format(e)) |
|
715 funcBody = "" |
|
716 |
|
717 funcBodies.append(funcBody) |
|
718 |
|
719 return ''.join(funcBodies) |
|
720 |
|
721 def __getShortDescription(self, desc): |
|
722 """ |
|
723 Private method to determine the short description of an object. |
|
724 |
|
725 The short description is just the first non empty line of the |
|
726 documentation string. |
|
727 |
|
728 @param desc The documentation string. (string) |
|
729 @return The short description. (string) |
|
730 """ |
|
731 dlist = desc.splitlines() |
|
732 sdlist = [] |
|
733 descfound = 0 |
|
734 for desc in dlist: |
|
735 desc = desc.strip() |
|
736 if desc: |
|
737 descfound = 1 |
|
738 dotpos = desc.find('.') |
|
739 if dotpos == -1: |
|
740 sdlist.append(desc.strip()) |
|
741 else: |
|
742 while ( |
|
743 dotpos + 1 < len(desc) and |
|
744 not desc[dotpos + 1].isspace() |
|
745 ): |
|
746 # don't recognize '.' inside a number or word as |
|
747 # stop condition |
|
748 dotpos = desc.find('.', dotpos + 1) |
|
749 if dotpos == -1: |
|
750 break |
|
751 if dotpos == -1: |
|
752 sdlist.append(desc.strip()) |
|
753 else: |
|
754 sdlist.append(desc[:dotpos + 1].strip()) |
|
755 break # break if a '.' is found |
|
756 else: |
|
757 if descfound: |
|
758 break # break if an empty line is found |
|
759 if sdlist: |
|
760 return html_uencode(' '.join(sdlist)) |
|
761 else: |
|
762 return '' |
|
763 |
|
764 def __checkDeprecated(self, descr): |
|
765 """ |
|
766 Private method to check, if the object to be documented contains a |
|
767 deprecated flag. |
|
768 |
|
769 @param descr documentation string (string) |
|
770 @return flag indicating the deprecation status (boolean) |
|
771 """ |
|
772 dlist = descr.splitlines() |
|
773 for desc in dlist: |
|
774 desc = desc.strip() |
|
775 if desc.startswith("@deprecated"): |
|
776 return True |
|
777 return False |
|
778 |
|
779 def __genParagraphs(self, lines): |
|
780 """ |
|
781 Private method to assemble the descriptive paragraphs of a docstring. |
|
782 |
|
783 A paragraph is made up of a number of consecutive lines without |
|
784 an intermediate empty line. Empty lines are treated as a paragraph |
|
785 delimiter. |
|
786 |
|
787 @param lines A list of individual lines. (list of strings) |
|
788 @return Ready formatted paragraphs. (string) |
|
789 """ |
|
790 lst = [] |
|
791 linelist = [] |
|
792 for line in lines: |
|
793 if line.strip(): |
|
794 if line == '.': |
|
795 linelist.append("") |
|
796 else: |
|
797 linelist.append(html_uencode(line)) |
|
798 else: |
|
799 lst.append(self.paragraphTemplate.format( |
|
800 **{'Lines': '\n'.join(linelist)})) |
|
801 linelist = [] |
|
802 if linelist: |
|
803 lst.append(self.paragraphTemplate.format( |
|
804 **{'Lines': '\n'.join(linelist)})) |
|
805 return ''.join(lst) |
|
806 |
|
807 def __genDescriptionListSection(self, dictionary, template): |
|
808 """ |
|
809 Private method to generate the list section of a description. |
|
810 |
|
811 @param dictionary Dictionary containing the info for the |
|
812 list section. |
|
813 @param template The template to be used for the list. (string) |
|
814 @return The list section. (string) |
|
815 """ |
|
816 lst = [] |
|
817 keys = sorted(list(dictionary.keys())) |
|
818 for key in keys: |
|
819 lst.append(template.format( |
|
820 **{'Name': key, |
|
821 'Description': html_uencode('\n'.join(dictionary[key])), |
|
822 })) |
|
823 return ''.join(lst) |
|
824 |
|
825 def __genParamDescriptionListSection(self, _list): |
|
826 """ |
|
827 Private method to generate the list section of a description. |
|
828 |
|
829 @param _list list containing the info for the parameter description |
|
830 list section (list of lists with three elements) |
|
831 @return formatted list section (string) |
|
832 """ |
|
833 lst = [] |
|
834 for name, type_, lines in _list: |
|
835 if type_: |
|
836 lst.append(self.parameterTypesListEntryTemplate.format( |
|
837 **{'Name': name, |
|
838 'Type': type_, |
|
839 'Description': html_uencode('\n'.join(lines)), |
|
840 })) |
|
841 else: |
|
842 lst.append(self.parametersListEntryTemplate.format( |
|
843 **{'Name': name, |
|
844 'Description': html_uencode('\n'.join(lines)), |
|
845 })) |
|
846 return ''.join(lst) |
|
847 |
|
848 def __formatCrossReferenceEntry(self, entry): |
|
849 """ |
|
850 Private method to format a cross reference entry. |
|
851 |
|
852 This cross reference entry looks like "package.module#member label". |
|
853 |
|
854 @param entry the entry to be formatted (string) |
|
855 @return formatted entry (string) |
|
856 """ |
|
857 if entry.startswith('"'): |
|
858 return entry |
|
859 elif entry.startswith('<'): |
|
860 entry = entry[3:] |
|
861 else: |
|
862 try: |
|
863 reference, label = entry.split(None, 1) |
|
864 except ValueError: |
|
865 reference = entry |
|
866 label = entry |
|
867 try: |
|
868 path, anchor = reference.split('#', 1) |
|
869 except ValueError: |
|
870 path = reference |
|
871 anchor = '' |
|
872 reference = path and "{0}.html".format(path) or '' |
|
873 if anchor: |
|
874 reference = "{0}#{1}".format(reference, anchor) |
|
875 entry = 'href="{0}">{1}</a>'.format(reference, label) |
|
876 |
|
877 return self.seeLinkTemplate.format(**{'Link': entry}) |
|
878 |
|
879 def __genSeeListSection(self, _list, template): |
|
880 """ |
|
881 Private method to generate the "see also" list section of a |
|
882 description. |
|
883 |
|
884 @param _list List containing the info for the section. |
|
885 @param template The template to be used for the list. (string) |
|
886 @return The list section. (string) |
|
887 """ |
|
888 lst = [] |
|
889 for seeEntry in _list: |
|
890 seeEntryString = ''.join(seeEntry) |
|
891 lst.append(template.format( |
|
892 **{'Link': html_uencode(self.__formatCrossReferenceEntry( |
|
893 seeEntryString)), |
|
894 })) |
|
895 return '\n'.join(lst) |
|
896 |
|
897 def __processInlineTags(self, desc): |
|
898 """ |
|
899 Private method to process inline tags. |
|
900 |
|
901 @param desc One line of the description (string) |
|
902 @return processed line with inline tags expanded (string) |
|
903 @exception TagError raised to indicate an invalid tag |
|
904 """ |
|
905 start = desc.find('{@') |
|
906 while start != -1: |
|
907 stop = desc.find('}', start + 2) |
|
908 if stop == -1: |
|
909 raise TagError("Unterminated inline tag.\n{0}".format(desc)) |
|
910 |
|
911 tagText = desc[start + 1:stop] |
|
912 if tagText.startswith('@link'): |
|
913 parts = tagText.split(None, 1) |
|
914 if len(parts) < 2: |
|
915 raise TagError( |
|
916 "Wrong format in inline tag {0}.\n{1}".format( |
|
917 parts[0], desc)) |
|
918 |
|
919 formattedTag = self.__formatCrossReferenceEntry(parts[1]) |
|
920 desc = desc.replace("{{{0}}}".format(tagText), formattedTag) |
|
921 else: |
|
922 tag = tagText.split(None, 1)[0] |
|
923 raise TagError( |
|
924 "Unknown inline tag encountered, {0}.\n{1}".format( |
|
925 tag, desc)) |
|
926 |
|
927 start = desc.find('{@') |
|
928 |
|
929 return desc |
|
930 |
|
931 def __formatDescription(self, descr): |
|
932 """ |
|
933 Private method to format the contents of the documentation string. |
|
934 |
|
935 @param descr The contents of the documentation string. (string) |
|
936 @exception TagError A tag doesn't have the correct number |
|
937 of arguments. |
|
938 @return The formatted contents of the documentation string. (string) |
|
939 """ |
|
940 if not descr: |
|
941 return "" |
|
942 |
|
943 paragraphs = [] |
|
944 paramList = [] |
|
945 returns = [] |
|
946 returnTypes = [] |
|
947 yields = [] |
|
948 yieldTypes = [] |
|
949 exceptionDict = {} |
|
950 signalDict = {} |
|
951 eventDict = {} |
|
952 deprecated = [] |
|
953 authorInfo = [] |
|
954 sinceInfo = [] |
|
955 seeList = [] |
|
956 lastItem = paragraphs |
|
957 inTagSection = False |
|
958 |
|
959 dlist = descr.splitlines() |
|
960 while dlist and not dlist[0]: |
|
961 del dlist[0] |
|
962 lastTag = "" |
|
963 buffer = "" |
|
964 for ditem in dlist: |
|
965 ditem = self.__processInlineTags(ditem) |
|
966 desc = ditem.strip() |
|
967 if buffer: |
|
968 if desc.startswith("@"): |
|
969 buffer = "" |
|
970 raise TagError( |
|
971 "Wrong format in {0} line.\n".format(lastTag)) |
|
972 else: |
|
973 desc = buffer + desc |
|
974 if desc: |
|
975 if desc.startswith(("@param", "@keyparam")): |
|
976 inTagSection = True |
|
977 parts = desc.split(None, 2) |
|
978 lastTag = parts[0] |
|
979 if len(parts) < 2: |
|
980 raise TagError( |
|
981 "Wrong format in {0} line.\n".format(parts[0])) |
|
982 paramName = parts[1] |
|
983 if parts[0] == "@keyparam": |
|
984 paramName += '=' |
|
985 try: |
|
986 paramList.append([paramName, "", [parts[2]]]) |
|
987 except IndexError: |
|
988 paramList.append([paramName, "", []]) |
|
989 lastItem = paramList[-1][2] |
|
990 elif desc.startswith("@type"): |
|
991 parts = desc.split(None, 1) |
|
992 if lastTag not in ["@param", "@keyparam"]: |
|
993 raise TagError( |
|
994 "{0} line must be preceded by a parameter line\n" |
|
995 .format(parts[0])) |
|
996 inTagSection = True |
|
997 lastTag = parts[0] |
|
998 if len(parts) < 2: |
|
999 raise TagError( |
|
1000 "Wrong format in {0} line.\n".format(parts[0])) |
|
1001 paramList[-1][1] = parts[1] |
|
1002 elif desc.startswith("@ptype"): |
|
1003 inTagSection = True |
|
1004 parts = desc.split(None, 2) |
|
1005 lastTag = parts[0] |
|
1006 if len(parts) < 3: |
|
1007 raise TagError( |
|
1008 "Wrong format in {0} line.\n".format(parts[0])) |
|
1009 param, type_ = parts[1:] |
|
1010 for index in range(len(paramList)): |
|
1011 if paramList[index][0] == param: |
|
1012 paramList[index][1] = type_ |
|
1013 break |
|
1014 else: |
|
1015 raise TagError( |
|
1016 "Unknow parameter name '{0}' in {1} line.\n" |
|
1017 .format(param, parts[0])) |
|
1018 elif desc.startswith(("@return", "@ireturn")): |
|
1019 inTagSection = True |
|
1020 parts = desc.split(None, 1) |
|
1021 lastTag = parts[0] |
|
1022 if len(parts) < 2: |
|
1023 raise TagError( |
|
1024 "Wrong format in {0} line.\n".format(parts[0])) |
|
1025 returns = [parts[1]] |
|
1026 lastItem = returns |
|
1027 elif desc.startswith("@rtype"): |
|
1028 parts = desc.split(None, 1) |
|
1029 if lastTag not in ["@return", "@ireturn"]: |
|
1030 raise TagError( |
|
1031 "{0} line must be preceded by a @return line\n" |
|
1032 .format(parts[0])) |
|
1033 inTagSection = True |
|
1034 lastTag = parts[0] |
|
1035 if len(parts) < 2: |
|
1036 raise TagError( |
|
1037 "Wrong format in {0} line.\n".format(parts[0])) |
|
1038 returnTypes = [parts[1]] |
|
1039 lastItem = returnTypes |
|
1040 elif desc.startswith("@yield"): |
|
1041 inTagSection = True |
|
1042 parts = desc.split(None, 1) |
|
1043 lastTag = parts[0] |
|
1044 if len(parts) < 2: |
|
1045 raise TagError( |
|
1046 "Wrong format in {0} line.\n".format(parts[0])) |
|
1047 yields = [parts[1]] |
|
1048 lastItem = yields |
|
1049 elif desc.startswith("@ytype"): |
|
1050 parts = desc.split(None, 1) |
|
1051 if lastTag != "@yield": |
|
1052 raise TagError( |
|
1053 "{0} line must be preceded by a @yield line\n" |
|
1054 .format(parts[0])) |
|
1055 inTagSection = True |
|
1056 lastTag = parts[0] |
|
1057 if len(parts) < 2: |
|
1058 raise TagError( |
|
1059 "Wrong format in {0} line.\n".format(parts[0])) |
|
1060 yieldTypes = [parts[1]] |
|
1061 lastItem = yieldTypes |
|
1062 elif desc.startswith(("@exception", "@throws", "@raise")): |
|
1063 inTagSection = True |
|
1064 parts = desc.split(None, 2) |
|
1065 lastTag = parts[0] |
|
1066 if len(parts) < 2: |
|
1067 raise TagError( |
|
1068 "Wrong format in {0} line.\n".format(parts[0])) |
|
1069 excName = parts[1] |
|
1070 try: |
|
1071 exceptionDict[excName] = [parts[2]] |
|
1072 except IndexError: |
|
1073 exceptionDict[excName] = [] |
|
1074 lastItem = exceptionDict[excName] |
|
1075 elif desc.startswith("@signal"): |
|
1076 inTagSection = True |
|
1077 lastTag = desc.split(None, 1)[0] |
|
1078 m = _signal(desc, 0) |
|
1079 if m is None: |
|
1080 buffer = desc |
|
1081 else: |
|
1082 buffer = "" |
|
1083 signalName = ( |
|
1084 m.group("SignalName1") or m.group("SignalName2") |
|
1085 ) |
|
1086 signalDesc = ( |
|
1087 m.group("SignalDescription1") or |
|
1088 m.group("SignalDescription2") |
|
1089 ) |
|
1090 signalDict[signalName] = [] |
|
1091 if signalDesc is not None: |
|
1092 signalDict[signalName].append(signalDesc) |
|
1093 lastItem = signalDict[signalName] |
|
1094 elif desc.startswith("@event"): |
|
1095 inTagSection = True |
|
1096 lastTag = desc.split(None, 1)[0] |
|
1097 m = _event(desc, 0) |
|
1098 if m is None: |
|
1099 buffer = desc |
|
1100 else: |
|
1101 buffer = "" |
|
1102 eventName = ( |
|
1103 m.group("EventName1") or m.group("EventName2") |
|
1104 ) |
|
1105 eventDesc = ( |
|
1106 m.group("EventDescription1") or |
|
1107 m.group("EventDescription2") |
|
1108 ) |
|
1109 eventDict[eventName] = [] |
|
1110 if eventDesc is not None: |
|
1111 eventDict[eventName].append(eventDesc) |
|
1112 lastItem = eventDict[eventName] |
|
1113 elif desc.startswith("@deprecated"): |
|
1114 inTagSection = True |
|
1115 parts = desc.split(None, 1) |
|
1116 lastTag = parts[0] |
|
1117 if len(parts) < 2: |
|
1118 raise TagError( |
|
1119 "Wrong format in {0} line.\n".format(parts[0])) |
|
1120 deprecated = [parts[1]] |
|
1121 lastItem = deprecated |
|
1122 elif desc.startswith("@author"): |
|
1123 inTagSection = True |
|
1124 parts = desc.split(None, 1) |
|
1125 lastTag = parts[0] |
|
1126 if len(parts) < 2: |
|
1127 raise TagError( |
|
1128 "Wrong format in {0} line.\n".format(parts[0])) |
|
1129 authorInfo = [parts[1]] |
|
1130 lastItem = authorInfo |
|
1131 elif desc.startswith("@since"): |
|
1132 inTagSection = True |
|
1133 parts = desc.split(None, 1) |
|
1134 lastTag = parts[0] |
|
1135 if len(parts) < 2: |
|
1136 raise TagError( |
|
1137 "Wrong format in {0} line.\n".format(parts[0])) |
|
1138 sinceInfo = [parts[1]] |
|
1139 lastItem = sinceInfo |
|
1140 elif desc.startswith("@see"): |
|
1141 inTagSection = True |
|
1142 parts = desc.split(None, 1) |
|
1143 lastTag = parts[0] |
|
1144 if len(parts) < 2: |
|
1145 raise TagError( |
|
1146 "Wrong format in {0} line.\n".format(parts[0])) |
|
1147 seeList.append([parts[1]]) |
|
1148 lastItem = seeList[-1] |
|
1149 elif desc.startswith("@@"): |
|
1150 lastItem.append(desc[1:]) |
|
1151 elif desc.startswith("@"): |
|
1152 tag = desc.split(None, 1)[0] |
|
1153 raise TagError( |
|
1154 "Unknown tag encountered, {0}.\n".format(tag)) |
|
1155 else: |
|
1156 lastItem.append(ditem) |
|
1157 elif not inTagSection: |
|
1158 lastItem.append(ditem) |
|
1159 |
|
1160 description = self.__genParagraphs(paragraphs) if paragraphs else "" |
|
1161 |
|
1162 parameterSect = ( |
|
1163 self.parametersListTemplate.format( |
|
1164 **{'Parameters': self.__genParamDescriptionListSection( |
|
1165 paramList)}) |
|
1166 if paramList else |
|
1167 "" |
|
1168 ) |
|
1169 |
|
1170 returnSect = ( |
|
1171 self.returnsTemplate.format( |
|
1172 html_uencode('\n'.join(returns))) |
|
1173 if returns else |
|
1174 "" |
|
1175 ) |
|
1176 |
|
1177 returnTypesSect = ( |
|
1178 self.returnTypesTemplate.format( |
|
1179 html_uencode('\n'.join(returnTypes))) |
|
1180 if returnTypes else |
|
1181 "" |
|
1182 ) |
|
1183 |
|
1184 yieldSect = ( |
|
1185 self.yieldsTemplate.format( |
|
1186 html_uencode('\n'.join(yields))) |
|
1187 if yields else |
|
1188 "" |
|
1189 ) |
|
1190 |
|
1191 yieldTypesSect = ( |
|
1192 self.yieldTypesTemplate.format( |
|
1193 html_uencode('\n'.join(yieldTypes))) |
|
1194 if yieldTypes else |
|
1195 "" |
|
1196 ) |
|
1197 |
|
1198 exceptionSect = ( |
|
1199 self.exceptionsListTemplate.format( |
|
1200 **{'Exceptions': self.__genDescriptionListSection( |
|
1201 exceptionDict, self.exceptionsListEntryTemplate)}) |
|
1202 if exceptionDict else |
|
1203 "" |
|
1204 ) |
|
1205 |
|
1206 signalSect = ( |
|
1207 self.signalsListTemplate.format( |
|
1208 **{'Signals': self.__genDescriptionListSection( |
|
1209 signalDict, self.signalsListEntryTemplate)}) |
|
1210 if signalDict else |
|
1211 "" |
|
1212 ) |
|
1213 |
|
1214 eventSect = ( |
|
1215 self.eventsListTemplate.format( |
|
1216 **{'Events': self.__genDescriptionListSection( |
|
1217 eventDict, self.eventsListEntryTemplate)}) |
|
1218 if eventDict else |
|
1219 "" |
|
1220 ) |
|
1221 |
|
1222 deprecatedSect = ( |
|
1223 self.deprecatedTemplate.format( |
|
1224 **{'Lines': html_uencode('\n'.join(deprecated))}) |
|
1225 if deprecated else |
|
1226 "" |
|
1227 ) |
|
1228 |
|
1229 authorInfoSect = ( |
|
1230 self.authorInfoTemplate.format( |
|
1231 **{'Authors': html_uencode('\n'.join(authorInfo))}) |
|
1232 if authorInfo else |
|
1233 "" |
|
1234 ) |
|
1235 |
|
1236 sinceInfoSect = ( |
|
1237 self.sinceInfoTemplate.format( |
|
1238 **{'Info': html_uencode(sinceInfo[0])}) |
|
1239 if sinceInfo else |
|
1240 "" |
|
1241 ) |
|
1242 |
|
1243 seeSect = ( |
|
1244 self.seeListTemplate.format( |
|
1245 **{'Links': self.__genSeeListSection( |
|
1246 seeList, self.seeListEntryTemplate)}) |
|
1247 if seeList else |
|
1248 '' |
|
1249 ) |
|
1250 |
|
1251 return "".join([ |
|
1252 deprecatedSect, description, parameterSect, returnSect, |
|
1253 returnTypesSect, yieldSect, yieldTypesSect, exceptionSect, |
|
1254 signalSect, eventSect, authorInfoSect, seeSect, sinceInfoSect, |
|
1255 ]) |
|
1256 |
|
1257 def getQtHelpKeywords(self): |
|
1258 """ |
|
1259 Public method to retrieve the parts for the QtHelp keywords section. |
|
1260 |
|
1261 @return list of tuples containing the name (string) and the ref |
|
1262 (string). The ref is without the filename part. |
|
1263 """ |
|
1264 if not self.generated: |
|
1265 self.genDocument() |
|
1266 |
|
1267 return self.keywords |