Leider gibt es dabei eine Vermischung von Python built-in Module/Befehle und die bei dem Projekt selber geschriebenen Klassen... Schön wäre, wenn es in der Datenbank getrennt in zwei Tabellen gespeichert werden würde, oder zumindest du Information zusätlich, aus welchen Modulen es stammt.
Mir fällt nur ein, direkt in den Hiletexten nach der Angabe "FILE" ausschau zu halten. Anhand des Pfades kann man drauf rückschließen, ob es ein built-in ist oder nicht...
Gibt es da eine bessere/einfachere Möglichkeit das zu Unterscheiden?
Hier mein Parser:
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"PySource2HTML by Jens Diemer (www.jensdiemer.de)"
__version__ = "0.0.1"
__history__ = """
v0.0.1
- erste Version
"""
__doc__ = """Parsed eine Python-Source Datei.
Schreibt dabei Hilfstexte, erzeugt mit help(), von allen vorhandenen
"Befehlen" und schreibt diese in eine DB.
Erzeugt eine HTML-Datei mit Syntaxhighlighting und Verknüpfungen bei den
gefundenen "Befehle"
Based on
MoinMoin - Python Source Parser
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
Hinweis
-------
Man muss die aktuelle Hilfe, in HTML Version herrunterladen und am besten in
"./python/Doc/" entpacken! Ansonsten erh孴 man oft folgenden Fehler:
Sorry, topic and keyword documentation is not available because the Python
HTML documentation files could not be found. If you have installed them,
please set the environment variable PYTHONDOCS to indicate their location.
"""
import os
if os.environ.has_key("SERVER_SIGNATURE"):
import cgitb;cgitb.enable()
import sys, cgi, string, cStringIO
import keyword, token, tokenize
class RedirectStdOut:
"""
ermöglicht es die Ausgaben zu speichern und als String abzurufen
wird von help2() benötigt.
"""
def __init__(self):
self.MeinStdOut = sys.stdout
self.save = False
self.data = ""
def store( self ):
self.save = True
def write(self,*text):
text=" ".join([str(i) for i in text])
if self.save:
self.data += text
return
self.MeinStdOut.write(text)
def get( self ):
self.save = False
result = self.data
self.data = ""
return result
# stdout für help2() erweitern
sys.stdout = RedirectStdOut()
def help2( cmd ):
"""
Liefert mit help() den Hilfetext als String zurück.
Wird in Parser.process_help() verwendet.
"""
sys.stdout.store()
help( cmd )
return sys.stdout.get()
#~ print "-"*80
#~ print help2( "cgi" )[:50]
#~ print "-"*80
#~ sys.exit()
#############################################################################
### Python Source Parser (does Hilighting)
#############################################################################
_KEYWORD = token.NT_OFFSET + 1
_TEXT = token.NT_OFFSET + 2
_colors = {
token.NUMBER: '#0080C0',
token.OP: '#0000C0',
token.STRING: '#004080',
tokenize.COMMENT: '#008000',
token.NAME: '#000000',
token.ERRORTOKEN: '#FF8080',
_KEYWORD: '#C00000',
_TEXT: '#000000',
}
class Parser:
""" Send colored python source.
"""
def __init__( self, raw, helpDB, out = sys.stdout ):
""" Store the source text.
"""
self.raw = string.strip(string.expandtabs(raw))
self.out = out
self.helpDB = helpDB
self.keycache = []
def format(self, formatter, form):
""" Parse and send the colored source.
"""
# store line offsets in self.lines
self.lines = [0, 0]
pos = 0
while 1:
pos = string.find(self.raw, '\n', pos) + 1
if not pos: break
self.lines.append(pos)
self.lines.append(len(self.raw))
# parse the source and write it
self.pos = 0
text = cStringIO.StringIO(self.raw)
self.out.write('<pre><font face="Lucida,Courier New">')
try:
tokenize.tokenize(text.readline, self)
except tokenize.TokenError, ex:
msg = ex[0]
line = ex[1][0]
self.out.write("<h3>ERROR: %s</h3>%s\n" % (
msg, self.raw[self.lines[line]:]))
self.out.write('</font></pre>')
def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
""" Token handler.
"""
if 0:
print "type", toktype, token.tok_name[toktype], "text", toktext,
print "start", srow,scol, "end", erow,ecol, "<br>"
# calculate new positions
oldpos = self.pos
newpos = self.lines[srow] + scol
self.pos = newpos + len(toktext)
# handle newlines
if toktype in [token.NEWLINE, tokenize.NL]:
self.out.write('\n')
return
# send the original whitespace, if needed
if newpos > oldpos:
self.out.write(self.raw[oldpos:newpos])
# skip indenting tokens
if toktype in [token.INDENT, token.DEDENT]:
self.pos = newpos
return
# map token type to a color group
if token.LPAR <= toktype and toktype <= token.OP:
toktype = token.OP
elif toktype == token.NAME and keyword.iskeyword(toktext):
toktype = _KEYWORD
color = _colors.get(toktype, _colors[_TEXT])
style = ''
if toktype == token.ERRORTOKEN:
style = ' style="border: solid 1.5pt #FF0000;"'
# ---------------------------------------------------------
helplink = False
#~ print toktext, toktype
if toktype in [1, _KEYWORD]:
helplink = self.process_help( toktext )
# ---------------------------------------------------------
if helplink:
# Beim Hilfelink erfolgt Einfärbung über CSS
self.out.write( """<a href="JavaScript:h('%s');">""" % toktext )
else:
self.out.write('<font color="%s"%s>' % (color, style))
self.out.write(cgi.escape(toktext))
if helplink:
self.out.write( "</a>" )
else:
self.out.write('</font>')
def process_help( self, toktext ):
"""
Extrahiert zum >toktext< die Hiletexte und schreibt diese in die DB
zurückgeliefert wird True oder False, jenachdem ob eine Verknüpfung
erstellt werden soll oder nicht.
"""
if toktext in self.keycache:
# Hilfstext wurde schon einmal erzeugt.
return True
#~ print ">",toktext
# Hilfe-Text extrahieren
txt = help2(toktext)
#~ print txt[:100]
if (txt == None) or txt.startswith("no Python documentation found"):
# Hilfe-Text nicht vorhanden -> Kein Link
return False
self.keycache.append(toktext)
# Hilfetext in DB schreiben
self.helpDB[toktext] = txt
# Link soll erzeugt werden
return True
if __name__ == "__main__":
class LocalTestDB(dict):
pass
class stdoutnull:
def write( self, txt):
pass
TestDB = LocalTestDB()
f = file( __file__, "r")
TestSourcen = f.read()
f.close()
MyParser = Parser( TestSourcen, TestDB, sys.stdout )
#~ MyParser = Parser( TestSourcen, TestDB, stdoutnull() )
MyParser.format(None, None)
Noch wird ein unschönes "<font color=...>" für die einfärbung verwendet. Das muß ich bei gelegenheit durch CSS-Klassen ersetzten...