root/Zope2/PortalTransforms/trunk/transforms/python.py

Revision 19076, 4.4 kB (checked in by sfermigier, 6 years ago)

Initial revision

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 """
2 Original code from active state recipe
3         'Colorize Python source using the built-in tokenizer'
4
5 ----------------------------------------------------------------------------
6      MoinMoin - Python Source Parser
7
8  This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
9  Python source code to HTML markup, rendering comments, keywords, operators,
10  numeric and string literals in different colors.
11
12  It shows how to use the built-in keyword, token and tokenize modules
13  to scan Python source code and re-emit it with no changes to its
14  original formatting (which is the hard part).
15 """
16 __revision__ = '$Id$'
17
18 import string
19 import keyword, token, tokenize
20 from cStringIO import StringIO
21
22 from Products.PortalTransforms.interfaces import itransform
23
24
25 ## Python Source Parser #####################################################
26
27 _KEYWORD = token.NT_OFFSET + 1
28 _TEXT    = token.NT_OFFSET + 2
29
30 class Parser:
31     """ Send colored python source.
32     """
33
34     def __init__(self, raw, tags, out):
35         """ Store the source text.
36         """
37         self.raw = string.strip(string.expandtabs(raw))
38         self.out = out
39         self.tags = tags
40
41     def format(self):
42         """ Parse and send the colored source.
43         """
44         # store line offsets in self.lines
45         self.lines = [0, 0]
46         pos = 0
47         while 1:
48             pos = string.find(self.raw, '\n', pos) + 1
49             if not pos: break
50             self.lines.append(pos)
51         self.lines.append(len(self.raw))
52
53         # parse the source and write it
54         self.pos = 0
55         text = StringIO(self.raw)
56         self.out.write('<pre class="python">\n')
57         try:
58             tokenize.tokenize(text.readline, self)
59         except tokenize.TokenError, ex:
60             msg = ex[0]
61             line = ex[1][0]
62             self.out.write("<h5 class='error>'ERROR: %s%s</h5>" % (
63                 msg, self.raw[self.lines[line]:]))
64         self.out.write('\n</pre>\n')
65
66     def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
67         """ Token handler.
68         """
69         #print "type", toktype, token.tok_name[toktype], "text", toktext,
70         #print "start", srow,scol, "end", erow,ecol, "<br>"
71
72         ## calculate new positions
73         oldpos = self.pos
74         newpos = self.lines[srow] + scol
75         self.pos = newpos + len(toktext)
76
77         ## handle newlines
78         if toktype in [token.NEWLINE, tokenize.NL]:
79             self.out.write('\n')
80             return
81
82         ## send the original whitespace, if needed
83         if newpos > oldpos:
84             self.out.write(self.raw[oldpos:newpos])
85
86         ## skip indenting tokens
87         if toktype in [token.INDENT, token.DEDENT]:
88             self.pos = newpos
89             return
90
91         ## map token type to a group
92         if token.LPAR <= toktype and toktype <= token.OP:
93             toktype = 'OP'
94         elif toktype == token.NAME and keyword.iskeyword(toktext):
95             toktype = 'KEYWORD'
96         else:
97             toktype = tokenize.tok_name[toktype]
98
99         open_tag = self.tags.get('OPEN_'+toktype, self.tags['OPEN_TEXT'])
100         close_tag = self.tags.get('CLOSE_'+toktype, self.tags['CLOSE_TEXT'])
101
102         ## send text
103         self.out.write(open_tag)
104         self.out.write(toktext)
105         self.out.write(close_tag)
106
107
108
109 class PythonTransform:
110     """Colorize Python source files
111     """
112     __implements__ = itransform
113
114     __name__ = "python_to_html"
115     inputs  = ("text/x-python",)
116     output = "text/html"
117
118     config = {
119         'OPEN_NUMBER':       '<font color="#0080C0">',
120         'CLOSE_NUMBER':      '</font>',
121         'OPEN_OP':           '<font color="#0000C0">',
122         'CLOSE_OP':          '</font>',
123         'OPEN_STRING':       '<font color="#004080">',
124         'CLOSE_STRING':      '</font>',
125         'OPEN_COMMENT':      '<font color="#008000">',
126         'CLOSE_COMMENT':      '</font>',
127         'OPEN_NAME':         '<font color="#000000">',
128         'CLOSE_NAME':        '</font>',
129         'OPEN_ERRORTOKEN':   '<font color="#FF8080">',
130         'CLOSE_ERRORTOKEN':  '</font>',
131         'OPEN_KEYWORD':      '<font color="#C00000">',
132         'CLOSE_KEYWORD':     '</font>',
133         'OPEN_TEXT':         '',
134         'CLOSE_TEXT':        '',
135         }
136
137     def name(self):
138         return self.__name__
139
140     def convert(self, orig, data, **kwargs):
141         dest = StringIO()
142         Parser(orig, self.config, dest).format()
143         data.setData(dest.getvalue())
144         return data
145
146
147 def register():
148     return PythonTransform()
Note: See TracBrowser for help on using the browser.