diff -r 000000000000 -r de9c2efb9d02 DocumentationTools/ModuleDocumentor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DocumentationTools/ModuleDocumentor.py Mon Dec 28 16:03:33 2009 +0000 @@ -0,0 +1,1033 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2003 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the builtin documentation generator. + +The different parts of the module document are assembled from the parsed +Python file. The appearance is determined by several templates defined within +this module. +""" + +import sys +import re + +import TemplatesListsStyle +import TemplatesListsStyleCSS + +from Utilities import html_uencode +from Utilities.ModuleParser import RB_SOURCE + +_signal = re.compile(r""" + ^@signal [ \t]+ + (?P<SignalName1> + [a-zA-Z_] \w* [ \t]* \( [^)]* \) + ) + [ \t]* (?P<SignalDescription1> .*) +| + ^@signal [ \t]+ + (?P<SignalName2> + [a-zA-Z_] \w* + ) + [ \t]+ (?P<SignalDescription2> .*) +""", re.VERBOSE | re.DOTALL | re.MULTILINE).search + +_event = re.compile(r""" + ^@event [ \t]+ + (?P<EventName1> + [a-zA-Z_] \w* [ \t]* \( [^)]* \) + ) + [ \t]* (?P<EventDescription1> .*) +| + ^@event [ \t]+ + (?P<EventName2> + [a-zA-Z_] \w* + ) + [ \t]+ (?P<EventDescription2> .*) +""", re.VERBOSE | re.DOTALL | re.MULTILINE).search + +class TagError(Exception): + """ + Exception class raised, if an invalid documentation tag was found. + """ + +class ModuleDocument(object): + """ + Class implementing the builtin documentation generator. + """ + def __init__(self, module, colors, stylesheet = None): + """ + Constructor + + @param module the information of the parsed Python file + @param colors dictionary specifying the various colors for the output + (dictionary of strings) + @param stylesheet the style to be used for the generated pages (string) + """ + self.module = module + self.empty = True + + self.stylesheet = stylesheet + + if self.stylesheet: + self.headerTemplate = TemplatesListsStyleCSS.headerTemplate + self.footerTemplate = TemplatesListsStyleCSS.footerTemplate + self.moduleTemplate = TemplatesListsStyleCSS.moduleTemplate + self.rbFileTemplate = TemplatesListsStyleCSS.rbFileTemplate + self.classTemplate = TemplatesListsStyleCSS.classTemplate + self.methodTemplate = TemplatesListsStyleCSS.methodTemplate + self.constructorTemplate = TemplatesListsStyleCSS.constructorTemplate + self.rbModuleTemplate = TemplatesListsStyleCSS.rbModuleTemplate + self.rbModulesClassTemplate = TemplatesListsStyleCSS.rbModulesClassTemplate + self.functionTemplate = TemplatesListsStyleCSS.functionTemplate + self.listTemplate = TemplatesListsStyleCSS.listTemplate + self.listEntryTemplate = TemplatesListsStyleCSS.listEntryTemplate + self.listEntryNoneTemplate = TemplatesListsStyleCSS.listEntryNoneTemplate + self.listEntryDeprecatedTemplate = \ + TemplatesListsStyleCSS.listEntryDeprecatedTemplate + self.listEntrySimpleTemplate = TemplatesListsStyleCSS.listEntrySimpleTemplate + self.paragraphTemplate = TemplatesListsStyleCSS.paragraphTemplate + self.parametersListTemplate = TemplatesListsStyleCSS.parametersListTemplate + self.parametersListEntryTemplate = \ + TemplatesListsStyleCSS.parametersListEntryTemplate + self.returnsTemplate = TemplatesListsStyleCSS.returnsTemplate + self.exceptionsListTemplate = TemplatesListsStyleCSS.exceptionsListTemplate + self.exceptionsListEntryTemplate = \ + TemplatesListsStyleCSS.exceptionsListEntryTemplate + self.signalsListTemplate = TemplatesListsStyleCSS.signalsListTemplate + self.signalsListEntryTemplate = \ + TemplatesListsStyleCSS.signalsListEntryTemplate + self.eventsListTemplate = TemplatesListsStyleCSS.eventsListTemplate + self.eventsListEntryTemplate = TemplatesListsStyleCSS.eventsListEntryTemplate + self.deprecatedTemplate = TemplatesListsStyleCSS.deprecatedTemplate + self.authorInfoTemplate = TemplatesListsStyleCSS.authorInfoTemplate + self.seeListTemplate = TemplatesListsStyleCSS.seeListTemplate + self.seeListEntryTemplate = TemplatesListsStyleCSS.seeListEntryTemplate + self.seeLinkTemplate = TemplatesListsStyleCSS.seeLinkTemplate + self.sinceInfoTemplate = TemplatesListsStyleCSS.sinceInfoTemplate + else: + self.headerTemplate = TemplatesListsStyle.headerTemplate % colors + self.footerTemplate = TemplatesListsStyle.footerTemplate % colors + self.moduleTemplate = TemplatesListsStyle.moduleTemplate % colors + self.rbFileTemplate = TemplatesListsStyle.rbFileTemplate % colors + self.classTemplate = TemplatesListsStyle.classTemplate % colors + self.methodTemplate = TemplatesListsStyle.methodTemplate % colors + self.constructorTemplate = TemplatesListsStyle.constructorTemplate % colors + self.rbModuleTemplate = TemplatesListsStyle.rbModuleTemplate % colors + self.rbModulesClassTemplate = \ + TemplatesListsStyle.rbModulesClassTemplate % colors + self.functionTemplate = TemplatesListsStyle.functionTemplate % colors + self.listTemplate = TemplatesListsStyle.listTemplate % colors + self.listEntryTemplate = TemplatesListsStyle.listEntryTemplate % colors + self.listEntryNoneTemplate = \ + TemplatesListsStyle.listEntryNoneTemplate % colors + self.listEntryDeprecatedTemplate = \ + TemplatesListsStyle.listEntryDeprecatedTemplate % colors + self.listEntrySimpleTemplate = \ + TemplatesListsStyle.listEntrySimpleTemplate % colors + self.paragraphTemplate = TemplatesListsStyle.paragraphTemplate % colors + self.parametersListTemplate = \ + TemplatesListsStyle.parametersListTemplate % colors + self.parametersListEntryTemplate = \ + TemplatesListsStyle.parametersListEntryTemplate % colors + self.returnsTemplate = TemplatesListsStyle.returnsTemplate % colors + self.exceptionsListTemplate = \ + TemplatesListsStyle.exceptionsListTemplate % colors + self.exceptionsListEntryTemplate = \ + TemplatesListsStyle.exceptionsListEntryTemplate % colors + self.signalsListTemplate = TemplatesListsStyle.signalsListTemplate % colors + self.signalsListEntryTemplate = \ + TemplatesListsStyle.signalsListEntryTemplate % colors + self.eventsListTemplate = TemplatesListsStyle.eventsListTemplate % colors + self.eventsListEntryTemplate = \ + TemplatesListsStyle.eventsListEntryTemplate % colors + self.deprecatedTemplate = TemplatesListsStyle.deprecatedTemplate % colors + self.authorInfoTemplate = TemplatesListsStyle.authorInfoTemplate % colors + self.seeListTemplate = TemplatesListsStyle.seeListTemplate % colors + self.seeListEntryTemplate = TemplatesListsStyle.seeListEntryTemplate % colors + self.seeLinkTemplate = TemplatesListsStyle.seeLinkTemplate % colors + self.sinceInfoTemplate = TemplatesListsStyle.sinceInfoTemplate % colors + + self.keywords = [] # list of tuples containing the name (string) and + # the ref (string). The ref is without the filename part. + self.generated = False + + def isEmpty(self): + """ + Public method to determine, if the module contains any classes or functions. + + @return Flag indicating an empty module (i.e. __init__.py without + any contents) + """ + return self.empty + + def name(self): + """ + Public method used to get the module name. + + @return The name of the module. (string) + """ + return self.module.name + + def description(self): + """ + Public method used to get the description of the module. + + @return The description of the module. (string) + """ + return self.__formatDescription(self.module.description) + + def shortDescription(self): + """ + Public method used to get the short description of the module. + + The short description is just the first line of the modules + description. + + @return The short description of the module. (string) + """ + return self.__getShortDescription(self.module.description) + + def genDocument(self): + """ + Public method to generate the source code documentation. + + @return The source code documentation. (string) + """ + doc = self.headerTemplate % { \ + 'Title' : self.module.name, + 'Style' : self.stylesheet} + \ + self.__genModuleSection() + \ + self.footerTemplate + self.generated = True + return doc + + def __genModuleSection(self): + """ + Private method to generate the body of the document. + + @return The body of the document. (string) + """ + globalsList = self.__genGlobalsListSection() + classList = self.__genClassListSection() + functionList = self.__genFunctionListSection() + try: + if self.module.type == RB_SOURCE: + rbModulesList = self.__genRbModulesListSection() + modBody = self.rbFileTemplate % { \ + 'Module' : self.module.name, + 'ModuleDescription' : \ + self.__formatDescription(self.module.description), + 'GlobalsList' : globalsList, + 'ClassList' : classList, + 'RbModulesList' : rbModulesList, + 'FunctionList' : functionList, + } + else: + modBody = self.moduleTemplate % { \ + 'Module' : self.module.name, + 'ModuleDescription' : \ + self.__formatDescription(self.module.description), + 'GlobalsList' : globalsList, + 'ClassList' : classList, + 'FunctionList' : functionList, + } + except TagError, e: + sys.stderr.write("Error in tags of description of module %s.\n" % \ + self.module.name) + sys.stderr.write("%s\n" % e) + return "" + + classesSection = self.__genClassesSection() + functionsSection = self.__genFunctionsSection() + if self.module.type == RB_SOURCE: + rbModulesSection = self.__genRbModulesSection() + else: + rbModulesSection = "" + return "%s%s%s%s" % (modBody, classesSection, rbModulesSection, functionsSection) + + def __genListSection(self, names, dict, kwSuffix = ""): + """ + Private method to generate a list section of the document. + + @param names The names to appear in the list. (list of strings) + @param dict A dictionary containing all relevant information. + @param kwSuffix suffix to be used for the QtHelp keywords (string) + @return The list section. (string) + """ + lst = [] + for name in names: + lst.append(self.listEntryTemplate % { \ + 'Link' : "%s" % name, + 'Name' : dict[name].name, + 'Description' : self.__getShortDescription(dict[name].description), + 'Deprecated' : self.__checkDeprecated(dict[name].description) and \ + self.listEntryDeprecatedTemplate or "", + }) + if kwSuffix: + n = "%s (%s)" % (name, kwSuffix) + else: + n = "%s" % name + self.keywords.append((n, "#%s" % name)) + return ''.join(lst) + + def __genGlobalsListSection(self, class_ = None): + """ + Private method to generate the section listing all global attributes of + the module. + + @param class_ reference to a class object (Class) + @return The globals list section. (string) + """ + if class_ is not None: + attrNames = sorted(class_.globals.keys()) + else: + attrNames = sorted(self.module.globals.keys()) + if attrNames: + s = ''.join( + [self.listEntrySimpleTemplate % {'Name' : name} for name in attrNames]) + else: + s = self.listEntryNoneTemplate + return self.listTemplate % { \ + 'Entries' : s, + } + + def __genClassListSection(self): + """ + Private method to generate the section listing all classes of the module. + + @return The classes list section. (string) + """ + names = self.module.classes.keys() + names.sort() + if names: + self.empty = False + s = self.__genListSection(names, self.module.classes) + else: + s = self.listEntryNoneTemplate + return self.listTemplate % { \ + 'Entries' : s, + } + + def __genRbModulesListSection(self): + """ + Private method to generate the section listing all modules of the file + (Ruby only). + + @return The modules list section. (string) + """ + names = self.module.modules.keys() + names.sort() + if names: + self.empty = False + s = self.__genListSection(names, self.module.modules) + else: + s = self.listEntryNoneTemplate + return self.listTemplate % { \ + 'Entries' : s, + } + + def __genFunctionListSection(self): + """ + Private method to generate the section listing all functions of the module. + + @return The functions list section. (string) + """ + names = self.module.functions.keys() + names.sort() + if names: + self.empty = False + s = self.__genListSection(names, self.module.functions) + else: + s = self.listEntryNoneTemplate + return self.listTemplate % { \ + 'Entries' : s, + } + + def __genClassesSection(self): + """ + Private method to generate the document section with details about classes. + + @return The classes details section. (string) + """ + classNames = self.module.classes.keys() + classNames.sort() + classes = [] + for className in classNames: + _class = self.module.classes[className] + supers = _class.super + if len(supers) > 0: + supers = ', '.join(supers) + else: + supers = 'None' + + globalsList = self.__genGlobalsListSection(_class) + methList, methBodies = self.__genMethodSection(_class, className) + + try: + clsBody = self.classTemplate % { \ + 'Anchor' : className, + 'Class' : _class.name, + 'ClassSuper' : supers, + 'ClassDescription' : self.__formatDescription(_class.description), + 'GlobalsList' : globalsList, + 'MethodList' : methList, + 'MethodDetails' : methBodies, + } + except TagError, e: + sys.stderr.write("Error in tags of description of class %s.\n" % \ + className) + sys.stderr.write("%s\n" % e) + clsBody = "" + + classes.append(clsBody) + + return ''.join(classes) + + def __genMethodsListSection(self, names, dict, className, clsName): + """ + Private method to generate the methods list section of a class. + + @param names The names to appear in the list. (list of strings) + @param dict A dictionary containing all relevant information. + @param className The class name containing the names. + @param clsName The visible class name containing the names. + @return The list section. (string) + """ + lst = [] + try: + lst.append(self.listEntryTemplate % { \ + 'Link' : "%s.%s" % (className, '__init__'), + 'Name' : clsName, + 'Description' : self.__getShortDescription(dict['__init__'].description), + 'Deprecated' : self.__checkDeprecated(dict['__init__'].description) and \ + self.listEntryDeprecatedTemplate or "", + }) + self.keywords.append(("%s (Constructor)" % className, + "#%s.%s" % (className, '__init__'))) + except KeyError: + pass + + for name in names: + lst.append(self.listEntryTemplate % { \ + 'Link' : "%s.%s" % (className, name), + 'Name' : dict[name].name, + 'Description' : self.__getShortDescription(dict[name].description), + 'Deprecated' : self.__checkDeprecated(dict[name].description) and \ + self.listEntryDeprecatedTemplate or "", + }) + self.keywords.append(("%s.%s" % (className, name), + "#%s.%s" % (className, name))) + return ''.join(lst) + + def __genMethodSection(self, obj, className): + """ + Private method to generate the method details section. + + @param obj Reference to the object being formatted. + @param className Name of the class containing the method. (string) + @return The method list and method details section. (tuple of two string) + """ + methList = [] + methBodies = [] + methods = obj.methods.keys() + methods.sort() + + # first do the constructor + if '__init__' in methods: + methods.remove('__init__') + try: + methBody = self.constructorTemplate % { \ + 'Anchor' : className, + 'Class' : obj.name, + 'Method' : '__init__', + 'MethodDescription' : \ + self.__formatDescription(obj.methods['__init__'].description), + 'Params' : ', '.join(obj.methods['__init__'].parameters[1:]), + } + except TagError, e: + sys.stderr.write("Error in tags of description of method %s.%s.\n" % \ + (className, '__init__')) + sys.stderr.write("%s\n" % e) + methBody = "" + methBodies.append(methBody) + + for method in methods: + try: + methBody = self.methodTemplate % { \ + 'Anchor' : className, + 'Class' : obj.name, + 'Method' : obj.methods[method].name, + 'MethodDescription' : \ + self.__formatDescription(obj.methods[method].description), + 'Params' : ', '.join(obj.methods[method].parameters[1:]), + } + except TagError, e: + sys.stderr.write("Error in tags of description of method %s.%s.\n" % \ + (className, method)) + sys.stderr.write("%s\n" % e) + methBody = "" + methBodies.append(methBody) + + methList = self.__genMethodsListSection(methods, obj.methods, className, obj.name) + + if not methList: + methList = self.listEntryNoneTemplate + return self.listTemplate % { \ + 'Entries' : methList, + }, ''.join(methBodies) + + def __genRbModulesSection(self): + """ + Private method to generate the document section with details about Ruby modules. + + @return The Ruby modules details section. (string) + """ + rbModulesNames = self.module.modules.keys() + rbModulesNames.sort() + rbModules = [] + for rbModuleName in rbModulesNames: + rbModule = self.module.modules[rbModuleName] + globalsList = self.__genGlobalsListSection(rbModule) + methList, methBodies = self.__genMethodSection(rbModule, rbModuleName) + classList, classBodies = \ + self.__genRbModulesClassesSection(rbModule, rbModuleName) + + try: + rbmBody = self.rbModuleTemplate % { \ + 'Anchor' : rbModuleName, + 'Module' : rbModule.name, + 'ModuleDescription' : self.__formatDescription(rbModule.description), + 'GlobalsList' : globalsList, + 'ClassesList' : classList, + 'ClassesDetails' : classBodies, + 'FunctionsList' : methList, + 'FunctionsDetails' : methBodies, + } + except TagError, e: + sys.stderr.write("Error in tags of description of Ruby module %s.\n" % \ + rbModuleName) + sys.stderr.write("%s\n" % e) + rbmBody = "" + + rbModules.append(rbmBody) + + return ''.join(rbModules) + + def __genRbModulesClassesSection(self, obj, modName): + """ + Private method to generate the Ruby module classes details section. + + @param obj Reference to the object being formatted. + @param modName Name of the Ruby module containing the classes. (string) + @return The classes list and classes details section. (tuple of two string) + """ + classNames = obj.classes.keys() + classNames.sort() + classes = [] + for className in classNames: + _class = obj.classes[className] + supers = _class.super + if len(supers) > 0: + supers = ', '.join(supers) + else: + supers = 'None' + + classname = "%s.%s" % (modName, className) + methList, methBodies = self.__genMethodSection(_class, className) + + try: + clsBody = self.rbModulesClassTemplate % { \ + 'Anchor' : className, + 'Class' : _class.name, + 'ClassSuper' : supers, + 'ClassDescription' : self.__formatDescription(_class.description), + 'MethodList' : methList, + 'MethodDetails' : methBodies, + } + except TagError, e: + sys.stderr.write("Error in tags of description of class %s.\n" % \ + className) + sys.stderr.write("%s\n" % e) + clsBody = "" + + classes.append(clsBody) + + + classesList = \ + self.__genRbModulesClassesListSection(classNames, obj.classes, modName) + + if not classesList: + classesList = self.listEntryNoneTemplate + return self.listTemplate % { \ + 'Entries' : classesList, + }, ''.join(classes) + + def __genRbModulesClassesListSection(self, names, dict, moduleName): + """ + Private method to generate the classes list section of a Ruby module. + + @param names The names to appear in the list. (list of strings) + @param dict A dictionary containing all relevant information. + @param moduleName Name of the Ruby module containing the classes. (string) + @return The list section. (string) + """ + lst = [] + for name in names: + lst.append(self.listEntryTemplate % { \ + 'Link' : "%s.%s" % (moduleName, name), + 'Name' : dict[name].name, + 'Description' : self.__getShortDescription(dict[name].description), + 'Deprecated' : self.__checkDeprecated(dict[name].description) and \ + self.listEntryDeprecatedTemplate or "", + }) + self.keywords.append(("%s.%s" % (moduleName, name), + "#%s.%s" % (moduleName, name))) + return ''.join(lst) + + def __genFunctionsSection(self): + """ + Private method to generate the document section with details about functions. + + @return The functions details section. (string) + """ + funcBodies = [] + funcNames = self.module.functions.keys() + funcNames.sort() + for funcName in funcNames: + try: + funcBody = self.functionTemplate % { \ + 'Anchor' : funcName, + 'Function' : self.module.functions[funcName].name, + 'FunctionDescription' : self.__formatDescription(\ + self.module.functions[funcName].description), + 'Params' : ', '.join(self.module.functions[funcName].parameters), + } + except TagError, e: + sys.stderr.write("Error in tags of description of function %s.\n" % \ + funcName) + sys.stderr.write("%s\n" % e) + funcBody = "" + + funcBodies.append(funcBody) + + return ''.join(funcBodies) + + def __getShortDescription(self, desc): + """ + Private method to determine the short description of an object. + + The short description is just the first non empty line of the + documentation string. + + @param desc The documentation string. (string) + @return The short description. (string) + """ + dlist = desc.splitlines() + sdlist = [] + descfound = 0 + for desc in dlist: + desc = desc.strip() + if desc: + descfound = 1 + dotpos = desc.find('.') + if dotpos == -1: + sdlist.append(desc.strip()) + else: + while dotpos+1 < len(desc) and not desc[dotpos+1].isspace(): + # don't recognize '.' inside a number or word as stop condition + dotpos = desc.find('.', dotpos+1) + if dotpos == -1: + break + if dotpos == -1: + sdlist.append(desc.strip()) + else: + sdlist.append(desc[:dotpos+1].strip()) + break # break if a '.' is found + else: + if descfound: + break # break if an empty line is found + if sdlist: + return html_uencode(' '.join(sdlist)) + else: + return '' + + def __checkDeprecated(self, descr): + """ + Private method to check, if the object to be documented contains a + deprecated flag. + + @param desc The documentation string. (string) + @return Flag indicating the deprecation status. (boolean) + """ + dlist = descr.splitlines() + for desc in dlist: + desc = desc.strip() + if desc.startswith("@deprecated"): + return True + return False + + def __genParagraphs(self, lines): + """ + Private method to assemble the descriptive paragraphs of a docstring. + + A paragraph is made up of a number of consecutive lines without + an intermediate empty line. Empty lines are treated as a paragraph + delimiter. + + @param lines A list of individual lines. (list of strings) + @return Ready formatted paragraphs. (string) + """ + lst = [] + linelist = [] + for line in lines: + if line.strip(): + if line == '.': + linelist.append("") + else: + linelist.append(html_uencode(line)) + else: + lst.append(self.paragraphTemplate % { \ + 'Lines' : '\n'.join(linelist) + }) + linelist = [] + if linelist: + lst.append(self.paragraphTemplate % { \ + 'Lines' : '\n'.join(linelist) + }) + return ''.join(lst) + + def __genDescriptionListSection(self, dictionary, template): + """ + Private method to generate the list section of a description. + + @param dictionary Dictionary containing the info for the + list section. + @param template The template to be used for the list. (string) + @return The list section. (string) + """ + lst = [] + keys = dictionary.keys() + keys.sort() + for key in keys: + lst.append(template % { \ + 'Name' : key, + 'Description' : html_uencode('\n'.join(dictionary[key])), + }) + return ''.join(lst) + + def __genParamDescriptionListSection(self, _list, template): + """ + Private method to generate the list section of a description. + + @param _list List containing the info for the + list section. + @param template The template to be used for the list. (string) + @return The list section. (string) + """ + lst = [] + for name, lines in _list: + lst.append(template % { \ + 'Name' : name, + 'Description' : html_uencode('\n'.join(lines)), + }) + return ''.join(lst) + + def __formatCrossReferenceEntry(self, entry): + """ + Private method to format a cross reference entry. + + This cross reference entry looks like "package.module#member label". + + @param entry the entry to be formatted (string) + @return formatted entry (string) + """ + if entry.startswith('"'): + return entry + elif entry.startswith('<'): + entry = entry[3:] + else: + try: + reference, label = entry.split(None, 1) + except ValueError: + reference = seeEntryString + label = seeEntryString + try: + path, anchor = reference.split('#', 1) + except ValueError: + path = reference + anchor = '' + reference = path and "%s.html" % path or '' + if anchor: + reference = "%s#%s" % (reference, anchor) + entry = 'href="%s">%s</a>' % (reference, label) + + return self.seeLinkTemplate % { \ + 'Link' : entry, + } + + def __genSeeListSection(self, _list, template): + """ + Private method to generate the "see also" list section of a description. + + @param _list List containing the info for the section. + @param template The template to be used for the list. (string) + @return The list section. (string) + """ + lst = [] + for seeEntry in _list: + seeEntryString = ''.join(seeEntry) + lst.append(template % { \ + 'Link' : html_uencode(self.__formatCrossReferenceEntry(seeEntryString)), + }) + return '\n'.join(lst) + + def __processInlineTags(self, desc): + """ + Private method to process inline tags. + + @param desc One line of the description (string) + @return processed line with inline tags expanded (string) + """ + start = desc.find('{@') + while start != -1: + stop = desc.find('}', start + 2) + if stop == -1: + raise TagError, "Unterminated inline tag.\n%s" % desc + + tagText = desc[start + 1:stop] + if tagText.startswith('@link'): + parts = tagText.split(None, 1) + if len(parts) < 2: + raise TagError, "Wrong format in inline tag %s.\n%s" % \ + (parts[0], desc) + + formattedTag = self.__formatCrossReferenceEntry(parts[1]) + desc = desc.replace("{%s}" % tagText, formattedTag) + else: + tag = tagText.split(None, 1)[0] + raise TagError, "Unknown inline tag encountered, %s.\n%s" % \ + (tag, desc) + + start = desc.find('{@') + + return desc + + def __formatDescription(self, descr): + """ + Private method to format the contents of the documentation string. + + @param descr The contents of the documentation string. (string) + @exception TagError A tag doesn't have the correct number + of arguments. + @return The formated contents of the documentation string. (string) + """ + if not descr: + return "" + + paragraphs = [] + paramList = [] + returns = [] + exceptionDict = {} + signalDict = {} + eventDict = {} + deprecated = [] + authorInfo = [] + sinceInfo = [] + seeList = [] + lastItem = paragraphs + inTagSection = False + + dlist = descr.splitlines() + while dlist and not dlist[0]: + del dlist[0] + for ditem in dlist: + ditem = self.__processInlineTags(ditem) + desc = ditem.strip() + if desc: + if desc.startswith("@param") or desc.startswith("@keyparam"): + inTagSection = True + parts = desc.split(None, 2) + if len(parts) < 2: + raise TagError, "Wrong format in %s line.\n" % parts[0] + paramName = parts[1] + if parts[0] == "@keyparam": + paramName += '=' + try: + paramList.append([paramName, [parts[2]]]) + except IndexError: + paramList.append([paramName, []]) + lastItem = paramList[-1][1] + elif desc.startswith("@return"): + inTagSection = True + parts = desc.split(None, 1) + if len(parts) < 2: + raise TagError, "Wrong format in %s line.\n" % parts[0] + returns = [parts[1]] + lastItem = returns + elif desc.startswith("@exception") or \ + desc.startswith("@throws") or \ + desc.startswith("@raise"): + inTagSection = True + parts = desc.split(None, 2) + if len(parts) < 2: + raise TagError, "Wrong format in %s line.\n" % parts[0] + excName = parts[1] + try: + exceptionDict[excName] = [parts[2]] + except IndexError: + exceptionDict[excName] = [] + lastItem = exceptionDict[excName] + elif desc.startswith("@signal"): + inTagSection = True + m = _signal(desc,0) + if m is None: + raise TagError, "Wrong format in %s line.\n" % parts[0] + signalName = 1 and m.group("SignalName1") \ + or m.group("SignalName2") + signalDesc = 1 and m.group("SignalDescription1") \ + or m.group("SignalDescription2") + signalDict[signalName] = [] + if signalDesc is not None: + signalDict[signalName].append(signalDesc) + lastItem = signalDict[signalName] + elif desc.startswith("@event"): + inTagSection = True + m = _event(desc,0) + if m is None: + raise TagError, "Wrong format in %s line.\n" % parts[0] + eventName = 1 and m.group("EventName1") \ + or m.group("EventName2") + eventDesc = 1 and m.group("EventDescription1") \ + or m.group("EventDescription2") + eventDict[eventName] = [] + if eventDesc is not None: + eventDict[eventName].append(eventDesc) + lastItem = eventDict[eventName] + elif desc.startswith("@deprecated"): + inTagSection = True + parts = desc.split(None, 1) + if len(parts) < 2: + raise TagError, "Wrong format in %s line.\n" % parts[0] + deprecated = [parts[1]] + lastItem = deprecated + elif desc.startswith("@author"): + inTagSection = True + parts = desc.split(None, 1) + if len(parts) < 2: + raise TagError, "Wrong format in %s line.\n" % parts[0] + authorInfo = [parts[1]] + lastItem = authorInfo + elif desc.startswith("@since"): + inTagSection = True + parts = desc.split(None, 1) + if len(parts) < 2: + raise TagError, "Wrong format in %s line.\n" % parts[0] + sinceInfo = [parts[1]] + lastItem = sinceInfo + elif desc.startswith("@see"): + inTagSection = True + parts = desc.split(None, 1) + if len(parts) < 2: + raise TagError, "Wrong format in %s line.\n" % parts[0] + seeList.append([parts[1]]) + lastItem = seeList[-1] + elif desc.startswith("@@"): + lastItem.append(desc[1:]) + elif desc.startswith("@"): + tag = desc.split(None, 1)[0] + raise TagError, "Unknown tag encountered, %s.\n" % tag + else: + lastItem.append(ditem) + elif not inTagSection: + lastItem.append(ditem) + + if paragraphs: + description = self.__genParagraphs(paragraphs) + else: + description = "" + + if paramList: + parameterSect = self.parametersListTemplate % { \ + 'Parameters' : self.__genParamDescriptionListSection(paramList, + self.parametersListEntryTemplate) + } + else: + parameterSect = "" + + if returns: + returnSect = self.returnsTemplate % html_uencode('\n'.join(returns)) + else: + returnSect = "" + + if exceptionDict: + exceptionSect = self.exceptionsListTemplate % { \ + 'Exceptions' : self.__genDescriptionListSection(exceptionDict, + self.exceptionsListEntryTemplate) + } + else: + exceptionSect = "" + + if signalDict: + signalSect = self.signalsListTemplate % { \ + 'Signals' : self.__genDescriptionListSection(signalDict, + self.signalsListEntryTemplate) + } + else: + signalSect = "" + + if eventDict: + eventSect = self.eventsListTemplate % { \ + 'Events' : self.__genDescriptionListSection(eventDict, + self.eventsListEntryTemplate) + } + else: + eventSect = "" + + if deprecated: + deprecatedSect = self.deprecatedTemplate % { \ + 'Lines' : html_uencode('\n'.join(deprecated)), + } + else: + deprecatedSect = "" + + if authorInfo: + authorInfoSect = self.authorInfoTemplate % { \ + 'Authors' : html_uencode('\n'.join(authorInfo)), + } + else: + authorInfoSect = "" + + if sinceInfo: + sinceInfoSect = self.sinceInfoTemplate % { \ + 'Info' : html_uencode(sinceInfo[0]), + } + else: + sinceInfoSect = "" + + if seeList: + seeSect = self.seeListTemplate % { \ + 'Links' : self.__genSeeListSection(seeList, self.seeListEntryTemplate), + } + else: + seeSect = '' + + return "%s%s%s%s%s%s%s%s%s%s" % ( \ + deprecatedSect, description, parameterSect, returnSect, + exceptionSect, signalSect, eventSect, authorInfoSect, + seeSect, sinceInfoSect + ) + + def getQtHelpKeywords(self): + """ + Public method to retrieve the parts for the QtHelp keywords section. + + @return list of tuples containing the name (string) and the ref (string). The ref + is without the filename part. + """ + if not self.generated: + self.genDocument() + + return self.keywords