M
M.E.Farmer
Hello all,
This version of PySourceColor supports decorators.
It looks like the syntax is there for a while, so I decided add them
in.
They parser code has also been extended to seperate all 12 types of
string.
I rewrote the _Null colorscheme to actually be null format.
Changed the old _Null to _Mono a black and white colorscheme for
printing.
Also added a few utility functions.
If you don't like the builtin colorschemes you should be able to write
a colorscheme that looks exactly like you want.
This is something that would be nice to have built into pydoc.
The links at the top-right of a pydoc page could point to a colorized
source and a plain text version
This program should run with Python 2.0 -> 2.4.
The code can be any version.
Just save to a file and run it.
It will parse itself into 6 diffrent webpages and show them.
M.E.Farmer
######################################################################
# PySourceColor
# A python source to colorized html converter.
# This does not create w3c valid html, but it works on every
# browser i've tried so far.(I.E.,Mozilla/Firefox,Opera,wxHTML).
# After experimenting with diffrent html vs CSS + html
# I settled on plain old html because it works!
# Too bad CSS is not supported everywhere yet.
# Hacked by M.E.Farmer Jr. 2004
# Python license
######################################################################
# Currently it can seperate and colorize:
# 12 types of strings
# 2 comment types
# numbers
# operators
# class / name
# def / name
# decorator / name
# keywords
# text
# And can use any combination of 3 styles:
# bold
# italic
# underline
######################################################################
# Recent changes:
# October 09, 2004:
# Added support for @decorators.
# Tested on 2.2 and 2.4
# Sepetember 25, 2004:
# Extended string handling:
# Unicode - single, singletriple, double, double triple
# Raw - single, singletriple, double, double triple
# regular - single, singletriple, double, double triple
#
######################################################################
import keyword, os, sys, traceback
import cgi, string, cStringIO
import token, tokenize, glob
import getopt, webbrowser, time
__title__ = 'PySourceColor'
__version__ = "1.7"
__date__ = '09 October 2004'
__author__ = "M.E.Farmer Jr."
__credits__ = '''This was originally submitted /written by
Jürgen Hermann to ASPN python recipes.
I hacked the parser to give me more control over tokens.
Python license M.E.Farmer 2004
'''
# Testing raw and unicode strings
# We do nothing with the value just look at colorizing
_ = (r'raw',r'''raw''',r"raw",r"""raw""")##Raw test
_ = (u'uni',u'''uni''',u"uni",u"""uni""")##Unicode test
# Do not edit
_DOUBLECOMMENT = token.NT_OFFSET + 1
_CLASS = token.NT_OFFSET + 2
_DEF = token.NT_OFFSET + 3
_TEXT = token.NT_OFFSET + 4
_KEYWORD = token.NT_OFFSET + 5
_SINGLEQUOTE = token.NT_OFFSET + 6
_SINGLEQUOTE_R = token.NT_OFFSET + 7
_SINGLEQUOTE_U = token.NT_OFFSET + 8
_DOUBLEQUOTE = token.NT_OFFSET + 9
_DOUBLEQUOTE_R = token.NT_OFFSET + 10
_DOUBLEQUOTE_U = token.NT_OFFSET + 11
_TRIPLESINGLEQUOTE = token.NT_OFFSET + 12
_TRIPLESINGLEQUOTE_R = token.NT_OFFSET + 13
_TRIPLESINGLEQUOTE_U = token.NT_OFFSET + 14
_TRIPLEDOUBLEQUOTE = token.NT_OFFSET + 15
_TRIPLEDOUBLEQUOTE_R = token.NT_OFFSET + 16
_TRIPLEDOUBLEQUOTE_U = token.NT_OFFSET + 17
_BACKGROUND = token.NT_OFFSET + 18
_DECORATOR = token.NT_OFFSET + 19
_DECORATOR_DEF = token.NT_OFFSET + 20
######################################################################
# Edit colors and styles to taste
# Create your own scheme, just copy one below , rename and edit.
# Color is rgb hex and must be specified. #RRGGBB
# Styles are optional: b=bold, i=italic, u=underline
# Colorscheme names must start with an underscore: _MyColor
# Underscore will not be used on command line (--color= Pythonwin)
######################################################################
_Null = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: '#000000',# Decorators
_DECORATOR: '#000000',# @
token.NAME: '#000000',# All Text
token.NUMBER: '#000000',# 0->10
token.OP: '#000000',# ()<>=!.:;^>%, etc...
tokenize.COMMENT: '#000000',# There are 2 types of comment
_DOUBLECOMMENT: '#000000',## Like this
_CLASS: '#000000',# Class name
_DEF: '#000000',# Def name
_KEYWORD: '#000000',# Python keywords
_SINGLEQUOTE: '#000000',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#000000',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#000000',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#000000',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#000000',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#000000',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#000000',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#000000',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#000000',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#000000',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#000000',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#000000',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
_Mono = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: 'bu#000000',# Decorators
_DECORATOR: 'b#000000',# @
token.NAME: '#000000',# All Text
token.NUMBER: 'b#000000',# 0->10
token.OP: 'b#000000',# ()<>=!.:;^>%, etc...
tokenize.COMMENT: 'i#000000',# There are 2 types of comment
_DOUBLECOMMENT: '#000000',## Like this
_CLASS: 'bu#000000',# Class name
_DEF: 'b#000000',# Def name
_KEYWORD: 'b#000000',# Python keywords
_SINGLEQUOTE: '#000000',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#000000',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#000000',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#000000',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#000000',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#000000',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#000000',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#000000',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#000000',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: 'i#000000',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R:'i#000000',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U:'i#000000',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
_Dark = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#FFFFFF',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: 'b#FFBBAA',# Decorators
_DECORATOR: 'b#CC5511',# @
token.NAME: '#ffffff',# All Text
token.NUMBER: '#FF0000',# 0->10
token.OP: 'b#FAF785',# Operators ()<>=!.:;^>%,
etc...
tokenize.COMMENT: 'i#45FCA0',# There are 2 types of comment
_DOUBLECOMMENT: '#A7C7A9',## Like this
_CLASS: 'b#B599FD',# Class name
_DEF: 'b#EBAE5C',# Def name
_KEYWORD: 'b#8680FF',# Python keywords
_SINGLEQUOTE: '#F8BAFE',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#F8BAFE',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#F8BAFE',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#FF80C0',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#FF80C0',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#FF80C0',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#FF9595',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#FF9595',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#FF9595',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#B3FFFF',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#B3FFFF',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#B3FFFF',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#000000',# Page background color
}
_Lite = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: 'b#BB4422',# Decorators
_DECORATOR: 'b#3333af',# @
token.NAME: '#000000',# All Text
token.NUMBER: '#FF2200',# 0->10
token.OP: 'b#303000',# Operators ()<>=!.:;^>%,
etc...
tokenize.COMMENT: '#007F00',# There are 2 types of comment
_DOUBLECOMMENT: '#606060',## Like this
_CLASS: '#0000FF',# Class name
_DEF: 'b#9C7A00',# Def name
_KEYWORD: 'b#0000AF',# Python keywords
_SINGLEQUOTE: '#600080',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#600080',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#600080',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#A0008A',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#A0008A',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#A0008A',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#4488BB',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#4488BB',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#4488BB',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#2299BB',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#2299BB',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#2299BB',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
_Idle = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: '#900090',# Decorators
_DECORATOR: '#000000',# @
token.NAME: '#000000',# All Text
token.NUMBER: '#000000',# 0->10
token.OP: '#000000',# Operators ()<>=!.:;^>%,
etc...
tokenize.COMMENT: '#DD0000',# There are 2 types of comment
_DOUBLECOMMENT: '#DD0000',## Like this
_CLASS: '#0000FF',# Class name
_DEF: '#0000FF',# Def name
_KEYWORD: '#FF7700',# Python keywords
_SINGLEQUOTE: '#00AA00',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#00AA00',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#00AA00',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#00AA00',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#00AA00',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#00AA00',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#00AA00',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#00AA00',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#00AA00',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#00AA00',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#00AA00',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#00AA00',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
_PythonWin = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: 'b#303030',# Decorators
_DECORATOR: 'b#DD0080',# @
token.NAME: '#303030',# All Text
token.NUMBER: '#008080',# 0->10
token.OP: '#000000',# ()<>=!.:;^>%, etc...
tokenize.COMMENT: '#007F00',# There are 2 types of comment
_DOUBLECOMMENT: '#7F7F7F',## Like this
_CLASS: 'b#0000FF',# Class name
_DEF: 'b#007F7F',# Def name
_KEYWORD: 'b#000080',# Python keywords
_SINGLEQUOTE: '#808000',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#808000',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#808000',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#808000',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#808000',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#808000',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#808000',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#808000',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#808000',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#808000',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#808000',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#808000',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
DefaultColorScheme= _Dark
##################################################################################
def Usage():
"""
_______________________________________________________________________________
Example usage:
# To colorize all .py,.pyw files in cwdir you can also use: . or _
python PySourceColor.py -i .
# Using long options w/ =
python PySourceColor.py --in=c:/myDir/my.py --out=c:/myDir
--color=Lite --show
# Using short options w/out =
python PySourceColor.py -i c:/myDir/ -c Idle
# Using any mix
python PySourceColor.py --in _ -o=c:/myDir --show
-------------------------------------------------------------------------------
This module is designed to colorize python source code.
It is a hacked version of MoinMoin python parser recipe.
-h or --help
Display this help message.
-i or --in
Input file or dir. (Use any of these for the cwdir . , _ ,
this)
-o or --out
Optional, output dir for the colorized source
default: output dir is input dir.
-c or --color
Optional. Null, Dark, Lite, Idle, Pythonwin, create your own!
default: Dark
-s or --show
Optional, Show webpage after creation.
default: no show
_______________________________________________________________________________
"""
print Usage.__doc__
def Main():
'''Gathers the command line arguments
and try to do something reasonable with them.
'''
try:
# try to get command line args
opts, args = getopt.getopt(sys.argv[1:],
"hsi:c:", ["help", "show", "input=", "out=",
"color="])
except getopt.GetoptError:
# on error print help information and exit:
Usage()
sys.exit(2)
# init some names
input = None
output = None
scheme = None
show = 0
# if we have args then process them
for o, a in opts:
if o in ("-h", "--help"):
Usage()
sys.exit()
if o in ("-o", "--out"):
output = a
if o in ("-i", "--input"):
input = a
if input in('.','_', 'this'):
input = os.getcwd()
if o in ("-s", "--show"):
show = 1
if o in ("-c", "--color"):
try:
#Fix this if you see a weakness
scheme = eval('_%s'%a)
except:
traceback.print_exc()
if input == None:
# if there was no input specified then we try to
# parse ourselves and do it in diffrent flavors.
fi = sys.argv[0]
Path2File(fi, '/MyDir/null', _Null, 1)
Path2File(fi, '/MyDir/mono', _Mono, 1)
Path2File(fi, '/MyDir/lite', _Lite, 1)
Path2File(fi, '/MyDir/dark', _Dark, 1)
Path2File(fi, '/MyDir/idle', _Idle, 1)
Path2File(fi, '/MyDir/pythonwin', _PythonWin, 1)
else:
# if there was at least an input given we can proceed
Convert(input, output, scheme, show)
import os
def Str2Html(sourcestring, title='', form=None, colors=None):
'''Converts a code(string) to colorized HTML
and prints to sys.stdout
form='pre','code',or'snip' for "<pre>yourcode</pre>" only
colors=_Null,_Mono,_Lite,_Dark,_Idle,or _PythonWin
example:
Str2Html("""x, y = os.path.split(myPath)
if os.path.isdir(y):
print'No file' """,form='snip',colors=_Lite)
'''
Parser(sourcestring, colors, title).format(form)
def Path2Html(sourcepath, form=None, colors=None):
'''Converts code(file) to colorized HTML
and prints to sys.stdout
form='pre','code',or'snip' for "<pre>yourcode</pre>" only
colors=_Null,_Mono,_Lite,_Dark,_Idle,or _PythonWin
'''
source = open(sourcepath).read()
Parser(source, colors, sourcepath).format(form)
def Convert(sourcePath, outdir=None, colors=None, show=0):
''' Converts all python source in the given directory to html
file/s.
'''
c=0
# If it is a filename then Path2File
if not os.path.isdir(sourcePath):
if os.path.isfile(sourcePath):
c+=1
Path2File(sourcePath, outdir, colors, show)
# If we pass in a dir we need to walkdir for files.
# Then we need to colorize them with Path2File
else:
fileList = WalkDir(sourcePath)
if fileList != None:
for i in fileList:
c+=1
Path2File(i, outdir, colors, show)
print'Completed colorizing %s source files.'% str(c)
else:
print"No files to convert in dir."
def Path2File(sourcePath, outdir=None, colors=None, show=0):
''' Converts python source to html file.
'''
print" Converting %s into HTML" % sourcePath
# If no outdir is given we use the sourcePath
if outdir == None:
htmlPath = sourcePath + '.html'
else:
# If we do give an outdir, and it does
# not exist , it will be created.
if not os.path.isdir(outdir):
os.makedirs(outdir)
sourceName = os.path.basename(sourcePath)
htmlPath = os.path.join(outdir,sourceName)+'.html'
print " Output to %s"%htmlPath
# Open the text and do the parsing.
source = open(sourcePath).read()
Parser(source, colors, sourcePath, open(htmlPath, 'wt')).format()
if show:
# load HTML page into the default web browser.
# slower than os.startfile or os.system, but more universal
try:
webbrowser.open_new(htmlPath)
except:
traceback.print_exc()
return htmlPath
def WalkDir(dir):
'''Return a list of .py and .pyw files from a given directory.
This function can be written as a generator Python 2.3, or a
genexp
in Python 2.4. But 2.2 and 2.1 would be left out....
'''
# Get a list of files that match *.py*
GLOB_PATTERN = os.path.join(dir, "*.[p][y]*")
pathlist = glob.glob(GLOB_PATTERN)
# Now filter out all but py and pyw
filterlist = [x for x in pathlist
if x.endswith('.py')
or x.endswith('.pyw')]
if filterlist != []:
# if we have a list send it
return filterlist
else:
return None
class Parser:
""" MoinMoin python parser heavily chopped
"""
def __init__(self, raw, colors=None, title='', out=sys.stdout):
''' Store the source text & set some flags.
'''
if colors == None:
colors = DefaultColorScheme
self.raw = string.strip(string.expandtabs(raw))
self.out = out
self.title = os.path.basename(title)
self.ClassFlag = 0
self.DefFlag = 0
self.Decorator = 0
self.colors = colors
# Name: Date stamp top
self.header = 0
# Name: Date stamp bottom
self.footer = 0
def format(self, form=None, filler=None):
''' Parse and send the colored source.
'''
if form in ['snip','pre','code']:
self.addEnds = 0
else:
self.addEnds = 1
# Store line offsets in self.lines
self.lines = [0, 0]
pos = 0
# Gather lines
while 1:
pos = string.find(self.raw, '\n', pos) + 1
if not pos: break
self.lines.append(pos)
self.lines.append(len(self.raw))
# Wrap text in a filelike object
self.pos = 0
text = cStringIO.StringIO(self.raw)
# Html start
if self.addEnds:
self._doPageStart()
else:
self._doSnippetStart()
# Parse the source.
## Tokenize calls the __call__
## function for each token till done.
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]:]))
traceback.print_exc()
# Html end
if self.addEnds:
self._doPageEnd()
else:
self._doSnippetEnd()
def __call__(self, toktype, toktext, (srow,scol), (erow,ecol),
line):
''' Token handler. Order of evaluation is important do not
rearrange.
'''
style = ''
# 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
if self.ClassFlag or self.DefFlag:
# maps the color if it was a class or def name
if self.ClassFlag:
toktype = _CLASS
self.ClassFlag = 0
elif self.DefFlag:
toktype = _DEF
self.DefFlag = 0
else:
# Sets a flag if it was a class, def
# next token will be colored.
if toktext =='class':
self.ClassFlag = 1
elif toktext == 'def':
self.DefFlag = 1
#The last token was a @ so we must be a deco name
elif self.Decorator:
toktype = _DECORATOR_DEF
# reset the flag
self.Decorator = 0
# map token type to a color group
if token.LPAR <= toktype and toktype <= token.OP:
# trap decorators py2.4>
if toktext == '@':
toktype = _DECORATOR
#Colorize next token (decorator name)
self.Decorator = 1
else:
toktype = token.OP
elif toktype == token.NAME and keyword.iskeyword(toktext):
toktype = _KEYWORD
# Extended to seperate the diffrent string types..
# Plus raw and unicode types. (12 string types)
# Order of evaluation is important do not change.
if toktype == token.STRING:
# TRIPLE DOUBLE QUOTE's
if (toktext[:3].lower() == '"""'):
toktype = _TRIPLEDOUBLEQUOTE
elif (toktext[:4].lower() == 'r"""'):
toktype = _TRIPLEDOUBLEQUOTE_R
elif (toktext[:4].lower() == 'u"""'):
toktype = _TRIPLEDOUBLEQUOTE_U
# DOUBLE QUOTE's
elif (toktext[:1].lower() == '"'):
toktype = _DOUBLEQUOTE
elif (toktext[:2].lower() == 'r"'):
toktype = _DOUBLEQUOTE_R
elif (toktext[:2].lower() == 'u"'):
toktype = _DOUBLEQUOTE_U
# TRIPLE SINGLE QUOTE's
elif (toktext[:3].lower() == "'''"):
toktype = _TRIPLESINGLEQUOTE
elif (toktext[:4].lower() == "r'''"):
toktype = _TRIPLESINGLEQUOTE_R
elif (toktext[:4].lower() == "u'''"):
toktype = _TRIPLESINGLEQUOTE_U
# SINGLE QUOTE's
elif (toktext[:1].lower() == "'"):
toktype = _SINGLEQUOTE
elif (toktext[:2].lower() == "r'"):
toktype = _SINGLEQUOTE_R
elif (toktext[:2].lower() == "u'"):
toktype = _SINGLEQUOTE_U
# Exetended to seperate the diffrent comment types
elif toktype == tokenize.COMMENT:
if toktext[:2] == "##":
toktype = _DOUBLECOMMENT
# Extended errors to seperate decorators
elif toktype == token.ERRORTOKEN:
# trap decorators...<py2.3
if toktext == '@':
toktype = _DECORATOR
self.Decorator = 1
else:
# Error tokenizing ..red boxes
style = ' style="border: solid 1.5pt #FF0000;"'
# Get the colors from the dictionary for the standard tokens
color = self.colors.get(toktype, self.colors[_TEXT])
otherstart = ''
otherend = ''
splitpoint = color.find('#')
tags = color[:splitpoint].lower()
color = color[splitpoint:]
# Check for styles and set them if needed.
if 'b' in tags:#Bold
otherstart += '<b>'
otherend += '</b>'
if 'i' in tags:#Italics
otherstart += '<i>'
otherend += '</i>'
if 'u' in tags:#Underline
otherstart += '<u>'
otherend += '</u>'
# send text
self.out.write('<font color="%s"%s>%s' % (color, style,
otherstart))
self.out.write(cgi.escape(toktext))
self.out.write('%s</font>'% (otherend,))
return
def _doSnippetStart(self):
self.out.write('<pre><font face="Lucida Console, Courier
New">\n')
def _doSnippetEnd(self):
self.out.write('</pre>\n')
def _doPageStart(self):
self.out.write(
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2
Final//EN">\n')
self.out.write('<html><head><title>%s</title>\n'%
(self.title))
self.out.write('<!--This document created by %s %s on:
%s-->\n'%
(__title__,__version__,time.ctime()))
self.out.write('<meta http-equiv="Content-Type" \
content="text/html;charset=iso-8859-1" />\n')
# Get background color and check for styles and ignore all but
b,i,u
color = self.colors.get(_BACKGROUND, self.colors[_TEXT])
color = color[color.find('#'):]
if color[:1] != '#':
self.out.write('</head><body bgcolor="#000000">\n')
else:
self.out.write('</head><body bgcolor="%s">\n'% color)
# Write a little info at the top.
if self.header:
self._doPageHeader()
self.out.write('<pre><font face="Lucida Console, Courier
New">\n')
def _doPageHeader(self):
color = self.colors.get(token.NAME, self.colors[_TEXT])
color = color[color.find('#'):]
self.out.write(' <b><u><font color="%s">%s
%s</font></u></b>\n'%
(color, self.title, time.ctime()))
def _doPageFooter(self):
color = self.colors.get(token.NAME, self.colors[_TEXT])
color = color[color.find('#'):]
self.out.write(' <b><u><font color="%s">%s
%s</font></u></b>\n'%
(color, self.title,time.ctime()))
def _doPageEnd(self):
self.out.write('</pre>\n')
# Write a little info at the bottom
if self.footer:
self._doPageFooter()
# Write a little info in the web page source
self.out.write('<!--This document created by %s ver.%s on:
%s-->\n'%
(__title__,__version__,time.ctime()))
self.out.write('</body></html>\n')
if __name__ == '__main__':
Main()
# End of code
This version of PySourceColor supports decorators.
It looks like the syntax is there for a while, so I decided add them
in.
They parser code has also been extended to seperate all 12 types of
string.
I rewrote the _Null colorscheme to actually be null format.
Changed the old _Null to _Mono a black and white colorscheme for
printing.
Also added a few utility functions.
If you don't like the builtin colorschemes you should be able to write
a colorscheme that looks exactly like you want.
This is something that would be nice to have built into pydoc.
The links at the top-right of a pydoc page could point to a colorized
source and a plain text version
This program should run with Python 2.0 -> 2.4.
The code can be any version.
Just save to a file and run it.
It will parse itself into 6 diffrent webpages and show them.
M.E.Farmer
######################################################################
# PySourceColor
# A python source to colorized html converter.
# This does not create w3c valid html, but it works on every
# browser i've tried so far.(I.E.,Mozilla/Firefox,Opera,wxHTML).
# After experimenting with diffrent html vs CSS + html
# I settled on plain old html because it works!
# Too bad CSS is not supported everywhere yet.
# Hacked by M.E.Farmer Jr. 2004
# Python license
######################################################################
# Currently it can seperate and colorize:
# 12 types of strings
# 2 comment types
# numbers
# operators
# class / name
# def / name
# decorator / name
# keywords
# text
# And can use any combination of 3 styles:
# bold
# italic
# underline
######################################################################
# Recent changes:
# October 09, 2004:
# Added support for @decorators.
# Tested on 2.2 and 2.4
# Sepetember 25, 2004:
# Extended string handling:
# Unicode - single, singletriple, double, double triple
# Raw - single, singletriple, double, double triple
# regular - single, singletriple, double, double triple
#
######################################################################
import keyword, os, sys, traceback
import cgi, string, cStringIO
import token, tokenize, glob
import getopt, webbrowser, time
__title__ = 'PySourceColor'
__version__ = "1.7"
__date__ = '09 October 2004'
__author__ = "M.E.Farmer Jr."
__credits__ = '''This was originally submitted /written by
Jürgen Hermann to ASPN python recipes.
I hacked the parser to give me more control over tokens.
Python license M.E.Farmer 2004
'''
# Testing raw and unicode strings
# We do nothing with the value just look at colorizing
_ = (r'raw',r'''raw''',r"raw",r"""raw""")##Raw test
_ = (u'uni',u'''uni''',u"uni",u"""uni""")##Unicode test
# Do not edit
_DOUBLECOMMENT = token.NT_OFFSET + 1
_CLASS = token.NT_OFFSET + 2
_DEF = token.NT_OFFSET + 3
_TEXT = token.NT_OFFSET + 4
_KEYWORD = token.NT_OFFSET + 5
_SINGLEQUOTE = token.NT_OFFSET + 6
_SINGLEQUOTE_R = token.NT_OFFSET + 7
_SINGLEQUOTE_U = token.NT_OFFSET + 8
_DOUBLEQUOTE = token.NT_OFFSET + 9
_DOUBLEQUOTE_R = token.NT_OFFSET + 10
_DOUBLEQUOTE_U = token.NT_OFFSET + 11
_TRIPLESINGLEQUOTE = token.NT_OFFSET + 12
_TRIPLESINGLEQUOTE_R = token.NT_OFFSET + 13
_TRIPLESINGLEQUOTE_U = token.NT_OFFSET + 14
_TRIPLEDOUBLEQUOTE = token.NT_OFFSET + 15
_TRIPLEDOUBLEQUOTE_R = token.NT_OFFSET + 16
_TRIPLEDOUBLEQUOTE_U = token.NT_OFFSET + 17
_BACKGROUND = token.NT_OFFSET + 18
_DECORATOR = token.NT_OFFSET + 19
_DECORATOR_DEF = token.NT_OFFSET + 20
######################################################################
# Edit colors and styles to taste
# Create your own scheme, just copy one below , rename and edit.
# Color is rgb hex and must be specified. #RRGGBB
# Styles are optional: b=bold, i=italic, u=underline
# Colorscheme names must start with an underscore: _MyColor
# Underscore will not be used on command line (--color= Pythonwin)
######################################################################
_Null = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: '#000000',# Decorators
_DECORATOR: '#000000',# @
token.NAME: '#000000',# All Text
token.NUMBER: '#000000',# 0->10
token.OP: '#000000',# ()<>=!.:;^>%, etc...
tokenize.COMMENT: '#000000',# There are 2 types of comment
_DOUBLECOMMENT: '#000000',## Like this
_CLASS: '#000000',# Class name
_DEF: '#000000',# Def name
_KEYWORD: '#000000',# Python keywords
_SINGLEQUOTE: '#000000',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#000000',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#000000',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#000000',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#000000',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#000000',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#000000',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#000000',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#000000',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#000000',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#000000',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#000000',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
_Mono = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: 'bu#000000',# Decorators
_DECORATOR: 'b#000000',# @
token.NAME: '#000000',# All Text
token.NUMBER: 'b#000000',# 0->10
token.OP: 'b#000000',# ()<>=!.:;^>%, etc...
tokenize.COMMENT: 'i#000000',# There are 2 types of comment
_DOUBLECOMMENT: '#000000',## Like this
_CLASS: 'bu#000000',# Class name
_DEF: 'b#000000',# Def name
_KEYWORD: 'b#000000',# Python keywords
_SINGLEQUOTE: '#000000',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#000000',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#000000',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#000000',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#000000',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#000000',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#000000',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#000000',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#000000',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: 'i#000000',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R:'i#000000',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U:'i#000000',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
_Dark = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#FFFFFF',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: 'b#FFBBAA',# Decorators
_DECORATOR: 'b#CC5511',# @
token.NAME: '#ffffff',# All Text
token.NUMBER: '#FF0000',# 0->10
token.OP: 'b#FAF785',# Operators ()<>=!.:;^>%,
etc...
tokenize.COMMENT: 'i#45FCA0',# There are 2 types of comment
_DOUBLECOMMENT: '#A7C7A9',## Like this
_CLASS: 'b#B599FD',# Class name
_DEF: 'b#EBAE5C',# Def name
_KEYWORD: 'b#8680FF',# Python keywords
_SINGLEQUOTE: '#F8BAFE',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#F8BAFE',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#F8BAFE',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#FF80C0',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#FF80C0',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#FF80C0',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#FF9595',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#FF9595',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#FF9595',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#B3FFFF',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#B3FFFF',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#B3FFFF',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#000000',# Page background color
}
_Lite = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: 'b#BB4422',# Decorators
_DECORATOR: 'b#3333af',# @
token.NAME: '#000000',# All Text
token.NUMBER: '#FF2200',# 0->10
token.OP: 'b#303000',# Operators ()<>=!.:;^>%,
etc...
tokenize.COMMENT: '#007F00',# There are 2 types of comment
_DOUBLECOMMENT: '#606060',## Like this
_CLASS: '#0000FF',# Class name
_DEF: 'b#9C7A00',# Def name
_KEYWORD: 'b#0000AF',# Python keywords
_SINGLEQUOTE: '#600080',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#600080',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#600080',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#A0008A',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#A0008A',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#A0008A',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#4488BB',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#4488BB',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#4488BB',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#2299BB',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#2299BB',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#2299BB',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
_Idle = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: '#900090',# Decorators
_DECORATOR: '#000000',# @
token.NAME: '#000000',# All Text
token.NUMBER: '#000000',# 0->10
token.OP: '#000000',# Operators ()<>=!.:;^>%,
etc...
tokenize.COMMENT: '#DD0000',# There are 2 types of comment
_DOUBLECOMMENT: '#DD0000',## Like this
_CLASS: '#0000FF',# Class name
_DEF: '#0000FF',# Def name
_KEYWORD: '#FF7700',# Python keywords
_SINGLEQUOTE: '#00AA00',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#00AA00',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#00AA00',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#00AA00',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#00AA00',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#00AA00',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#00AA00',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#00AA00',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#00AA00',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#00AA00',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#00AA00',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#00AA00',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
_PythonWin = {
token.ERRORTOKEN: '#FF8080',# no edit
token.STRING: '#000000',# no edit
_TEXT: '#000000',# no edit
_DECORATOR_DEF: 'b#303030',# Decorators
_DECORATOR: 'b#DD0080',# @
token.NAME: '#303030',# All Text
token.NUMBER: '#008080',# 0->10
token.OP: '#000000',# ()<>=!.:;^>%, etc...
tokenize.COMMENT: '#007F00',# There are 2 types of comment
_DOUBLECOMMENT: '#7F7F7F',## Like this
_CLASS: 'b#0000FF',# Class name
_DEF: 'b#007F7F',# Def name
_KEYWORD: 'b#000080',# Python keywords
_SINGLEQUOTE: '#808000',# 'SINGLEQUOTE'
_SINGLEQUOTE_R: '#808000',# r'SINGLEQUOTE'
_SINGLEQUOTE_U: '#808000',# u'SINGLEQUOTE'
_DOUBLEQUOTE: '#808000',# "DOUBLEQUOTE"
_DOUBLEQUOTE_R: '#808000',# r"DOUBLEQUOTE"
_DOUBLEQUOTE_U: '#808000',# u"DOUBLEQUOTE"
_TRIPLESINGLEQUOTE: '#808000',# '''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_R: '#808000',# r'''TRIPLESINGLEQUOTE'''
_TRIPLESINGLEQUOTE_U: '#808000',# u'''TRIPLESINGLEQUOTE'''
_TRIPLEDOUBLEQUOTE: '#808000',# """TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_R: '#808000',# r"""TRIPLEDOUBLEQUOTE"""
_TRIPLEDOUBLEQUOTE_U: '#808000',# u"""TRIPLEDOUBLEQUOTE"""
_BACKGROUND: '#FFFFFF',# Page background color
}
DefaultColorScheme= _Dark
##################################################################################
def Usage():
"""
_______________________________________________________________________________
Example usage:
# To colorize all .py,.pyw files in cwdir you can also use: . or _
python PySourceColor.py -i .
# Using long options w/ =
python PySourceColor.py --in=c:/myDir/my.py --out=c:/myDir
--color=Lite --show
# Using short options w/out =
python PySourceColor.py -i c:/myDir/ -c Idle
# Using any mix
python PySourceColor.py --in _ -o=c:/myDir --show
-------------------------------------------------------------------------------
This module is designed to colorize python source code.
It is a hacked version of MoinMoin python parser recipe.
-h or --help
Display this help message.
-i or --in
Input file or dir. (Use any of these for the cwdir . , _ ,
this)
-o or --out
Optional, output dir for the colorized source
default: output dir is input dir.
-c or --color
Optional. Null, Dark, Lite, Idle, Pythonwin, create your own!
default: Dark
-s or --show
Optional, Show webpage after creation.
default: no show
_______________________________________________________________________________
"""
print Usage.__doc__
def Main():
'''Gathers the command line arguments
and try to do something reasonable with them.
'''
try:
# try to get command line args
opts, args = getopt.getopt(sys.argv[1:],
"hsi:c:", ["help", "show", "input=", "out=",
"color="])
except getopt.GetoptError:
# on error print help information and exit:
Usage()
sys.exit(2)
# init some names
input = None
output = None
scheme = None
show = 0
# if we have args then process them
for o, a in opts:
if o in ("-h", "--help"):
Usage()
sys.exit()
if o in ("-o", "--out"):
output = a
if o in ("-i", "--input"):
input = a
if input in('.','_', 'this'):
input = os.getcwd()
if o in ("-s", "--show"):
show = 1
if o in ("-c", "--color"):
try:
#Fix this if you see a weakness
scheme = eval('_%s'%a)
except:
traceback.print_exc()
if input == None:
# if there was no input specified then we try to
# parse ourselves and do it in diffrent flavors.
fi = sys.argv[0]
Path2File(fi, '/MyDir/null', _Null, 1)
Path2File(fi, '/MyDir/mono', _Mono, 1)
Path2File(fi, '/MyDir/lite', _Lite, 1)
Path2File(fi, '/MyDir/dark', _Dark, 1)
Path2File(fi, '/MyDir/idle', _Idle, 1)
Path2File(fi, '/MyDir/pythonwin', _PythonWin, 1)
else:
# if there was at least an input given we can proceed
Convert(input, output, scheme, show)
import os
def Str2Html(sourcestring, title='', form=None, colors=None):
'''Converts a code(string) to colorized HTML
and prints to sys.stdout
form='pre','code',or'snip' for "<pre>yourcode</pre>" only
colors=_Null,_Mono,_Lite,_Dark,_Idle,or _PythonWin
example:
Str2Html("""x, y = os.path.split(myPath)
if os.path.isdir(y):
print'No file' """,form='snip',colors=_Lite)
'''
Parser(sourcestring, colors, title).format(form)
def Path2Html(sourcepath, form=None, colors=None):
'''Converts code(file) to colorized HTML
and prints to sys.stdout
form='pre','code',or'snip' for "<pre>yourcode</pre>" only
colors=_Null,_Mono,_Lite,_Dark,_Idle,or _PythonWin
'''
source = open(sourcepath).read()
Parser(source, colors, sourcepath).format(form)
def Convert(sourcePath, outdir=None, colors=None, show=0):
''' Converts all python source in the given directory to html
file/s.
'''
c=0
# If it is a filename then Path2File
if not os.path.isdir(sourcePath):
if os.path.isfile(sourcePath):
c+=1
Path2File(sourcePath, outdir, colors, show)
# If we pass in a dir we need to walkdir for files.
# Then we need to colorize them with Path2File
else:
fileList = WalkDir(sourcePath)
if fileList != None:
for i in fileList:
c+=1
Path2File(i, outdir, colors, show)
print'Completed colorizing %s source files.'% str(c)
else:
print"No files to convert in dir."
def Path2File(sourcePath, outdir=None, colors=None, show=0):
''' Converts python source to html file.
'''
print" Converting %s into HTML" % sourcePath
# If no outdir is given we use the sourcePath
if outdir == None:
htmlPath = sourcePath + '.html'
else:
# If we do give an outdir, and it does
# not exist , it will be created.
if not os.path.isdir(outdir):
os.makedirs(outdir)
sourceName = os.path.basename(sourcePath)
htmlPath = os.path.join(outdir,sourceName)+'.html'
print " Output to %s"%htmlPath
# Open the text and do the parsing.
source = open(sourcePath).read()
Parser(source, colors, sourcePath, open(htmlPath, 'wt')).format()
if show:
# load HTML page into the default web browser.
# slower than os.startfile or os.system, but more universal
try:
webbrowser.open_new(htmlPath)
except:
traceback.print_exc()
return htmlPath
def WalkDir(dir):
'''Return a list of .py and .pyw files from a given directory.
This function can be written as a generator Python 2.3, or a
genexp
in Python 2.4. But 2.2 and 2.1 would be left out....
'''
# Get a list of files that match *.py*
GLOB_PATTERN = os.path.join(dir, "*.[p][y]*")
pathlist = glob.glob(GLOB_PATTERN)
# Now filter out all but py and pyw
filterlist = [x for x in pathlist
if x.endswith('.py')
or x.endswith('.pyw')]
if filterlist != []:
# if we have a list send it
return filterlist
else:
return None
class Parser:
""" MoinMoin python parser heavily chopped
"""
def __init__(self, raw, colors=None, title='', out=sys.stdout):
''' Store the source text & set some flags.
'''
if colors == None:
colors = DefaultColorScheme
self.raw = string.strip(string.expandtabs(raw))
self.out = out
self.title = os.path.basename(title)
self.ClassFlag = 0
self.DefFlag = 0
self.Decorator = 0
self.colors = colors
# Name: Date stamp top
self.header = 0
# Name: Date stamp bottom
self.footer = 0
def format(self, form=None, filler=None):
''' Parse and send the colored source.
'''
if form in ['snip','pre','code']:
self.addEnds = 0
else:
self.addEnds = 1
# Store line offsets in self.lines
self.lines = [0, 0]
pos = 0
# Gather lines
while 1:
pos = string.find(self.raw, '\n', pos) + 1
if not pos: break
self.lines.append(pos)
self.lines.append(len(self.raw))
# Wrap text in a filelike object
self.pos = 0
text = cStringIO.StringIO(self.raw)
# Html start
if self.addEnds:
self._doPageStart()
else:
self._doSnippetStart()
# Parse the source.
## Tokenize calls the __call__
## function for each token till done.
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]:]))
traceback.print_exc()
# Html end
if self.addEnds:
self._doPageEnd()
else:
self._doSnippetEnd()
def __call__(self, toktype, toktext, (srow,scol), (erow,ecol),
line):
''' Token handler. Order of evaluation is important do not
rearrange.
'''
style = ''
# 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
if self.ClassFlag or self.DefFlag:
# maps the color if it was a class or def name
if self.ClassFlag:
toktype = _CLASS
self.ClassFlag = 0
elif self.DefFlag:
toktype = _DEF
self.DefFlag = 0
else:
# Sets a flag if it was a class, def
# next token will be colored.
if toktext =='class':
self.ClassFlag = 1
elif toktext == 'def':
self.DefFlag = 1
#The last token was a @ so we must be a deco name
elif self.Decorator:
toktype = _DECORATOR_DEF
# reset the flag
self.Decorator = 0
# map token type to a color group
if token.LPAR <= toktype and toktype <= token.OP:
# trap decorators py2.4>
if toktext == '@':
toktype = _DECORATOR
#Colorize next token (decorator name)
self.Decorator = 1
else:
toktype = token.OP
elif toktype == token.NAME and keyword.iskeyword(toktext):
toktype = _KEYWORD
# Extended to seperate the diffrent string types..
# Plus raw and unicode types. (12 string types)
# Order of evaluation is important do not change.
if toktype == token.STRING:
# TRIPLE DOUBLE QUOTE's
if (toktext[:3].lower() == '"""'):
toktype = _TRIPLEDOUBLEQUOTE
elif (toktext[:4].lower() == 'r"""'):
toktype = _TRIPLEDOUBLEQUOTE_R
elif (toktext[:4].lower() == 'u"""'):
toktype = _TRIPLEDOUBLEQUOTE_U
# DOUBLE QUOTE's
elif (toktext[:1].lower() == '"'):
toktype = _DOUBLEQUOTE
elif (toktext[:2].lower() == 'r"'):
toktype = _DOUBLEQUOTE_R
elif (toktext[:2].lower() == 'u"'):
toktype = _DOUBLEQUOTE_U
# TRIPLE SINGLE QUOTE's
elif (toktext[:3].lower() == "'''"):
toktype = _TRIPLESINGLEQUOTE
elif (toktext[:4].lower() == "r'''"):
toktype = _TRIPLESINGLEQUOTE_R
elif (toktext[:4].lower() == "u'''"):
toktype = _TRIPLESINGLEQUOTE_U
# SINGLE QUOTE's
elif (toktext[:1].lower() == "'"):
toktype = _SINGLEQUOTE
elif (toktext[:2].lower() == "r'"):
toktype = _SINGLEQUOTE_R
elif (toktext[:2].lower() == "u'"):
toktype = _SINGLEQUOTE_U
# Exetended to seperate the diffrent comment types
elif toktype == tokenize.COMMENT:
if toktext[:2] == "##":
toktype = _DOUBLECOMMENT
# Extended errors to seperate decorators
elif toktype == token.ERRORTOKEN:
# trap decorators...<py2.3
if toktext == '@':
toktype = _DECORATOR
self.Decorator = 1
else:
# Error tokenizing ..red boxes
style = ' style="border: solid 1.5pt #FF0000;"'
# Get the colors from the dictionary for the standard tokens
color = self.colors.get(toktype, self.colors[_TEXT])
otherstart = ''
otherend = ''
splitpoint = color.find('#')
tags = color[:splitpoint].lower()
color = color[splitpoint:]
# Check for styles and set them if needed.
if 'b' in tags:#Bold
otherstart += '<b>'
otherend += '</b>'
if 'i' in tags:#Italics
otherstart += '<i>'
otherend += '</i>'
if 'u' in tags:#Underline
otherstart += '<u>'
otherend += '</u>'
# send text
self.out.write('<font color="%s"%s>%s' % (color, style,
otherstart))
self.out.write(cgi.escape(toktext))
self.out.write('%s</font>'% (otherend,))
return
def _doSnippetStart(self):
self.out.write('<pre><font face="Lucida Console, Courier
New">\n')
def _doSnippetEnd(self):
self.out.write('</pre>\n')
def _doPageStart(self):
self.out.write(
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2
Final//EN">\n')
self.out.write('<html><head><title>%s</title>\n'%
(self.title))
self.out.write('<!--This document created by %s %s on:
%s-->\n'%
(__title__,__version__,time.ctime()))
self.out.write('<meta http-equiv="Content-Type" \
content="text/html;charset=iso-8859-1" />\n')
# Get background color and check for styles and ignore all but
b,i,u
color = self.colors.get(_BACKGROUND, self.colors[_TEXT])
color = color[color.find('#'):]
if color[:1] != '#':
self.out.write('</head><body bgcolor="#000000">\n')
else:
self.out.write('</head><body bgcolor="%s">\n'% color)
# Write a little info at the top.
if self.header:
self._doPageHeader()
self.out.write('<pre><font face="Lucida Console, Courier
New">\n')
def _doPageHeader(self):
color = self.colors.get(token.NAME, self.colors[_TEXT])
color = color[color.find('#'):]
self.out.write(' <b><u><font color="%s">%s
%s</font></u></b>\n'%
(color, self.title, time.ctime()))
def _doPageFooter(self):
color = self.colors.get(token.NAME, self.colors[_TEXT])
color = color[color.find('#'):]
self.out.write(' <b><u><font color="%s">%s
%s</font></u></b>\n'%
(color, self.title,time.ctime()))
def _doPageEnd(self):
self.out.write('</pre>\n')
# Write a little info at the bottom
if self.footer:
self._doPageFooter()
# Write a little info in the web page source
self.out.write('<!--This document created by %s ver.%s on:
%s-->\n'%
(__title__,__version__,time.ctime()))
self.out.write('</body></html>\n')
if __name__ == '__main__':
Main()
# End of code