OLD | NEW |
1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). | |
2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr | |
3 # | |
4 # This program is free software; you can redistribute it and/or modify it under | |
5 # the terms of the GNU General Public License as published by the Free Software | |
6 # Foundation; either version 2 of the License, or (at your option) any later | |
7 # version. | |
8 # | |
9 # This program is distributed in the hope that it will be useful, but WITHOUT | |
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
11 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details | |
12 # | |
13 # You should have received a copy of the GNU General Public License along with | |
14 # this program; if not, write to the Free Software Foundation, Inc., | |
15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
16 """Tkinker gui for pylint""" | 1 """Tkinker gui for pylint""" |
17 | 2 |
18 import os | 3 import os |
19 import sys | 4 import sys |
20 import re | 5 import re |
21 import Queue | 6 import Queue |
22 from threading import Thread | 7 from threading import Thread |
23 from Tkinter import (Tk, Frame, Listbox, Entry, Label, Button, Scrollbar, | 8 from Tkinter import (Tk, Frame, Listbox, Entry, Label, Button, Scrollbar, |
24 Checkbutton, Radiobutton, IntVar, StringVar) | 9 Checkbutton, Radiobutton, IntVar, StringVar) |
25 from Tkinter import (TOP, LEFT, RIGHT, BOTTOM, END, X, Y, BOTH, SUNKEN, W, | 10 from Tkinter import (TOP, LEFT, RIGHT, BOTTOM, END, X, Y, BOTH, SUNKEN, W, |
26 HORIZONTAL, DISABLED, NORMAL, W) | 11 HORIZONTAL, DISABLED, NORMAL, W, E) |
27 from tkFileDialog import askopenfilename, askdirectory | 12 from tkFileDialog import askopenfilename, askdirectory |
28 | 13 |
29 import pylint.lint | 14 import pylint.lint |
30 from pylint.reporters.guireporter import GUIReporter | 15 from pylint.reporters.guireporter import GUIReporter |
31 | 16 |
32 HOME = os.path.expanduser('~/') | 17 HOME = os.path.expanduser('~/') |
33 HISTORY = '.pylint-gui-history' | 18 HISTORY = '.pylint-gui-history' |
34 COLORS = {'(I)':'lightblue', | 19 COLORS = {'(I)':'lightblue', |
35 '(C)':'blue', '(R)':'darkblue', | 20 '(C)':'blue', '(R)':'darkblue', |
36 '(W)':'black', '(E)':'darkred', | 21 '(W)':'black', '(E)':'darkred', |
37 '(F)':'red'} | 22 '(F)':'red'} |
38 | 23 |
39 | 24 class BasicStream: |
40 def convert_to_string(msg): | |
41 """make a string representation of a message""" | |
42 module_object = msg.module | |
43 if msg.obj: | |
44 module_object += ".%s" % msg.obj | |
45 return "(%s) %s [%d]: %s" % (msg.C, module_object, msg.line, msg.msg) | |
46 | |
47 class BasicStream(object): | |
48 ''' | 25 ''' |
49 used in gui reporter instead of writing to stdout, it is written to | 26 used in gui reporter instead of writing to stdout, it is written to |
50 this stream and saved in contents | 27 this stream and saved in contents |
51 ''' | 28 ''' |
52 def __init__(self, gui): | 29 def __init__(self, gui): |
53 """init""" | 30 """init""" |
54 self.curline = "" | 31 self.curline = "" |
55 self.gui = gui | 32 self.gui = gui |
56 self.contents = [] | 33 self.contents = [] |
57 self.outdict = {} | 34 self.outdict = {} |
58 self.currout = None | 35 self.currout = None |
59 self.next_title = None | 36 self.nextTitle = None |
60 | 37 |
61 def write(self, text): | 38 def write(self, text): |
62 """write text to the stream""" | 39 """write text to the stream""" |
63 if re.match('^--+$', text.strip()) or re.match('^==+$', text.strip()): | 40 if re.match('^--+$', text.strip()) or re.match('^==+$', text.strip()): |
64 if self.currout: | 41 if self.currout: |
65 self.outdict[self.currout].remove(self.next_title) | 42 self.outdict[self.currout].remove(self.nextTitle) |
66 self.outdict[self.currout].pop() | 43 self.outdict[self.currout].pop() |
67 self.currout = self.next_title | 44 self.currout = self.nextTitle |
68 self.outdict[self.currout] = [''] | 45 self.outdict[self.currout] = [''] |
69 | 46 |
70 if text.strip(): | 47 if text.strip(): |
71 self.next_title = text.strip() | 48 self.nextTitle = text.strip() |
72 | 49 |
73 if text.startswith(os.linesep): | 50 if text.startswith('\n'): |
74 self.contents.append('') | 51 self.contents.append('') |
75 if self.currout: | 52 if self.currout: self.outdict[self.currout].append('') |
76 self.outdict[self.currout].append('') | 53 self.contents[-1] += text.strip('\n') |
77 self.contents[-1] += text.strip(os.linesep) | 54 if self.currout: self.outdict[self.currout][-1] += text.strip('\n') |
78 if self.currout: | 55 if text.endswith('\n') and text.strip(): |
79 self.outdict[self.currout][-1] += text.strip(os.linesep) | |
80 if text.endswith(os.linesep) and text.strip(): | |
81 self.contents.append('') | 56 self.contents.append('') |
82 if self.currout: | 57 if self.currout: self.outdict[self.currout].append('') |
83 self.outdict[self.currout].append('') | |
84 | 58 |
85 def fix_contents(self): | 59 def fix_contents(self): |
86 """finalize what the contents of the dict should look like before output
""" | 60 """finalize what the contents of the dict should look like before output
""" |
87 for item in self.outdict: | 61 for item in self.outdict: |
88 num_empty = self.outdict[item].count('') | 62 numEmpty = self.outdict[item].count('') |
89 for _ in xrange(num_empty): | 63 for i in range(numEmpty): |
90 self.outdict[item].remove('') | 64 self.outdict[item].remove('') |
91 if self.outdict[item]: | 65 if self.outdict[item]: |
92 self.outdict[item].pop(0) | 66 self.outdict[item].pop(0) |
93 | 67 |
94 def output_contents(self): | 68 def output_contents(self): |
95 """output contents of dict to the gui, and set the rating""" | 69 """output contents of dict to the gui, and set the rating""" |
96 self.fix_contents() | 70 self.fix_contents() |
97 self.gui.tabs = self.outdict | 71 self.gui.tabs = self.outdict |
98 try: | 72 try: |
99 self.gui.rating.set(self.outdict['Global evaluation'][0]) | 73 self.gui.rating.set(self.outdict['Global evaluation'][0]) |
100 except: | 74 except: |
101 self.gui.rating.set('Error') | 75 self.gui.rating.set('Error') |
102 self.gui.refresh_results_window() | 76 self.gui.refresh_results_window() |
103 | 77 |
104 #reset stream variables for next run | 78 #reset stream variables for next run |
105 self.contents = [] | 79 self.contents = [] |
106 self.outdict = {} | 80 self.outdict = {} |
107 self.currout = None | 81 self.currout = None |
108 self.next_title = None | 82 self.nextTitle = None |
109 | 83 |
110 | 84 |
111 class LintGui(object): | 85 class LintGui: |
112 """Build and control a window to interact with pylint""" | 86 """Build and control a window to interact with pylint""" |
113 | 87 |
114 def __init__(self, root=None): | 88 def __init__(self, root=None): |
115 """init""" | 89 """init""" |
116 self.root = root or Tk() | 90 self.root = root or Tk() |
117 self.root.title('Pylint') | 91 self.root.title('Pylint') |
118 #reporter | 92 #reporter |
119 self.reporter = None | 93 self.reporter = None |
120 #message queue for output from reporter | 94 #message queue for output from reporter |
121 self.msg_queue = Queue.Queue() | 95 self.msg_queue = Queue.Queue() |
122 self.msgs = [] | 96 self.msgs = [] |
123 self.visible_msgs = [] | |
124 self.filenames = [] | 97 self.filenames = [] |
125 self.rating = StringVar() | 98 self.rating = StringVar() |
126 self.tabs = {} | 99 self.tabs = {} |
127 self.report_stream = BasicStream(self) | 100 self.report_stream = BasicStream(self) |
128 #gui objects | 101 #gui objects |
129 self.lb_messages = None | 102 self.lbMessages = None |
130 self.showhistory = None | 103 self.showhistory = None |
131 self.results = None | 104 self.results = None |
132 self.btnRun = None | 105 self.btnRun = None |
133 self.information_box = None | 106 self.information_box = None |
134 self.convention_box = None | 107 self.convention_box = None |
135 self.refactor_box = None | 108 self.refactor_box = None |
136 self.warning_box = None | 109 self.warning_box = None |
137 self.error_box = None | 110 self.error_box = None |
138 self.fatal_box = None | 111 self.fatal_box = None |
139 self.txtModule = None | 112 self.txtModule = None |
(...skipping 16 matching lines...) Expand all Loading... |
156 top_frame.pack(side=TOP, fill=X) | 129 top_frame.pack(side=TOP, fill=X) |
157 mid_frame.pack(side=TOP, fill=X) | 130 mid_frame.pack(side=TOP, fill=X) |
158 history_frame.pack(side=TOP, fill=BOTH, expand=True) | 131 history_frame.pack(side=TOP, fill=BOTH, expand=True) |
159 radio_frame.pack(side=TOP, fill=BOTH, expand=True) | 132 radio_frame.pack(side=TOP, fill=BOTH, expand=True) |
160 rating_frame.pack(side=TOP, fill=BOTH, expand=True) | 133 rating_frame.pack(side=TOP, fill=BOTH, expand=True) |
161 res_frame.pack(side=TOP, fill=BOTH, expand=True) | 134 res_frame.pack(side=TOP, fill=BOTH, expand=True) |
162 check_frame.pack(side=TOP, fill=BOTH, expand=True) | 135 check_frame.pack(side=TOP, fill=BOTH, expand=True) |
163 msg_frame.pack(side=TOP, fill=BOTH, expand=True) | 136 msg_frame.pack(side=TOP, fill=BOTH, expand=True) |
164 btn_frame.pack(side=TOP, fill=X) | 137 btn_frame.pack(side=TOP, fill=X) |
165 | 138 |
166 # Binding F5 application-wide to run lint | |
167 self.root.bind('<F5>', self.run_lint) | |
168 | |
169 #Message ListBox | 139 #Message ListBox |
170 rightscrollbar = Scrollbar(msg_frame) | 140 rightscrollbar = Scrollbar(msg_frame) |
171 rightscrollbar.pack(side=RIGHT, fill=Y) | 141 rightscrollbar.pack(side=RIGHT, fill=Y) |
172 bottomscrollbar = Scrollbar(msg_frame, orient=HORIZONTAL) | 142 bottomscrollbar = Scrollbar(msg_frame, orient=HORIZONTAL) |
173 bottomscrollbar.pack(side=BOTTOM, fill=X) | 143 bottomscrollbar.pack(side=BOTTOM, fill=X) |
174 self.lb_messages = Listbox( | 144 self.lbMessages = Listbox(msg_frame, |
175 msg_frame, | 145 yscrollcommand=rightscrollbar.set, |
176 yscrollcommand=rightscrollbar.set, | 146 xscrollcommand=bottomscrollbar.set, |
177 xscrollcommand=bottomscrollbar.set, | 147 bg="white") |
178 bg="white") | 148 self.lbMessages.pack(expand=True, fill=BOTH) |
179 self.lb_messages.bind("<Double-Button-1>", self.show_sourcefile) | 149 rightscrollbar.config(command=self.lbMessages.yview) |
180 self.lb_messages.pack(expand=True, fill=BOTH) | 150 bottomscrollbar.config(command=self.lbMessages.xview) |
181 rightscrollbar.config(command=self.lb_messages.yview) | |
182 bottomscrollbar.config(command=self.lb_messages.xview) | |
183 | 151 |
184 #History ListBoxes | 152 #History ListBoxes |
185 rightscrollbar2 = Scrollbar(history_frame) | 153 rightscrollbar2 = Scrollbar(history_frame) |
186 rightscrollbar2.pack(side=RIGHT, fill=Y) | 154 rightscrollbar2.pack(side=RIGHT, fill=Y) |
187 bottomscrollbar2 = Scrollbar(history_frame, orient=HORIZONTAL) | 155 bottomscrollbar2 = Scrollbar(history_frame, orient=HORIZONTAL) |
188 bottomscrollbar2.pack(side=BOTTOM, fill=X) | 156 bottomscrollbar2.pack(side=BOTTOM, fill=X) |
189 self.showhistory = Listbox( | 157 self.showhistory = Listbox(history_frame, |
190 history_frame, | 158 yscrollcommand=rightscrollbar2.set, |
191 yscrollcommand=rightscrollbar2.set, | 159 xscrollcommand=bottomscrollbar2.set, |
192 xscrollcommand=bottomscrollbar2.set, | 160 bg="white") |
193 bg="white") | |
194 self.showhistory.pack(expand=True, fill=BOTH) | 161 self.showhistory.pack(expand=True, fill=BOTH) |
195 rightscrollbar2.config(command=self.showhistory.yview) | 162 rightscrollbar2.config(command=self.showhistory.yview) |
196 bottomscrollbar2.config(command=self.showhistory.xview) | 163 bottomscrollbar2.config(command=self.showhistory.xview) |
197 self.showhistory.bind('<Double-Button-1>', self.select_recent_file) | 164 self.showhistory.bind('<Double-Button-1>', self.select_recent_file) |
198 self.set_history_window() | 165 self.set_history_window() |
199 | 166 |
200 #status bar | 167 #status bar |
201 self.status = Label(self.root, text="", bd=1, relief=SUNKEN, anchor=W) | 168 self.status = Label(self.root, text="", bd=1, relief=SUNKEN, anchor=W) |
202 self.status.pack(side=BOTTOM, fill=X) | 169 self.status.pack(side=BOTTOM, fill=X) |
203 | 170 |
204 #labelbl_ratingls | 171 #labels |
205 lbl_rating_label = Label(rating_frame, text='Rating:') | 172 self.lblRatingLabel = Label(rating_frame, text='Rating:') |
206 lbl_rating_label.pack(side=LEFT) | 173 self.lblRatingLabel.pack(side=LEFT) |
207 lbl_rating = Label(rating_frame, textvariable=self.rating) | 174 self.lblRating = Label(rating_frame, textvariable=self.rating) |
208 lbl_rating.pack(side=LEFT) | 175 self.lblRating.pack(side=LEFT) |
209 Label(mid_frame, text='Recently Used:').pack(side=LEFT) | 176 Label(mid_frame, text='Recently Used:').pack(side=LEFT) |
210 Label(top_frame, text='Module or package').pack(side=LEFT) | 177 Label(top_frame, text='Module or package').pack(side=LEFT) |
211 | 178 |
212 #file textbox | 179 #file textbox |
213 self.txt_module = Entry(top_frame, background='white') | 180 self.txtModule = Entry(top_frame, background='white') |
214 self.txt_module.bind('<Return>', self.run_lint) | 181 self.txtModule.bind('<Return>', self.run_lint) |
215 self.txt_module.pack(side=LEFT, expand=True, fill=X) | 182 self.txtModule.pack(side=LEFT, expand=True, fill=X) |
216 | 183 |
217 #results box | 184 #results box |
218 rightscrollbar = Scrollbar(res_frame) | 185 rightscrollbar = Scrollbar(res_frame) |
219 rightscrollbar.pack(side=RIGHT, fill=Y) | 186 rightscrollbar.pack(side=RIGHT, fill=Y) |
220 bottomscrollbar = Scrollbar(res_frame, orient=HORIZONTAL) | 187 bottomscrollbar = Scrollbar(res_frame, orient=HORIZONTAL) |
221 bottomscrollbar.pack(side=BOTTOM, fill=X) | 188 bottomscrollbar.pack(side=BOTTOM, fill=X) |
222 self.results = Listbox( | 189 self.results = Listbox(res_frame, |
223 res_frame, | 190 yscrollcommand=rightscrollbar.set, |
224 yscrollcommand=rightscrollbar.set, | 191 xscrollcommand=bottomscrollbar.set, |
225 xscrollcommand=bottomscrollbar.set, | 192 bg="white", font="Courier") |
226 bg="white", font="Courier") | |
227 self.results.pack(expand=True, fill=BOTH, side=BOTTOM) | 193 self.results.pack(expand=True, fill=BOTH, side=BOTTOM) |
228 rightscrollbar.config(command=self.results.yview) | 194 rightscrollbar.config(command=self.results.yview) |
229 bottomscrollbar.config(command=self.results.xview) | 195 bottomscrollbar.config(command=self.results.xview) |
230 | 196 |
231 #buttons | 197 #buttons |
232 Button(top_frame, text='Open', command=self.file_open).pack(side=LEFT) | 198 Button(top_frame, text='Open', command=self.file_open).pack(side=LEFT) |
233 Button(top_frame, text='Open Package', | 199 Button(top_frame, text='Open Package', |
234 command=(lambda: self.file_open(package=True))).pack(side=LEFT) | 200 command=(lambda : self.file_open(package=True))).pack(side=LEFT) |
235 | 201 |
236 self.btnRun = Button(top_frame, text='Run', command=self.run_lint) | 202 self.btnRun = Button(top_frame, text='Run', command=self.run_lint) |
237 self.btnRun.pack(side=LEFT) | 203 self.btnRun.pack(side=LEFT) |
238 Button(btn_frame, text='Quit', command=self.quit).pack(side=BOTTOM) | 204 Button(btn_frame, text='Quit', command=self.quit).pack(side=BOTTOM) |
239 | 205 |
240 #radio buttons | 206 #radio buttons |
241 self.information_box = IntVar() | 207 self.information_box = IntVar() |
242 self.convention_box = IntVar() | 208 self.convention_box = IntVar() |
243 self.refactor_box = IntVar() | 209 self.refactor_box = IntVar() |
244 self.warning_box = IntVar() | 210 self.warning_box = IntVar() |
(...skipping 20 matching lines...) Expand all Loading... |
265 i.pack(side=LEFT) | 231 i.pack(side=LEFT) |
266 c.pack(side=LEFT) | 232 c.pack(side=LEFT) |
267 r.pack(side=LEFT) | 233 r.pack(side=LEFT) |
268 w.pack(side=LEFT) | 234 w.pack(side=LEFT) |
269 e.pack(side=LEFT) | 235 e.pack(side=LEFT) |
270 f.pack(side=LEFT) | 236 f.pack(side=LEFT) |
271 | 237 |
272 #check boxes | 238 #check boxes |
273 self.box = StringVar() | 239 self.box = StringVar() |
274 # XXX should be generated | 240 # XXX should be generated |
275 report = Radiobutton( | 241 report = Radiobutton(radio_frame, text="Report", variable=self.box, |
276 radio_frame, text="Report", variable=self.box, | 242 value="Report", command=self.refresh_results_window
) |
277 value="Report", command=self.refresh_results_window) | 243 rawMet = Radiobutton(radio_frame, text="Raw metrics", variable=self.box, |
278 raw_met = Radiobutton( | 244 value="Raw metrics", command=self.refresh_results_w
indow) |
279 radio_frame, text="Raw metrics", variable=self.box, | 245 dup = Radiobutton(radio_frame, text="Duplication", variable=self.box, |
280 value="Raw metrics", command=self.refresh_results_window) | 246 value="Duplication", command=self.refresh_results_wind
ow) |
281 dup = Radiobutton( | 247 ext = Radiobutton(radio_frame, text="External dependencies", |
282 radio_frame, text="Duplication", variable=self.box, | 248 variable=self.box, value="External dependencies", |
283 value="Duplication", command=self.refresh_results_window) | 249 command=self.refresh_results_window) |
284 ext = Radiobutton( | 250 stat = Radiobutton(radio_frame, text="Statistics by type", |
285 radio_frame, text="External dependencies", | 251 variable=self.box, value="Statistics by type", |
286 variable=self.box, value="External dependencies", | 252 command=self.refresh_results_window) |
287 command=self.refresh_results_window) | 253 msgCat = Radiobutton(radio_frame, text="Messages by category", |
288 stat = Radiobutton( | 254 variable=self.box, value="Messages by category", |
289 radio_frame, text="Statistics by type", | 255 command=self.refresh_results_window) |
290 variable=self.box, value="Statistics by type", | 256 msg = Radiobutton(radio_frame, text="Messages", variable=self.box, |
291 command=self.refresh_results_window) | 257 value="Messages", command=self.refresh_results_windo
w) |
292 msg_cat = Radiobutton( | |
293 radio_frame, text="Messages by category", | |
294 variable=self.box, value="Messages by category", | |
295 command=self.refresh_results_window) | |
296 msg = Radiobutton( | |
297 radio_frame, text="Messages", variable=self.box, | |
298 value="Messages", command=self.refresh_results_window) | |
299 source_file = Radiobutton( | |
300 radio_frame, text="Source File", variable=self.box, | |
301 value="Source File", command=self.refresh_results_window) | |
302 report.select() | 258 report.select() |
303 report.grid(column=0, row=0, sticky=W) | 259 report.grid(column=0, row=0, sticky=W) |
304 raw_met.grid(column=1, row=0, sticky=W) | 260 rawMet.grid(column=1, row=0, sticky=W) |
305 dup.grid(column=2, row=0, sticky=W) | 261 dup.grid(column=2, row=0, sticky=W) |
306 msg.grid(column=3, row=0, sticky=W) | 262 msg.grid(column=3, row=0, sticky=E) |
307 stat.grid(column=0, row=1, sticky=W) | 263 stat.grid(column=0, row=1, sticky=W) |
308 msg_cat.grid(column=1, row=1, sticky=W) | 264 msgCat.grid(column=1, row=1, sticky=W) |
309 ext.grid(column=2, row=1, sticky=W) | 265 ext.grid(column=2, row=1, columnspan=2, sticky=W) |
310 source_file.grid(column=3, row=1, sticky=W) | |
311 | 266 |
312 #dictionary for check boxes and associated error term | 267 #dictionary for check boxes and associated error term |
313 self.msg_type_dict = { | 268 self.msg_type_dict = { |
314 'I': lambda: self.information_box.get() == 1, | 269 'I' : lambda : self.information_box.get() == 1, |
315 'C': lambda: self.convention_box.get() == 1, | 270 'C' : lambda : self.convention_box.get() == 1, |
316 'R': lambda: self.refactor_box.get() == 1, | 271 'R' : lambda : self.refactor_box.get() == 1, |
317 'E': lambda: self.error_box.get() == 1, | 272 'E' : lambda : self.error_box.get() == 1, |
318 'W': lambda: self.warning_box.get() == 1, | 273 'W' : lambda : self.warning_box.get() == 1, |
319 'F': lambda: self.fatal_box.get() == 1 | 274 'F' : lambda : self.fatal_box.get() == 1 |
320 } | 275 } |
321 self.txt_module.focus_set() | 276 self.txtModule.focus_set() |
322 | 277 |
323 | 278 |
324 def select_recent_file(self, event): | 279 def select_recent_file(self, event): |
325 """adds the selected file in the history listbox to the Module box""" | 280 """adds the selected file in the history listbox to the Module box""" |
326 if not self.showhistory.size(): | 281 if not self.showhistory.size(): |
327 return | 282 return |
328 | 283 |
329 selected = self.showhistory.curselection() | 284 selected = self.showhistory.curselection() |
330 item = self.showhistory.get(selected) | 285 item = self.showhistory.get(selected) |
331 #update module | 286 #update module |
332 self.txt_module.delete(0, END) | 287 self.txtModule.delete(0, END) |
333 self.txt_module.insert(0, item) | 288 self.txtModule.insert(0, item) |
334 | 289 |
335 def refresh_msg_window(self): | 290 def refresh_msg_window(self): |
336 """refresh the message window with current output""" | 291 """refresh the message window with current output""" |
337 #clear the window | 292 #clear the window |
338 self.lb_messages.delete(0, END) | 293 self.lbMessages.delete(0, END) |
339 self.visible_msgs = [] | |
340 for msg in self.msgs: | 294 for msg in self.msgs: |
341 if self.msg_type_dict.get(msg.C)(): | 295 if (self.msg_type_dict.get(msg[0])()): |
342 self.visible_msgs.append(msg) | 296 msg_str = self.convert_to_string(msg) |
343 msg_str = convert_to_string(msg) | 297 self.lbMessages.insert(END, msg_str) |
344 self.lb_messages.insert(END, msg_str) | |
345 fg_color = COLORS.get(msg_str[:3], 'black') | 298 fg_color = COLORS.get(msg_str[:3], 'black') |
346 self.lb_messages.itemconfigure(END, fg=fg_color) | 299 self.lbMessages.itemconfigure(END, fg=fg_color) |
347 | 300 |
348 def refresh_results_window(self): | 301 def refresh_results_window(self): |
349 """refresh the results window with current output""" | 302 """refresh the results window with current output""" |
350 #clear the window | 303 #clear the window |
351 self.results.delete(0, END) | 304 self.results.delete(0, END) |
352 try: | 305 try: |
353 for res in self.tabs[self.box.get()]: | 306 for res in self.tabs[self.box.get()]: |
354 self.results.insert(END, res) | 307 self.results.insert(END, res) |
355 except: | 308 except: |
356 pass | 309 pass |
357 | 310 |
| 311 def convert_to_string(self, msg): |
| 312 """make a string representation of a message""" |
| 313 if (msg[2] != ""): |
| 314 return "(" + msg[0] + ") " + msg[1] + "." + msg[2] + " [" + msg[3] +
"]: " + msg[4] |
| 315 else: |
| 316 return "(" + msg[0] + ") " + msg[1] + " [" + msg[3] + "]: " + msg[4] |
| 317 |
358 def process_incoming(self): | 318 def process_incoming(self): |
359 """process the incoming messages from running pylint""" | 319 """process the incoming messages from running pylint""" |
360 while self.msg_queue.qsize(): | 320 while self.msg_queue.qsize(): |
361 try: | 321 try: |
362 msg = self.msg_queue.get(0) | 322 msg = self.msg_queue.get(0) |
363 if msg == "DONE": | 323 if msg == "DONE": |
364 self.report_stream.output_contents() | 324 self.report_stream.output_contents() |
365 return False | 325 return False |
366 | 326 |
367 #adding message to list of msgs | 327 #adding message to list of msgs |
368 self.msgs.append(msg) | 328 self.msgs.append(msg) |
369 | 329 |
370 #displaying msg if message type is selected in check box | 330 #displaying msg if message type is selected in check box |
371 if self.msg_type_dict.get(msg.C)(): | 331 if (self.msg_type_dict.get(msg[0])()): |
372 self.visible_msgs.append(msg) | 332 msg_str = self.convert_to_string(msg) |
373 msg_str = convert_to_string(msg) | 333 self.lbMessages.insert(END, msg_str) |
374 self.lb_messages.insert(END, msg_str) | |
375 fg_color = COLORS.get(msg_str[:3], 'black') | 334 fg_color = COLORS.get(msg_str[:3], 'black') |
376 self.lb_messages.itemconfigure(END, fg=fg_color) | 335 self.lbMessages.itemconfigure(END, fg=fg_color) |
377 | 336 |
378 except Queue.Empty: | 337 except Queue.Empty: |
379 pass | 338 pass |
380 return True | 339 return True |
381 | 340 |
382 def periodic_call(self): | 341 def periodic_call(self): |
383 """determine when to unlock the run button""" | 342 """determine when to unlock the run button""" |
384 if self.process_incoming(): | 343 if self.process_incoming(): |
385 self.root.after(100, self.periodic_call) | 344 self.root.after(100, self.periodic_call) |
386 else: | 345 else: |
387 #enabling button so it can be run again | 346 #enabling button so it can be run again |
388 self.btnRun.config(state=NORMAL) | 347 self.btnRun.config(state=NORMAL) |
389 | 348 |
390 def mainloop(self): | 349 def mainloop(self): |
391 """launch the mainloop of the application""" | 350 """launch the mainloop of the application""" |
392 self.root.mainloop() | 351 self.root.mainloop() |
393 | 352 |
394 def quit(self, _=None): | 353 def quit(self, _=None): |
395 """quit the application""" | 354 """quit the application""" |
396 self.root.quit() | 355 self.root.quit() |
397 | 356 |
398 def halt(self): | 357 def halt(self): |
399 """program halt placeholder""" | 358 """program halt placeholder""" |
400 return | 359 return |
401 | 360 |
402 def file_open(self, package=False, _=None): | 361 def file_open(self, package=False, _=None): |
403 """launch a file browser""" | 362 """launch a file browser""" |
404 if not package: | 363 if not package: |
405 filename = askopenfilename(parent=self.root, | 364 filename = askopenfilename(parent=self.root, filetypes=[('pythonfile
s', '*.py'), |
406 filetypes=[('pythonfiles', '*.py'), | 365 ('allfiles', '*')], title='S
elect Module') |
407 ('allfiles', '*')], | |
408 title='Select Module') | |
409 else: | 366 else: |
410 filename = askdirectory(title="Select A Folder", mustexist=1) | 367 filename = askdirectory(title="Select A Folder", mustexist=1) |
411 | 368 |
412 if filename == (): | 369 if filename == (): |
413 return | 370 return |
414 | 371 |
415 self.txt_module.delete(0, END) | 372 self.txtModule.delete(0, END) |
416 self.txt_module.insert(0, filename) | 373 self.txtModule.insert(0, filename) |
417 | 374 |
418 def update_filenames(self): | 375 def update_filenames(self): |
419 """update the list of recent filenames""" | 376 """update the list of recent filenames""" |
420 filename = self.txt_module.get() | 377 filename = self.txtModule.get() |
421 if not filename: | 378 if not filename: |
422 filename = os.getcwd() | 379 filename = os.getcwd() |
423 if filename+'\n' in self.filenames: | 380 if filename+'\n' in self.filenames: |
424 index = self.filenames.index(filename+'\n') | 381 index = self.filenames.index(filename+'\n') |
425 self.filenames.pop(index) | 382 self.filenames.pop(index) |
426 | 383 |
427 #ensure only 10 most recent are stored | 384 #ensure only 10 most recent are stored |
428 if len(self.filenames) == 10: | 385 if len(self.filenames) == 10: |
429 self.filenames.pop() | 386 self.filenames.pop() |
430 self.filenames.insert(0, filename+'\n') | 387 self.filenames.insert(0, filename+'\n') |
(...skipping 12 matching lines...) Expand all Loading... |
443 view_history.close() | 400 view_history.close() |
444 except IOError: | 401 except IOError: |
445 # do nothing since history file will be created later | 402 # do nothing since history file will be created later |
446 return | 403 return |
447 | 404 |
448 def run_lint(self, _=None): | 405 def run_lint(self, _=None): |
449 """launches pylint""" | 406 """launches pylint""" |
450 self.update_filenames() | 407 self.update_filenames() |
451 self.root.configure(cursor='watch') | 408 self.root.configure(cursor='watch') |
452 self.reporter = GUIReporter(self, output=self.report_stream) | 409 self.reporter = GUIReporter(self, output=self.report_stream) |
453 module = self.txt_module.get() | 410 module = self.txtModule.get() |
454 if not module: | 411 if not module: |
455 module = os.getcwd() | 412 module = os.getcwd() |
456 | 413 |
457 #cleaning up msgs and windows | 414 #cleaning up msgs and windows |
458 self.msgs = [] | 415 self.msgs = [] |
459 self.visible_msgs = [] | 416 self.lbMessages.delete(0, END) |
460 self.lb_messages.delete(0, END) | |
461 self.tabs = {} | 417 self.tabs = {} |
462 self.results.delete(0, END) | 418 self.results.delete(0, END) |
463 self.btnRun.config(state=DISABLED) | 419 self.btnRun.config(state=DISABLED) |
464 | 420 |
465 #setting up a worker thread to run pylint | 421 #setting up a worker thread to run pylint |
466 worker = Thread(target=lint_thread, args=(module, self.reporter, self,)) | 422 worker = Thread(target=lint_thread, args=(module, self.reporter, self,)) |
467 self.periodic_call() | 423 self.periodic_call() |
468 worker.start() | 424 worker.start() |
469 | 425 |
470 # Overwrite the .pylint-gui-history file with all the new recently added
files | 426 # Overwrite the .pylint-gui-history file with all the new recently added
files |
471 # in order from filenames but only save last 10 files | 427 # in order from filenames but only save last 10 files |
472 write_history = open(HOME+HISTORY, 'w') | 428 write_history = open(HOME+HISTORY, 'w') |
473 write_history.writelines(self.filenames) | 429 write_history.writelines(self.filenames) |
474 write_history.close() | 430 write_history.close() |
475 self.set_history_window() | 431 self.set_history_window() |
476 | 432 |
477 self.root.configure(cursor='') | 433 self.root.configure(cursor='') |
478 | 434 |
479 def show_sourcefile(self, event=None): | |
480 selected = self.lb_messages.curselection() | |
481 if not selected: | |
482 return | |
483 | |
484 msg = self.visible_msgs[int(selected[0])] | |
485 scroll = msg.line - 3 | |
486 if scroll < 0: | |
487 scroll = 0 | |
488 | |
489 self.tabs["Source File"] = open(msg.path, "r").readlines() | |
490 self.box.set("Source File") | |
491 self.refresh_results_window() | |
492 self.results.yview(scroll) | |
493 self.results.select_set(msg.line - 1) | |
494 | |
495 | 435 |
496 def lint_thread(module, reporter, gui): | 436 def lint_thread(module, reporter, gui): |
497 """thread for pylint""" | 437 """thread for pylint""" |
498 gui.status.text = "processing module(s)" | 438 gui.status.text = "processing module(s)" |
499 pylint.lint.Run(args=[module], reporter=reporter, exit=False) | 439 lint_obj = pylint.lint.Run(args=[module], reporter=reporter, exit=False) |
500 gui.msg_queue.put("DONE") | 440 gui.msg_queue.put("DONE") |
501 | 441 |
502 | 442 |
503 def Run(args): | 443 def Run(args): |
504 """launch pylint gui from args""" | 444 """launch pylint gui from args""" |
505 if args: | 445 if args: |
506 print 'USAGE: pylint-gui\n launch a simple pylint gui using Tk' | 446 print 'USAGE: pylint-gui\n launch a simple pylint gui using Tk' |
507 sys.exit(1) | 447 return |
508 gui = LintGui() | 448 gui = LintGui() |
509 gui.mainloop() | 449 gui.mainloop() |
510 sys.exit(0) | |
511 | 450 |
512 if __name__ == '__main__': | 451 if __name__ == '__main__': |
513 Run(sys.argv[1:]) | 452 Run(sys.argv[1:]) |
OLD | NEW |