root/galaxy-central/eggs/Mako-0.2.5-py2.6.egg/mako/pygen.py @ 3

リビジョン 3, 9.5 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# pygen.py
2# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com
3#
4# This module is part of Mako and is released under
5# the MIT License: http://www.opensource.org/licenses/mit-license.php
6
7"""utilities for generating and formatting literal Python code."""
8
9import re, string
10from StringIO import StringIO
11
12class PythonPrinter(object):
13    def __init__(self, stream):
14        # indentation counter
15        self.indent = 0
16       
17        # a stack storing information about why we incremented
18        # the indentation counter, to help us determine if we
19        # should decrement it
20        self.indent_detail = []
21       
22        # the string of whitespace multiplied by the indent
23        # counter to produce a line
24        self.indentstring = "    "
25       
26        # the stream we are writing to
27        self.stream = stream
28       
29        # a list of lines that represents a buffered "block" of code,
30        # which can be later printed relative to an indent level
31        self.line_buffer = []
32       
33        self.in_indent_lines = False
34       
35        self._reset_multi_line_flags()
36
37    def write(self, text):
38        self.stream.write(text)
39       
40    def write_indented_block(self, block):
41        """print a line or lines of python which already contain indentation.
42       
43        The indentation of the total block of lines will be adjusted to that of
44        the current indent level."""
45        self.in_indent_lines = False
46        for l in re.split(r'\r?\n', block):
47            self.line_buffer.append(l)
48   
49    def writelines(self, *lines):
50        """print a series of lines of python."""
51        for line in lines:
52            self.writeline(line)
53               
54    def writeline(self, line):
55        """print a line of python, indenting it according to the current indent level.
56       
57        this also adjusts the indentation counter according to the content of the line."""
58
59        if not self.in_indent_lines:
60            self._flush_adjusted_lines()
61            self.in_indent_lines = True
62
63        decreased_indent = False
64   
65        if (line is None or
66            re.match(r"^\s*#",line) or
67            re.match(r"^\s*$", line)
68            ):
69            hastext = False
70        else:
71            hastext = True
72
73        is_comment = line and len(line) and line[0] == '#'
74       
75        # see if this line should decrease the indentation level
76        if (not decreased_indent and
77            not is_comment and
78            (not hastext or self._is_unindentor(line))
79            ):
80           
81            if self.indent > 0:
82                self.indent -=1
83                # if the indent_detail stack is empty, the user
84                # probably put extra closures - the resulting
85                # module wont compile. 
86                if len(self.indent_detail) == 0: 
87                    raise "Too many whitespace closures"
88                self.indent_detail.pop()
89       
90        if line is None:
91            return
92               
93        # write the line
94        self.stream.write(self._indent_line(line) + "\n")
95       
96        # see if this line should increase the indentation level.
97        # note that a line can both decrase (before printing) and
98        # then increase (after printing) the indentation level.
99
100        if re.search(r":[ \t]*(?:#.*)?$", line):
101            # increment indentation count, and also
102            # keep track of what the keyword was that indented us,
103            # if it is a python compound statement keyword
104            # where we might have to look for an "unindent" keyword
105            match = re.match(r"^\s*(if|try|elif|while|for)", line)
106            if match:
107                # its a "compound" keyword, so we will check for "unindentors"
108                indentor = match.group(1)
109                self.indent +=1
110                self.indent_detail.append(indentor)
111            else:
112                indentor = None
113                # its not a "compound" keyword.  but lets also
114                # test for valid Python keywords that might be indenting us,
115                # else assume its a non-indenting line
116                m2 = re.match(r"^\s*(def|class|else|elif|except|finally)", line)
117                if m2:
118                    self.indent += 1
119                    self.indent_detail.append(indentor)
120
121    def close(self):
122        """close this printer, flushing any remaining lines."""
123        self._flush_adjusted_lines()
124   
125    def _is_unindentor(self, line):
126        """return true if the given line is an 'unindentor', relative to the last 'indent' event received."""
127               
128        # no indentation detail has been pushed on; return False
129        if len(self.indent_detail) == 0:
130            return False
131
132        indentor = self.indent_detail[-1]
133       
134        # the last indent keyword we grabbed is not a
135        # compound statement keyword; return False
136        if indentor is None:
137            return False
138       
139        # if the current line doesnt have one of the "unindentor" keywords,
140        # return False
141        match = re.match(r"^\s*(else|elif|except|finally).*\:", line)
142        if not match:
143            return False
144       
145        # whitespace matches up, we have a compound indentor,
146        # and this line has an unindentor, this
147        # is probably good enough
148        return True
149       
150        # should we decide that its not good enough, heres
151        # more stuff to check.
152        #keyword = match.group(1)
153       
154        # match the original indent keyword
155        #for crit in [
156        #   (r'if|elif', r'else|elif'),
157        #   (r'try', r'except|finally|else'),
158        #   (r'while|for', r'else'),
159        #]:
160        #   if re.match(crit[0], indentor) and re.match(crit[1], keyword): return True
161       
162        #return False
163       
164    def _indent_line(self, line, stripspace = ''):
165        """indent the given line according to the current indent level.
166       
167        stripspace is a string of space that will be truncated from the start of the line
168        before indenting."""
169        return re.sub(r"^%s" % stripspace, self.indentstring * self.indent, line)
170
171    def _reset_multi_line_flags(self):
172        """reset the flags which would indicate we are in a backslashed or triple-quoted section."""
173        (self.backslashed, self.triplequoted) = (False, False)
174       
175    def _in_multi_line(self, line):
176        """return true if the given line is part of a multi-line block, via backslash or triple-quote."""
177        # we are only looking for explicitly joined lines here,
178        # not implicit ones (i.e. brackets, braces etc.).  this is just
179        # to guard against the possibility of modifying the space inside
180        # of a literal multiline string with unfortunately placed whitespace
181         
182        current_state = (self.backslashed or self.triplequoted)
183                       
184        if re.search(r"\\$", line):
185            self.backslashed = True
186        else:
187            self.backslashed = False
188           
189        triples = len(re.findall(r"\"\"\"|\'\'\'", line))
190        if triples == 1 or triples % 2 != 0:
191            self.triplequoted = not self.triplequoted
192           
193        return current_state
194
195    def _flush_adjusted_lines(self):
196        stripspace = None
197        self._reset_multi_line_flags()
198       
199        for entry in self.line_buffer:
200            if self._in_multi_line(entry):
201                self.stream.write(entry + "\n")
202            else:
203                entry = string.expandtabs(entry)
204                if stripspace is None and re.search(r"^[ \t]*[^# \t]", entry):
205                    stripspace = re.match(r"^([ \t]*)", entry).group(1)
206                self.stream.write(self._indent_line(entry, stripspace) + "\n")
207           
208        self.line_buffer = []
209        self._reset_multi_line_flags()
210
211
212def adjust_whitespace(text):
213    """remove the left-whitespace margin of a block of Python code."""
214    state = [False, False]
215    (backslashed, triplequoted) = (0, 1)
216
217    def in_multi_line(line):
218        start_state = (state[backslashed] or state[triplequoted])
219       
220        if re.search(r"\\$", line):
221            state[backslashed] = True
222        else:
223            state[backslashed] = False
224       
225        def match(reg, t):
226            m = re.match(reg, t)
227            if m:
228                return m, t[len(m.group(0)):]
229            else:
230                return None, t
231               
232        while line:
233            if state[triplequoted]:
234                m, line = match(r"%s" % state[triplequoted], line)
235                if m:
236                    state[triplequoted] = False
237                else:
238                    m, line = match(r".*?(?=%s|$)" % state[triplequoted], line)
239            else:
240                m, line = match(r'#', line)
241                if m:
242                    return start_state
243               
244                m, line = match(r"\"\"\"|\'\'\'", line)
245                if m:
246                    state[triplequoted] = m.group(0)
247                    continue
248
249                m, line = match(r".*?(?=\"\"\"|\'\'\'|#|$)", line)
250           
251        return start_state
252
253    def _indent_line(line, stripspace = ''):
254        return re.sub(r"^%s" % stripspace, '', line)
255
256    lines = []
257    stripspace = None
258
259    for line in re.split(r'\r?\n', text):
260        if in_multi_line(line):
261            lines.append(line)
262        else:
263            line = string.expandtabs(line)
264            if stripspace is None and re.search(r"^[ \t]*[^# \t]", line):
265                stripspace = re.match(r"^([ \t]*)", line).group(1)
266            lines.append(_indent_line(line, stripspace))
267    return "\n".join(lines)
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。