""" Generiert zu einem Python-Projekt Beschreibungsdateien im HTML-Format. gendesc.py <dateiname> Die Dateien sollten Kommentare in dem vom Programm verwendeten, auf XML basierenden Format enthalten. Der Text in den einzelnen Feldern muss HTML-kompatibel sein, d.h. Tags für die Formatierung sind möglich, und von HTML speziell behandelte Sonderzeichen müssen entsprechend gequoted sein. Matthias Neumann, Gerard de Melo (Gruppe 2) """ import re, string, sys, os importdescriptions={ 'math': 'Mathematik-Funktionen', 'cmath': 'Mathematik-Funktionen für komplexe Zahlen', 'os': 'Betriebssystem-bezogene Funktionen', 'pickle': 'Objekt-Serialisation', 'random': 'Zufallszahlen', 're': 'Regular-Expression-Modul', 'string': 'Zeichenketten-Funktionen', 'sys': 'System-spezifische Parameter und Funktionen' } global bearbeitet bearbeitet={} # zwei Verbund-Datenstrukturen, die verwendet werden class moduleinfostruct: pass class funcinfostruct: pass def re_search(regexp,s): """ führt eine Regular Expression Suche durch regexp - Python Regular Expression s - String Die 1. Gruppe des MatchObjects, falls die Suche erfolgreich war, ansonsten einen leeren String. """ mo=re.compile(regexp,re.IGNORECASE | re.DOTALL | re.UNICODE).search(s) if mo!=None: return(mo.group(1)) else: return '' def extractmoduleinfo(s): """ Extrahiert die Modulbeschreibung s - String mit den Modulbeschreibungen, so wie sie in der Datei vorkommen Modulbeschreibung in einem moduleinfostruct """ moduleinfo=moduleinfostruct() # die regular expressions wurden ein wenig # entstellt, damit dass programm sie beim # Selbsttest nicht fälschlicherweise matched moduleinfo.purpose=re_search(r"<[p]urpose>(.*?)",s) moduleinfo.start=re_search(r"<[s]tart>(.*?)",s) moduleinfo.output=re_search(r"<[o]utput>(.*?)",s) moduleinfo.comment=re_search(r"<[c]omment>(.*?)",s) moduleinfo.bugs=re_search(r"<[b]ugs>(.*?)",s) moduleinfo.author=re_search(r"<[a]uthor>(.*?)",s) moduleinfo.history=re_search(r"<[h]istory>(.*?)",s) return moduleinfo def extractfuncinfo(s): """ Extrahiert die Funktionsbeschreibung s - String mit der Funktionsdefinition und den Kommentaren Funktionsbeschreibung in einem funcinfostruct """ funcinfo=funcinfostruct() # Standardinformationen funcinfo.name=re_search(r"^\s*def\s*(\w*?\s*\(.*?\))",s) funcinfo.purpose=re_search(r"<[p]urpose>(.*?)",s) funcinfo.parameters=re_search(r"<[p]arameters>(.*?)",s) funcinfo.returns=re_search(r"<[r]eturns>(.*?)",s) funcinfo.comment=re_search(r"<[c]omment>(.*?)",s) funcinfo.bugs=re_search(r"<[b]ugs>(.*?)",s) funcinfo.author=re_search(r"<[a]uthor>(.*?)",s) # Suche nach exceptions funcinfo.exceptions=re.compile(r"^\s*raise\s+(\w*)",re.MULTILINE).findall(s) return funcinfo def writehtml(name,fn,moduleinfo,functionlist): """ Generiert die Ausgabedatei im HTML-Format. name - Name des Moduls
fn - Ausgabe-Dateiname
moduleinfo - moduleinfostruct mit den Informationen zum Modul
functionlist - eine funcinfostruct-Liste mit Informationen zu den Funktionen
kein Rückgabewert """ # Datei öffnen try: fo=open(fn,"w") except: raise IOError # HTML-Kopf fo.write('\n'); fo.write('\n'); fo.write(' '+name+'\n'); fo.write('\n'); fo.write('\n'); # Modulbeschreibung ausgeben fo.write('

Modul: '+name+'

\n'); if moduleinfo.purpose: fo.write('

Modulbeschreibung
\n'+moduleinfo.purpose+'
\n'); if moduleinfo.start: fo.write('

Aufruf
\n'+moduleinfo.start+'
\n'); if moduleinfo.output: fo.write('

Ausgabe
\n'+moduleinfo.output+'
\n'); if moduleinfo.comment: fo.write('

Bemerkungen
\n'+moduleinfo.comment+'
\n'); if moduleinfo.bugs: fo.write('

Bugs
\n'+moduleinfo.bugs+'
\n'); fo.write('

Importierte Module
\n'); if len(moduleinfo.imports)==0: fo.write('Keine
\n') else: moduleinfo.imports.sort() for s in moduleinfo.imports: if importdescriptions.has_key(s): s+=' - '+importdescriptions[s] fo.write(s+'
\n') if moduleinfo.author: fo.write('

Autor
\n'+moduleinfo.author+'
\n'); if moduleinfo.history: fo.write('

History
\n'+moduleinfo.history+'
\n'); # Funktionsübersicht mit Quicklinks ausgeben fo.write('

Funktionen:
\n'); if len(functionlist)==0: fo.write('Das Modul enthält keine Funktionen
\n'); else: for funcinfo in functionlist: fo.write(''+funcinfo.name+'
\n'); fo.write('
\n'); # detaillierte Beschreibungen der Funktionen ausgeben for funcinfo in functionlist: fo.write('\n\n\n


\n'+moduleinfo.output); fo.write('\n'); fo.write('

Funktion: '+funcinfo.name+'

\n'); if funcinfo.purpose: fo.write('

Beschreibung: \n'+funcinfo.purpose+'
\n'); if funcinfo.parameters: fo.write('

Parameter:
\n'+funcinfo.parameters+'
\n'); if funcinfo.returns: fo.write('

Rückgabewert: \n'+funcinfo.returns+'
\n'); if funcinfo.comment: fo.write('

Bemerkungen
\n'+funcinfo.comment+'
\n'); if funcinfo.bugs: fo.write('

Bugs
\n'+funcinfo.comment+'
\n'); if len(funcinfo.exceptions)>0: fo.write('

Unmittelbar erzeugte Exceptions:
\n'); for s in funcinfo.exceptions: fo.write(s+'
\n'); if funcinfo.author: fo.write('

Autor
\n'+funcinfo.author+'
\n'); fo.write('
\n'); # Ende der Datei fo.write('


\n'); fo.write('\n'); fo.write('\n'); fo.close() def parsefile(fn): """ Liest und scannt die Datei fn und generiert mit Hilfe der Hilfsfunktionen die Ausgabedatei. fn - Eingabedatei kein Rückgabewert """ global bearbeitet # Modul lesen try: fi=open(fn,"r") data=string.join(fi.readlines()) fi.close() except: print "Konnte die Datei "+fn+" nicht öffnen!" return # Modulbeschreibung extrahieren und interpretieren moduledescription=re_search(r"(.*?)",data) moduleinfo=extractmoduleinfo(moduledescription) # import-Anweisungen suchen moduleinfo.imports=re.compile(r"^\s*from\s+(\w*)\s+import\s+\w*",re.MULTILINE).findall(data) ml=re.compile(r"^\s*import \s*([^\n#]*)",re.MULTILINE).findall(data) for x in ml: liste=string.split(x,',') for s in liste: s=string.strip(s) if s!='': moduleinfo.imports.append(s) # die einzelnen Funktionen trennen data=re.split("\n\s*def ",data) # jede Funktion untersuchen functionlist=[] i=1 for func in data[1:]: funcinfo=extractfuncinfo("def "+func) funcinfo.no=i functionlist.append(funcinfo) i+=1 # Ausgabe der Beschreibung fn2=fn+'.html' writehtml(fn,fn2,moduleinfo,functionlist) # Rekursiv die anderen Module bearbeiten bearbeitet[fn]=1 for s in moduleinfo.imports: s=s+'.py' if not bearbeitet.has_key(s): if os.path.exists(s): parsefile(s) if len(sys.argv)>1: parsefile(sys.argv[1]) else: print "Bitte geben Sie eine Python-Eingabedatei als Parameter an!"