1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 =================================
19 Support for code analysis tools
20 =================================
21
22 Support for code analysis tools.
23 """
24 __author__ = u"Andr\xe9 Malo"
25 __docformat__ = "restructuredtext en"
26
27 import re as _re
28 import sys as _sys
29
30 from _setup import term as _term
31 from _setup import shell as _shell
32
33
35 """ Exception used for message passing in the stream filter """
36
38 """ Exception used for message passing in the stream filter """
39
41 """ Exception used for message passing in the stream filter """
42
43
45 """ Stream filter """
46 _LINERE = _re.compile(r'''
47 (?P<name>[^:]+)
48 :
49 (?P<lineno>\d+)
50 :\s+
51 \[(?P<mid>[^\],]+)(?:,\s+(?P<func>[^\]]+))?\]
52 \s+
53 (?P<desc>.*)
54 ''', _re.X)
55 _SIMRE = _re.compile(r'in (?P<number>\d+) files')
56
57 - def __init__(self, term, stream=_sys.stdout):
58 self.written = False
59 self._stream = stream
60 self._lastname = None
61 self._term = dict(term)
62 self._buffer = ''
63
64 - def write(self, towrite):
65 """ Stream write function """
66 self._buffer += towrite
67 term = self._term
68
69 while True:
70 try:
71 name, lineno, mid, func, desc = self._parse()
72 except NotFinished:
73 break
74 except SpecialMessage, e:
75 self._dospecial(e)
76 continue
77 except NotParseable, e:
78 self._print_literal(str(e.args[0]))
79 continue
80
81 if name != self._lastname:
82 if self._lastname is not None:
83 self._stream.write("\n")
84 term['path'] = name
85 self._stream.write(
86 "%(BOLD)s>>> %(path)s%(NORMAL)s\n" % term
87 )
88 self._lastname = name
89 self.written = True
90
91 term['mid'] = mid
92 if mid.startswith('E') or mid.startswith('F'):
93 self._stream.write("%(BOLD)s%(RED)s%(mid)s%(NORMAL)s" % term)
94 elif mid == 'W0511':
95 self._stream.write(
96 "%(BOLD)s%(GREEN)s%(mid)s%(NORMAL)s" % term
97 )
98 else:
99 self._stream.write(
100 "%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
101 )
102
103 if int(lineno) != 0:
104 term['lineno'] = lineno
105 self._stream.write(" (%(lineno)s" % term)
106 if func:
107 term['func'] = func
108 self._stream.write(
109 ", %(BOLD)s%(YELLOW)s%(func)s%(NORMAL)s" % term
110 )
111 self._stream.write(')')
112
113 self._stream.write(": %s\n" % desc)
114 self._stream.flush()
115
116 return
117
119 """ Print literal """
120 suppress = (
121 line.startswith('Unable to get imported names for ') or
122 line.startswith("Exception exceptions.RuntimeError: 'generator "
123 "ignored GeneratorExit' in <generator object at") or
124 line.startswith("Exception RuntimeError: 'generator "
125 "ignored GeneratorExit' in <generator object") or
126 not line.strip()
127 )
128 if not suppress:
129 self._stream.write("%s\n" % line)
130 self._stream.flush()
131 self.written = True
132
134 """ Deal with special messages """
135 if e.args[0] == 'R0801':
136 match = self._SIMRE.search(e.args[1])
137 if not match:
138 raise AssertionError(
139 'Could not determine number of similar files'
140 )
141
142 numfiles = int(match.group('number'))
143 pos = -1
144 for _ in range(numfiles + 1):
145 pos = self._buffer.find('\n', pos + 1)
146 if pos >= 0:
147 lines = self._buffer[:pos + 1]
148 self._buffer = self._buffer[pos + 1:]
149 term = self._term
150
151 self._stream.write("\n")
152 for name in lines.splitlines()[1:]:
153 name = name.rstrip()[2:]
154 term['path'] = name
155 self._stream.write(
156 "%(BOLD)s=== %(path)s%(NORMAL)s\n" % term
157 )
158 self._lastname = name
159
160 term['mid'] = e.args[0]
161 self._stream.write(
162 "%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
163 )
164 self._stream.write(": %s\n" % e.args[1])
165 self._stream.flush()
166 self.written = True
167
169 """ Parse output """
170 if '\n' not in self._buffer:
171 raise NotFinished()
172
173 line = self._buffer[:self._buffer.find('\n') + 1]
174 self._buffer = self._buffer[len(line):]
175 line = line.rstrip()
176 match = self._LINERE.match(line)
177 if not match:
178 raise NotParseable(line)
179
180 mid = match.group('mid')
181 if mid == 'R0801':
182 self._buffer = "%s\n%s" % (line, self._buffer)
183 raise SpecialMessage(mid, match.group('desc'))
184
185 return match.group('name', 'lineno', 'mid', 'func', 'desc')
186
187
188 -def run(config, *args):
189 """ Run pylint """
190 try:
191 from pylint import lint
192 from pylint.reporters import text
193 except ImportError:
194 return 2
195
196 if config is None:
197 config = _shell.native('pylint.conf')
198 argv = ['--rcfile', config,
199 '--reports', 'no',
200 '--output-format', 'parseable',
201 '--include-ids', 'yes'
202 ]
203
204 libpath = _shell.native('lib')
205 if libpath != _sys.path[0]:
206 while libpath in _sys.path:
207 _sys.path.remove(libpath)
208 _sys.path.insert(0, libpath)
209
210 stream = FilterStream(_term.terminfo())
211
212 old_stderr = _sys.stderr
213 try:
214
215 _sys.stderr = stream
216 from pylint import __pkginfo__
217 if __pkginfo__.numversion < (0, 13):
218
219 lint.REPORTER_OPT_MAP['parseable'] = \
220 lambda: text.TextReporter2(stream)
221 reporter = text.TextReporter2(stream)
222 else:
223 reporter = text.ParseableTextReporter(stream)
224 lint.REPORTER_OPT_MAP['parseable'] = lambda: reporter
225
226 for path in args:
227 try:
228 path = _shell.native(path)
229 try:
230 lint.Run(argv + [path], reporter=reporter)
231 except SystemExit:
232 pass
233
234 if stream.written:
235 print
236 stream.written = False
237 except KeyboardInterrupt:
238 print
239 raise
240 finally:
241 _sys.stderr = old_stderr
242
243 return 0
244