Python To HTML
Na verdade, isso não é exatamente uma receita. É uma pequena aplicação que imaginei que pudesse ser útil para alguns e não encontrei lugar melhor para colocar.
É um software simples que gera a partir do seu código Python, o código HTML para exibi-lo com coloração de sintaxe. A parte do código para a colorização foi retirada do proprio Moin. A interface para selecionar as cores e arquivos usa Tkinter.
Código
1 import Tkinter
2 import tkColorChooser
3 import tkFileDialog
4 from Tkconstants import *
5
6 import cgi
7 import sys
8 import cStringIO
9 import keyword
10 import token
11 import tokenize
12
13
14 _KEYWORD = token.NT_OFFSET + 1
15 _TEXT = token.NT_OFFSET + 2
16
17
18 class Parser:
19 """ Send colored python source.
20 """
21
22 def __init__(self, raw, colors, out = sys.stdout):
23 """ Store the source text.
24 """
25 self.raw = raw.expandtabs().strip()
26 self.colors = colors
27 self.out = out
28
29 def format(self, formatter, form):
30 """ Parse and send the colored source.
31 """
32 # store line offsets in self.lines
33 self.lines = [0, 0]
34 pos = 0
35 while 1:
36 pos = self.raw.find('\n', pos) + 1
37 if not pos: break
38 self.lines.append(pos)
39 self.lines.append(len(self.raw))
40
41 # parse the source and write it
42 self.pos = 0
43 text = cStringIO.StringIO(self.raw)
44 self.out.write('<pre><font face="Lucida,Courier New">')
45 try:
46 tokenize.tokenize(text.readline, self)
47 except tokenize.TokenError, ex:
48 msg = ex[0]
49 line = ex[1][0]
50 self.out.write("<h3>ERROR: %s</h3>%s\n" % (
51 msg, self.raw[self.lines[line]:]))
52 self.out.write('</font></pre>')
53
54 def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
55 """ Token handler.
56 """
57 if 0:
58 print "type", toktype, token.tok_name[toktype], "text", toktext,
59 print "start", srow,scol, "end", erow,ecol, "<br>"
60
61 # calculate new positions
62 oldpos = self.pos
63 newpos = self.lines[srow] + scol
64 self.pos = newpos + len(toktext)
65
66 # handle newlines
67 if toktype in [token.NEWLINE, tokenize.NL]:
68 self.out.write('\n')
69 return
70
71 # send the original whitespace, if needed
72 if newpos > oldpos:
73 self.out.write(self.raw[oldpos:newpos])
74
75 # skip indenting tokens
76 if toktype in [token.INDENT, token.DEDENT]:
77 self.pos = newpos
78 return
79
80 # map token type to a color group
81 if token.LPAR <= toktype and toktype <= token.OP:
82 toktype = token.OP
83 elif toktype == token.NAME and keyword.iskeyword(toktext):
84 toktype = _KEYWORD
85 color = self.colors.get(toktype, self.colors[_TEXT])
86
87 style = ''
88 if toktype == token.ERRORTOKEN:
89 style = ' style="border: solid 1.5pt #FF0000;"'
90
91 # send text
92 self.out.write('<font color="%s"%s>' % (color, style))
93 self.out.write(cgi.escape(toktext))
94 self.out.write('</font>')
95
96
97
98 class MainWindow(Tkinter.Tk):
99 def __init__(self):
100 Tkinter.Tk.__init__(self)
101 self.title("TkColorizer")
102 self.colors = {"Numbers":"#0080C0",
103 "Operators":"#0000C0",
104 "Strings":"#004080",
105 "Comments":"#008000",
106 "Names":"#000000",
107 "Errors":"#FF8080",
108 "Keywords":"#C00000",
109 "Text":"#000000"}
110 self.build()
111
112 def build(self):
113 lbody = Tkinter.Frame(self)
114 for k, v in self.colors.items():
115 b = Tkinter.Label(lbody, text=k, padx=30, bg=v)
116 b.pack(expand=1, fill=BOTH)
117 b.bind("<Button-1>", self.changeColor)
118 self.setFg(b)
119 lbody.pack(expand=1, fill=BOTH, side=TOP)
120
121 rbody = Tkinter.Frame(self)
122 self.input = Tkinter.StringVar()
123 self.output = Tkinter.StringVar()
124 Tkinter.Label(rbody, text="Input:").grid(row=0, column=0)
125 Tkinter.Entry(rbody, textvariable=self.input).grid(row=0, column=1)
126 Tkinter.Button(rbody, text="...", command=self.askinput,
127 bd=1).grid(row=0, column=2)
128 Tkinter.Label(rbody, text="Output:").grid(row=1, column=0)
129 Tkinter.Entry(rbody, textvariable=self.output).grid(row=1, column=1)
130 Tkinter.Button(rbody, text="...", command=self.askoutput,
131 bd=1).grid(row=1, column=2)
132 Tkinter.Button(rbody, text="Generate HTML",
133 command=self.done).grid(row=2, column=1)
134 rbody.pack(expand=1, fill=BOTH, side=BOTTOM)
135
136 def done(self, event=None):
137 raw = open(self.input.get()).read()
138 out = open(self.output.get(), "wt")
139 colors = {token.NUMBER:self.colors['Numbers'],
140 token.OP:self.colors['Operators'],
141 token.STRING:self.colors['Strings'],
142 tokenize.COMMENT:self.colors['Comments'],
143 token.NAME:self.colors['Names'],
144 token.ERRORTOKEN:self.colors['Errors'],
145 _KEYWORD:self.colors['Keywords'],
146 _TEXT:self.colors['Text']
147 }
148
149 Parser(raw, colors, out).format(None, None)
150 self.destroy()
151
152 def askinput(self, event=None):
153 ft = [("Python source file", "*.py"),
154 ("All files", "*.*")]
155 file = tkFileDialog.askopenfilename(parent=self, filetypes=ft)
156 if file:
157 self.input.set(file)
158
159 def askoutput(self, event=None):
160 ft = [("HTML file", "*.html"),
161 ("HTML file", "*.htm"),
162 ("All files", "*.*")]
163 file = tkFileDialog.asksaveasfilename(parent=self, filetypes=ft)
164 if file:
165 self.output.set(file)
166
167 def setFg(self, button):
168 bg = int(button['bg'][1:], 16)
169 set = [(bg >> 8*x) % 256 for x in (0, 1, 2)]
170 if sum(set)/3 < 85:
171 button['fg'] = "#FFFFFF"
172 else:
173 button['fg'] = "#000000"
174
175 def changeColor(self, event=None):
176 w = event.widget
177 k = w['text']
178 c = w['bg']
179 a, b = tkColorChooser.askcolor(parent=self, initialcolor=c, title=k)
180 if b is not None:
181 w['bg'] = b
182 self.colors[k] = b
183 self.setFg(w)
184
185
186 if __name__ == "__main__":
187 root = MainWindow()
188 root.mainloop()
Volta para CookBook.