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