Attached is a diff with the (heavy) modifications to gui.py, addition of guireporter.py in reporters/, and the small change to lint.py

The change to lint.py was the removal of sys.path.pop(0) and sys.exit() in __init__ in Lint(). This seems to not change anything. If these are left in, the gui can only be run on one file, and it locks up. With them removed as the patch states, everything works properly, including pylint and pylint-gui.

The actual files (gui.py and guireporter.py) are also submitted, as an added bonus.

(Note that double-clicking an item in the recent history loads that text to the input box so you can run it again)

Hope it's to everyone's liking! If there are any questions, comments, or concerns, don't hesitate to say anything.

Thanks,
Team Tahiti
"""Tkinker gui for pylint"""

from Tkinter import Tk, Frame, Listbox, Entry, Label, Button, Scrollbar, 
Checkbutton, Radiobutton, IntVar, Text, StringVar
from Tkinter import TOP, LEFT, RIGHT, BOTTOM, END, X, Y, BOTH, SUNKEN, W, 
HORIZONTAL, DISABLED, NORMAL, W, E, N, S
from tkFileDialog import askopenfilename, askdirectory
import os
import sys
import re
import pylint.lint
from threading import Thread
from pylint.reporters.guireporter import GUIReporter
import Queue


if sys.platform.startswith('win'):
    PYLINT = 'pylint.bat'
else:
    PYLINT = 'pylint'

HOME = os.path.expanduser('~/')
HISTORY = '.pylint-gui-history'
COLORS = {'(C)':'blue', '(R)':'darkblue', '(W)':'black', '(E)':'darkred', 
'(F)':'red'}

class BasicStream:
    '''
    used in gui reporter instead of writing to stdout, it is written to 
    this stream and saved in contents
    '''
    def __init__(self, gui):
        """init"""
        self.curline = ""
        self.gui = gui
        self.contents = []
        self.outdict = {}
        self.currout = None
        self.nextTitle = None
        
    def write(self, text):
        """write text to the stream"""
        if re.match('^--+$', text.strip()) or re.match('^==+$', text.strip()):
            if self.currout:
                self.outdict[self.currout].remove(self.nextTitle)
                self.outdict[self.currout].pop()
            self.currout = self.nextTitle
            self.outdict[self.currout] = ['']
            
        if text.strip():
            self.nextTitle = text.strip()
            
        if text.startswith('\n'):
            self.contents.append('')
            if self.currout: self.outdict[self.currout].append('')
        self.contents[-1] += text.strip('\n')
        if self.currout: self.outdict[self.currout][-1] += text.strip('\n')
        if text.endswith('\n') and text.strip():
            self.contents.append('')
            if self.currout: self.outdict[self.currout].append('')
    
    def fix_contents(self):
        """finalize what the contents of the dict should look like before 
output"""
        for item in self.outdict:
            numEmpty = self.outdict[item].count('')
            for i in range(numEmpty):
                self.outdict[item].remove('')
            if self.outdict[item]:
                self.outdict[item].pop(0)

    def output_contents(self):
        """output contents of dict to the gui, and set the rating"""
        self.fix_contents()
        self.gui.tabs = self.outdict
        try:
            self.gui.rating.set(self.outdict['Global evaluation'][0])
        except:
            self.gui.rating.set('Error')
        self.gui.refresh_results_window()
        
        #reset stream variables for next run
        self.contents = []
        self.outdict = {}
        self.currout = None
        self.nextTitle = None
        
        
class LintGui:
    """Build and control a window to interact with pylint"""
    
    def __init__(self, root=None):
        """init"""
        self.root = root or Tk()
        self.root.title('Pylint')
        #reporter
        self.reporter = None
        #message queue for output from reporter
        self.msg_queue = Queue.Queue()
        self.msgs = []
        self.filenames = []
                
        self.rating = StringVar()
        self.tabs = {}

        self.report_stream = BasicStream(self)
        
        #gui objects
        self.lbMessages = None
        self.showhistory = None
        self.results = None
        self.btnRun = None
        self.convention_box = None
        self.refactor_box = None
        self.warning_box = None
        self.error_box = None
        self.fatal_box = None
        self.txtModule = None
        self.status = None
        self.msg_type_dict = None
        
        self.init_gui()
        
    def init_gui(self):
        """init helper"""
        #setting up frames
        top_frame = Frame(self.root)
        mid_frame = Frame(self.root)
        radio_frame = Frame(self.root)
        res_frame = Frame(self.root)
        msg_frame = Frame(self.root)
        check_frame = Frame(self.root)
        history_frame = Frame(self.root)
        btn_frame = Frame(self.root)
        rating_frame = Frame(self.root)
        top_frame.pack(side=TOP, fill=X)
        mid_frame.pack(side=TOP, fill=X)
        history_frame.pack(side=TOP, fill=BOTH, expand=True)
        radio_frame.pack(side=TOP, fill=BOTH, expand=True)
        rating_frame.pack(side=TOP, fill=BOTH, expand=True)
        res_frame.pack(side=TOP, fill=BOTH, expand=True)
        check_frame.pack(side=TOP, fill=BOTH, expand=True)
        msg_frame.pack(side=TOP, fill=BOTH, expand=True)
        btn_frame.pack(side=TOP, fill=X)
        
        #Message ListBox
        rightscrollbar = Scrollbar(msg_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(msg_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.lbMessages = Listbox(msg_frame,
                  yscrollcommand=rightscrollbar.set,
                  xscrollcommand=bottomscrollbar.set,
                  bg="white")
        self.lbMessages.pack(expand=True, fill=BOTH)
        rightscrollbar.config(command=self.lbMessages.yview)
        bottomscrollbar.config(command=self.lbMessages.xview)

        #History ListBoxes
        rightscrollbar2 = Scrollbar(history_frame)
        rightscrollbar2.pack(side=RIGHT, fill=Y)
        bottomscrollbar2 = Scrollbar(history_frame, orient=HORIZONTAL)
        bottomscrollbar2.pack(side=BOTTOM, fill=X)
        self.showhistory = Listbox(history_frame,
                    yscrollcommand=rightscrollbar2.set,
                    xscrollcommand=bottomscrollbar2.set,
                    bg="white")
        self.showhistory.pack(expand=True, fill=BOTH)
        rightscrollbar2.config(command=self.showhistory.yview)
        bottomscrollbar2.config(command=self.showhistory.xview)
        self.showhistory.bind('<Double-Button-1>', self.select_recent_file)
        self.set_history_window()       
        
        #status bar
        self.status = Label(self.root, text="", bd=1, relief=SUNKEN, anchor=W)
        self.status.pack(side=BOTTOM, fill=X)

        #labels
        self.lblRatingLabel = Label(rating_frame, text='Rating:')
        self.lblRatingLabel.pack(side=LEFT)
        self.lblRating = Label(rating_frame, textvariable=self.rating)
        self.lblRating.pack(side=LEFT)
        Label(mid_frame, text='Recently Used:').pack(side=LEFT)
        Label(top_frame, text='Module or package').pack(side=LEFT)

        #file textbox
        self.txtModule = Entry(top_frame, background='white')
        self.txtModule.bind('<Return>', self.run_lint)
        self.txtModule.pack(side=LEFT, expand=True, fill=X)
        
        #results box
        rightscrollbar = Scrollbar(res_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(res_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.results = Listbox(res_frame,
                  yscrollcommand=rightscrollbar.set,
                  xscrollcommand=bottomscrollbar.set,
                  bg="white", font="Courier")
        self.results.pack(expand=True, fill=BOTH, side=BOTTOM)
        rightscrollbar.config(command=self.results.yview)
        bottomscrollbar.config(command=self.results.xview)

        #buttons
        Button(top_frame, text='Open', command=self.file_open).pack(side=LEFT)
        Button(top_frame, text='Open Package', command=(lambda : 
self.file_open(package=True))).pack(side=LEFT)
        
        self.btnRun = Button(top_frame, text='Run', command=self.run_lint)
        self.btnRun.pack(side=LEFT)
        Button(btn_frame, text='Quit', command=self.quit).pack(side=BOTTOM)

        #radio buttons
        self.convention_box = IntVar()
        self.refactor_box = IntVar()
        self.warning_box = IntVar()
        self.error_box = IntVar()
        self.fatal_box = IntVar()
        c = Checkbutton(check_frame, text="Convention", fg=COLORS['(C)'], 
variable=self.convention_box, command=self.refresh_msg_window)
        r = Checkbutton(check_frame, text="Refactor", fg=COLORS['(R)'], 
variable=self.refactor_box, command=self.refresh_msg_window)
        w = Checkbutton(check_frame, text="Warning", fg=COLORS['(W)'], 
variable=self.warning_box, command=self.refresh_msg_window)
        e = Checkbutton(check_frame, text="Error", fg=COLORS['(E)'], 
variable=self.error_box, command=self.refresh_msg_window)
        f = Checkbutton(check_frame, text="Fatal", fg=COLORS['(F)'], 
variable=self.fatal_box, command=self.refresh_msg_window)
        c.select()
        r.select()
        w.select()
        e.select()
        f.select()
        c.pack(side=LEFT)
        r.pack(side=LEFT)
        w.pack(side=LEFT)
        e.pack(side=LEFT)
        f.pack(side=LEFT)

        #check boxes
        self.box = StringVar()
        report = Radiobutton(radio_frame, text="Report", variable=self.box, 
value="Report", command=self.refresh_results_window)
        rawMet = Radiobutton(radio_frame, text="Raw metrics", 
variable=self.box, value="Raw metrics", command=self.refresh_results_window)
        dup = Radiobutton(radio_frame, text="Duplication", variable=self.box, 
value="Duplication", command=self.refresh_results_window)
        ext = Radiobutton(radio_frame, text="External dependencies", 
variable=self.box, value="External dependencies", 
command=self.refresh_results_window)
        stat = Radiobutton(radio_frame, text="Statistics by type", 
variable=self.box, value="Statistics by type", 
command=self.refresh_results_window)
        msgCat = Radiobutton(radio_frame, text="Messages by category", 
variable=self.box, value="Messages by category", 
command=self.refresh_results_window)
        msg = Radiobutton(radio_frame, text="Messages", variable=self.box, 
value="Messages", command=self.refresh_results_window)
        report.select()
        report.grid(column=0, row=0, sticky=W)
        rawMet.grid(column=1, row=0, sticky=W)
        dup.grid(column=2, row=0, sticky=W)
        msg.grid(column=3, row=0, sticky=E)
        stat.grid(column=0, row=1, sticky=W)
        msgCat.grid(column=1, row=1, sticky=W)
        ext.grid(column=2, row=1, columnspan=2, sticky=W)

        #dictionary for check boxes and associated error term
        self.msg_type_dict = {
            'C' : lambda : self.convention_box.get() == 1,
            'R' : lambda : self.refactor_box.get() == 1,
            'E' : lambda : self.error_box.get() == 1,
            'W' : lambda : self.warning_box.get() == 1,
            'F' : lambda : self.fatal_box.get() == 1
        }       
        self.txtModule.focus_set()

    
    def select_recent_file(self, event):
        """adds the selected file in the history listbox to the Module box"""
        if not self.showhistory.size():
            return
        
        selected = self.showhistory.curselection()
        item = self.showhistory.get(selected)
        #update module
        self.txtModule.delete(0, END)
        self.txtModule.insert(0, item)
        
    def refresh_msg_window(self):
        """refresh the message window with current output"""
        #clear the window
        self.lbMessages.delete(0, END)
        for msg in self.msgs:
            if (self.msg_type_dict.get(msg[0])()):
                msg_str = self.convert_to_string(msg)
                self.lbMessages.insert(END, msg_str)
                fg_color = COLORS.get(msg_str[:3], 'black')
                self.lbMessages.itemconfigure(END, fg=fg_color)
                
    def refresh_results_window(self):
        """refresh the results window with current output"""
        #clear the window
        self.results.delete(0, END)
        try:
            for res in self.tabs[self.box.get()]:
                self.results.insert(END, res)
        except:
            pass
    
    def convert_to_string(self, msg):
        """make a string representation of a message"""
        if (msg[2] != ""):
            return "(" + msg[0] + ") " + msg[1] + "." + msg[2] + " [" + msg[3] 
+ "]: " + msg[4]
        else:
            return "(" + msg[0] + ") " + msg[1] + " [" + msg[3] + "]: " + msg[4]
    
    def process_incoming(self):
        """process the incoming messages from running pylint"""
        while self.msg_queue.qsize():
            try:
                msg = self.msg_queue.get(0)
                if msg == "DONE":
                    self.report_stream.output_contents()
                    return False

                #adding message to list of msgs
                self.msgs.append(msg)
                
                #displaying msg if message type is selected in check box
                if (self.msg_type_dict.get(msg[0])()):
                    msg_str = self.convert_to_string(msg)
                    self.lbMessages.insert(END, msg_str)
                    fg_color = COLORS.get(msg_str[:3], 'black')
                    self.lbMessages.itemconfigure(END, fg=fg_color)
                    
            except Queue.Empty:
                pass
        return True
    
    def periodic_call(self):
        """determine when to unlock the run button"""
        if self.process_incoming():
            self.root.after(100, self.periodic_call)
        else:
            #enabling button so it can be run again
            self.btnRun.config(state=NORMAL)
                
    def mainloop(self):
        """launch the mainloop of the application"""
        self.root.mainloop()

    def quit(self, _=None):
        """quit the application"""
        self.root.quit()    
    
    def halt(self):
        """program halt placeholder"""
        return
    
    def file_open(self, package=False, _=None):
        """launch a file browser"""
        if not package:
            filename = askopenfilename(parent=self.root, 
filetypes=[('pythonfiles','*.py'),
                                                    
('allfiles','*')],title='Select Module')
        else:
            filename = askdirectory(title="Select A Folder", mustexist=1)
        
        if filename == ():
            return

        self.txtModule.delete(0, END)
        self.txtModule.insert(0, filename)
        
    def update_filenames(self):
        """update the list of recent filenames"""
        filename = self.txtModule.get()
        if not filename:
            filename = os.getcwd()
        if filename+'\n' in self.filenames:
            index = self.filenames.index(filename+'\n')
            self.filenames.pop(index)
        
        #ensure only 10 most recent are stored
        if len(self.filenames) == 10:
            self.filenames.pop()
        self.filenames.insert(0, filename+'\n')
            
    def set_history_window(self):
        """update the history window with info from the history file"""
        #clear the window
        self.showhistory.delete(0, END)
        # keep the last 10 most recent files
        try:
            view_history = open(HOME+HISTORY, 'r')
            for hist in view_history.readlines():
                if not hist in self.filenames:
                    self.filenames.append(hist)
                self.showhistory.insert(END, hist.split('\n')[0])
            view_history.close()
        except IOError:
            # do nothing since history file will be created later
            return    
        
    def run_lint(self, _=None):
        """launches pylint"""
        self.update_filenames()
        self.root.configure(cursor='watch')
        self.reporter = GUIReporter(self, output=self.report_stream)
        module = self.txtModule.get()
        if not module:
            module = os.getcwd()
        
        #cleaning up msgs and windows
        self.msgs = []
        self.lbMessages.delete(0, END)
        self.tabs = {}
        self.results.delete(0, END)
        self.btnRun.config(state=DISABLED)
        
        #setting up a worker thread to run pylint
        worker = Thread(target=lint_thread, args=(module, self.reporter, self,))
        self.periodic_call()
        worker.start()
        
        # Overwrite the .pylint-gui-history file with all the new recently 
added files
        # in order from filenames but only save last 10 files
        write_history = open(HOME+HISTORY, 'w') 
        write_history.writelines(self.filenames)
        write_history.close()
        self.set_history_window()  
        
        self.root.configure(cursor='')

        
def lint_thread(module, reporter, gui):
    """thread for pylint"""
    gui.status.text = "processing module(s)"
    lint_obj = pylint.lint.Run(args=[module], reporter=reporter)
    gui.msg_queue.put("DONE")

        
def Run(args):
    """launch pylint gui from args"""
    if args:
        print 'USAGE: pylint-gui\n launch a simple pylint gui using Tk'
        return
    gui = LintGui()
    gui.mainloop()

if __name__ == '__main__':
    Run(sys.argv[1:]) 
""" reporter used by gui.py """

import os
import sys

from pylint.interfaces import IReporter
from pylint.reporters import BaseReporter
from logilab.common.ureports import TextWriter


class GUIReporter(BaseReporter):
    """saves messages"""

    __implements__ = IReporter
    extension = ''
    
    def __init__(self, gui, output=sys.stdout):
        """init"""
        BaseReporter.__init__(self, output)
        self.msgs = []
        self.gui = gui

    def add_message(self, msg_id, location, msg):
        """manage message of different type and in the context of path"""
        module, obj, line = location[1:]
        if self.include_ids:
            sigle = msg_id
        else:
            sigle = msg_id[0]
            
        full_msg = [sigle, module, obj, str(line), msg]
        self.msgs += [[sigle, module, obj, str(line)]]
        self.gui.msg_queue.put(full_msg)
        
    def _display(self, layout):
        """launch layouts display"""
        TextWriter().format(layout, self.out)
        
diff -r 16f098a0c3ae gui.py
--- a/gui.py    Tue Mar 30 14:54:42 2010 +0200
+++ b/gui.py    Thu Apr 01 12:46:36 2010 -0400
@@ -1,75 +1,425 @@
 """Tkinker gui for pylint"""
 
-from Tkinter import Tk, Frame, Listbox, Entry, Label, Button, Scrollbar
-from Tkinter import TOP, LEFT, RIGHT, BOTTOM, END, X, Y, BOTH
+from Tkinter import Tk, Frame, Listbox, Entry, Label, Button, Scrollbar, 
Checkbutton, Radiobutton, IntVar, Text, StringVar
+from Tkinter import TOP, LEFT, RIGHT, BOTTOM, END, X, Y, BOTH, SUNKEN, W, 
HORIZONTAL, DISABLED, NORMAL, W, E, N, S
+from tkFileDialog import askopenfilename, askdirectory
 import os
 import sys
+import re
+import pylint.lint
+from threading import Thread
+from pylint.reporters.guireporter import GUIReporter
+import Queue
+
 
 if sys.platform.startswith('win'):
     PYLINT = 'pylint.bat'
 else:
     PYLINT = 'pylint'
 
+HOME = os.path.expanduser('~/')
+HISTORY = '.pylint-gui-history'
+COLORS = {'(C)':'blue', '(R)':'darkblue', '(W)':'black', '(E)':'darkred', 
'(F)':'red'}
+
+class BasicStream:
+    '''
+    used in gui reporter instead of writing to stdout, it is written to 
+    this stream and saved in contents
+    '''
+    def __init__(self, gui):
+        """init"""
+        self.curline = ""
+        self.gui = gui
+        self.contents = []
+        self.outdict = {}
+        self.currout = None
+        self.nextTitle = None
+       
+    def write(self, text):
+        """write text to the stream"""
+        if re.match('^--+$', text.strip()) or re.match('^==+$', text.strip()):
+            if self.currout:
+                self.outdict[self.currout].remove(self.nextTitle)
+                self.outdict[self.currout].pop()
+            self.currout = self.nextTitle
+            self.outdict[self.currout] = ['']
+            
+        if text.strip():
+            self.nextTitle = text.strip()
+            
+        if text.startswith('\n'):
+            self.contents.append('')
+            if self.currout: self.outdict[self.currout].append('')
+        self.contents[-1] += text.strip('\n')
+        if self.currout: self.outdict[self.currout][-1] += text.strip('\n')
+        if text.endswith('\n') and text.strip():
+            self.contents.append('')
+            if self.currout: self.outdict[self.currout].append('')
+    
+    def fix_contents(self):
+        """finalize what the contents of the dict should look like before 
output"""
+        for item in self.outdict:
+            numEmpty = self.outdict[item].count('')
+            for i in range(numEmpty):
+                self.outdict[item].remove('')
+            if self.outdict[item]:
+                self.outdict[item].pop(0)
+
+    def output_contents(self):
+        """output contents of dict to the gui, and set the rating"""
+        self.fix_contents()
+        self.gui.tabs = self.outdict
+        try:
+            self.gui.rating.set(self.outdict['Global evaluation'][0])
+        except:
+            self.gui.rating.set('Error')
+        self.gui.refresh_results_window()
+        
+        #reset stream variables for next run
+        self.contents = []
+        self.outdict = {}
+        self.currout = None
+        self.nextTitle = None
+       
+        
 class LintGui:
     """Build and control a window to interact with pylint"""
     
     def __init__(self, root=None):
+        """init"""
         self.root = root or Tk()
         self.root.title('Pylint')
+        #reporter
+        self.reporter = None
+        #message queue for output from reporter
+        self.msg_queue = Queue.Queue()
+        self.msgs = []
+        self.filenames = []
+               
+        self.rating = StringVar()
+        self.tabs = {}
+
+        self.report_stream = BasicStream(self)
+       
+        #gui objects
+        self.lbMessages = None
+        self.showhistory = None
+        self.results = None
+        self.btnRun = None
+        self.convention_box = None
+        self.refactor_box = None
+        self.warning_box = None
+        self.error_box = None
+        self.fatal_box = None
+        self.txtModule = None
+        self.status = None
+        self.msg_type_dict = None
+       
+        self.init_gui()
+       
+    def init_gui(self):
+        """init helper"""
+        #setting up frames
         top_frame = Frame(self.root)
+        mid_frame = Frame(self.root)
+        radio_frame = Frame(self.root)
         res_frame = Frame(self.root)
+        msg_frame = Frame(self.root)
+        check_frame = Frame(self.root)
+        history_frame = Frame(self.root)
         btn_frame = Frame(self.root)
+        rating_frame = Frame(self.root)
         top_frame.pack(side=TOP, fill=X)
+        mid_frame.pack(side=TOP, fill=X)
+        history_frame.pack(side=TOP, fill=BOTH, expand=True)
+        radio_frame.pack(side=TOP, fill=BOTH, expand=True)
+        rating_frame.pack(side=TOP, fill=BOTH, expand=True)
         res_frame.pack(side=TOP, fill=BOTH, expand=True)
+        check_frame.pack(side=TOP, fill=BOTH, expand=True)
+        msg_frame.pack(side=TOP, fill=BOTH, expand=True)
         btn_frame.pack(side=TOP, fill=X)
+       
+        #Message ListBox
+        rightscrollbar = Scrollbar(msg_frame)
+        rightscrollbar.pack(side=RIGHT, fill=Y)
+        bottomscrollbar = Scrollbar(msg_frame, orient=HORIZONTAL)
+        bottomscrollbar.pack(side=BOTTOM, fill=X)
+        self.lbMessages = Listbox(msg_frame,
+                  yscrollcommand=rightscrollbar.set,
+                  xscrollcommand=bottomscrollbar.set,
+                  bg="white")
+        self.lbMessages.pack(expand=True, fill=BOTH)
+        rightscrollbar.config(command=self.lbMessages.yview)
+        bottomscrollbar.config(command=self.lbMessages.xview)
+
+        #History ListBoxes
+        rightscrollbar2 = Scrollbar(history_frame)
+        rightscrollbar2.pack(side=RIGHT, fill=Y)
+        bottomscrollbar2 = Scrollbar(history_frame, orient=HORIZONTAL)
+        bottomscrollbar2.pack(side=BOTTOM, fill=X)
+        self.showhistory = Listbox(history_frame,
+                    yscrollcommand=rightscrollbar2.set,
+                    xscrollcommand=bottomscrollbar2.set,
+                    bg="white")
+        self.showhistory.pack(expand=True, fill=BOTH)
+        rightscrollbar2.config(command=self.showhistory.yview)
+        bottomscrollbar2.config(command=self.showhistory.xview)
+        self.showhistory.bind('<Double-Button-1>', self.select_recent_file)
+        self.set_history_window()      
         
+        #status bar
+        self.status = Label(self.root, text="", bd=1, relief=SUNKEN, anchor=W)
+        self.status.pack(side=BOTTOM, fill=X)
+
+        #labels
+        self.lblRatingLabel = Label(rating_frame, text='Rating:')
+        self.lblRatingLabel.pack(side=LEFT)
+        self.lblRating = Label(rating_frame, textvariable=self.rating)
+        self.lblRating.pack(side=LEFT)
+        Label(mid_frame, text='Recently Used:').pack(side=LEFT)
         Label(top_frame, text='Module or package').pack(side=LEFT)
+
+        #file textbox
         self.txtModule = Entry(top_frame, background='white')
         self.txtModule.bind('<Return>', self.run_lint)
         self.txtModule.pack(side=LEFT, expand=True, fill=X)
-        Button(top_frame, text='Run', command=self.run_lint).pack(side=LEFT)
+        
+        #results box
+        rightscrollbar = Scrollbar(res_frame)
+        rightscrollbar.pack(side=RIGHT, fill=Y)
+        bottomscrollbar = Scrollbar(res_frame, orient=HORIZONTAL)
+        bottomscrollbar.pack(side=BOTTOM, fill=X)
+        self.results = Listbox(res_frame,
+                  yscrollcommand=rightscrollbar.set,
+                  xscrollcommand=bottomscrollbar.set,
+                  bg="white", font="Courier")
+        self.results.pack(expand=True, fill=BOTH, side=BOTTOM)
+        rightscrollbar.config(command=self.results.yview)
+        bottomscrollbar.config(command=self.results.xview)
 
-        scrl = Scrollbar(res_frame)
-        self.results = Listbox(res_frame,
-                               background='white',
-                               font='fixedsys',
-                               selectmode='browse',
-                               yscrollcommand=scrl.set)
-        scrl.configure(command=self.results.yview)
-        self.results.pack(side=LEFT, expand=True, fill=BOTH)
-        scrl.pack(side=RIGHT, fill=Y)
-        
+        #buttons
+        Button(top_frame, text='Open', command=self.file_open).pack(side=LEFT)
+        Button(top_frame, text='Open Package', command=(lambda : 
self.file_open(package=True))).pack(side=LEFT)
+       
+        self.btnRun = Button(top_frame, text='Run', command=self.run_lint)
+        self.btnRun.pack(side=LEFT)
         Button(btn_frame, text='Quit', command=self.quit).pack(side=BOTTOM)
-        #self.root.bind('<ctrl-q>', self.quit)
+
+        #radio buttons
+        self.convention_box = IntVar()
+        self.refactor_box = IntVar()
+        self.warning_box = IntVar()
+        self.error_box = IntVar()
+        self.fatal_box = IntVar()
+        c = Checkbutton(check_frame, text="Convention", fg=COLORS['(C)'], 
variable=self.convention_box, command=self.refresh_msg_window)
+        r = Checkbutton(check_frame, text="Refactor", fg=COLORS['(R)'], 
variable=self.refactor_box, command=self.refresh_msg_window)
+        w = Checkbutton(check_frame, text="Warning", fg=COLORS['(W)'], 
variable=self.warning_box, command=self.refresh_msg_window)
+        e = Checkbutton(check_frame, text="Error", fg=COLORS['(E)'], 
variable=self.error_box, command=self.refresh_msg_window)
+        f = Checkbutton(check_frame, text="Fatal", fg=COLORS['(F)'], 
variable=self.fatal_box, command=self.refresh_msg_window)
+        c.select()
+        r.select()
+        w.select()
+        e.select()
+        f.select()
+        c.pack(side=LEFT)
+        r.pack(side=LEFT)
+        w.pack(side=LEFT)
+        e.pack(side=LEFT)
+        f.pack(side=LEFT)
+
+        #check boxes
+        self.box = StringVar()
+        report = Radiobutton(radio_frame, text="Report", variable=self.box, 
value="Report", command=self.refresh_results_window)
+        rawMet = Radiobutton(radio_frame, text="Raw metrics", 
variable=self.box, value="Raw metrics", command=self.refresh_results_window)
+        dup = Radiobutton(radio_frame, text="Duplication", variable=self.box, 
value="Duplication", command=self.refresh_results_window)
+        ext = Radiobutton(radio_frame, text="External dependencies", 
variable=self.box, value="External dependencies", 
command=self.refresh_results_window)
+        stat = Radiobutton(radio_frame, text="Statistics by type", 
variable=self.box, value="Statistics by type", 
command=self.refresh_results_window)
+        msgCat = Radiobutton(radio_frame, text="Messages by category", 
variable=self.box, value="Messages by category", 
command=self.refresh_results_window)
+        msg = Radiobutton(radio_frame, text="Messages", variable=self.box, 
value="Messages", command=self.refresh_results_window)
+        report.select()
+        report.grid(column=0, row=0, sticky=W)
+        rawMet.grid(column=1, row=0, sticky=W)
+        dup.grid(column=2, row=0, sticky=W)
+        msg.grid(column=3, row=0, sticky=E)
+        stat.grid(column=0, row=1, sticky=W)
+        msgCat.grid(column=1, row=1, sticky=W)
+        ext.grid(column=2, row=1, columnspan=2, sticky=W)
+
+        #dictionary for check boxes and associated error term
+        self.msg_type_dict = {
+            'C' : lambda : self.convention_box.get() == 1,
+            'R' : lambda : self.refactor_box.get() == 1,
+            'E' : lambda : self.error_box.get() == 1,
+            'W' : lambda : self.warning_box.get() == 1,
+            'F' : lambda : self.fatal_box.get() == 1
+        }      
         self.txtModule.focus_set()
-        
+
+    
+    def select_recent_file(self, event):
+        """adds the selected file in the history listbox to the Module box"""
+        if not self.showhistory.size():
+            return
+       
+        selected = self.showhistory.curselection()
+        item = self.showhistory.get(selected)
+        #update module
+        self.txtModule.delete(0, END)
+        self.txtModule.insert(0, item)
+       
+    def refresh_msg_window(self):
+        """refresh the message window with current output"""
+        #clear the window
+        self.lbMessages.delete(0, END)
+        for msg in self.msgs:
+            if (self.msg_type_dict.get(msg[0])()):
+                msg_str = self.convert_to_string(msg)
+                self.lbMessages.insert(END, msg_str)
+                fg_color = COLORS.get(msg_str[:3], 'black')
+                self.lbMessages.itemconfigure(END, fg=fg_color)
+                
+    def refresh_results_window(self):
+        """refresh the results window with current output"""
+        #clear the window
+        self.results.delete(0, END)
+        try:
+            for res in self.tabs[self.box.get()]:
+                self.results.insert(END, res)
+        except:
+            pass
+    
+    def convert_to_string(self, msg):
+        """make a string representation of a message"""
+        if (msg[2] != ""):
+            return "(" + msg[0] + ") " + msg[1] + "." + msg[2] + " [" + msg[3] 
+ "]: " + msg[4]
+        else:
+            return "(" + msg[0] + ") " + msg[1] + " [" + msg[3] + "]: " + 
msg[4]
+    
+    def process_incoming(self):
+        """process the incoming messages from running pylint"""
+        while self.msg_queue.qsize():
+            try:
+                msg = self.msg_queue.get(0)
+                if msg == "DONE":
+                    self.report_stream.output_contents()
+                    return False
+
+                #adding message to list of msgs
+                self.msgs.append(msg)
+               
+                #displaying msg if message type is selected in check box
+                if (self.msg_type_dict.get(msg[0])()):
+                    msg_str = self.convert_to_string(msg)
+                    self.lbMessages.insert(END, msg_str)
+                    fg_color = COLORS.get(msg_str[:3], 'black')
+                    self.lbMessages.itemconfigure(END, fg=fg_color)
+                    
+            except Queue.Empty:
+                pass
+        return True
+    
+    def periodic_call(self):
+        """determine when to unlock the run button"""
+        if self.process_incoming():
+            self.root.after(100, self.periodic_call)
+        else:
+            #enabling button so it can be run again
+            self.btnRun.config(state=NORMAL)
+               
     def mainloop(self):
         """launch the mainloop of the application"""
         self.root.mainloop()
 
     def quit(self, _=None):
         """quit the application"""
-        self.root.quit()
+        self.root.quit()    
+    
+    def halt(self):
+        """program halt placeholder"""
+        return
+    
+    def file_open(self, package=False, _=None):
+        """launch a file browser"""
+        if not package:
+            filename = askopenfilename(parent=self.root, 
filetypes=[('pythonfiles','*.py'),
+                                                    
('allfiles','*')],title='Select Module')
+        else:
+            filename = askdirectory(title="Select A Folder", mustexist=1)
+        
+        if filename == ():
+            return
 
+        self.txtModule.delete(0, END)
+        self.txtModule.insert(0, filename)
+        
+    def update_filenames(self):
+        """update the list of recent filenames"""
+        filename = self.txtModule.get()
+        if not filename:
+            filename = os.getcwd()
+        if filename+'\n' in self.filenames:
+            index = self.filenames.index(filename+'\n')
+            self.filenames.pop(index)
+        
+        #ensure only 10 most recent are stored
+        if len(self.filenames) == 10:
+            self.filenames.pop()
+        self.filenames.insert(0, filename+'\n')
+           
+    def set_history_window(self):
+        """update the history window with info from the history file"""
+        #clear the window
+        self.showhistory.delete(0, END)
+        # keep the last 10 most recent files
+        try:
+            view_history = open(HOME+HISTORY, 'r')
+            for hist in view_history.readlines():
+                if not hist in self.filenames:
+                    self.filenames.append(hist)
+                self.showhistory.insert(END, hist.split('\n')[0])
+            view_history.close()
+        except IOError:
+            # do nothing since history file will be created later
+            return    
+       
     def run_lint(self, _=None):
         """launches pylint"""
-        colors = {'W:':'red1', 'E:': 'red4',
-                  'W:': 'red3', '**': 'navy'}
-        
+        self.update_filenames()
         self.root.configure(cursor='watch')
-        self.results.focus_set()
+        self.reporter = GUIReporter(self, output=self.report_stream)
+        module = self.txtModule.get()
+        if not module:
+            module = os.getcwd()
+       
+        #cleaning up msgs and windows
+        self.msgs = []
+        self.lbMessages.delete(0, END)
+        self.tabs = {}
         self.results.delete(0, END)
-        self.results.update()
-        module = self.txtModule.get()
-        pout = os.popen('%s %s' % (PYLINT, module), 'r')
-        for line in  pout.xreadlines():
-            line = line.rstrip()
-            self.results.insert(END, line)
-            fg_color = colors.get(line[:2], 'black')
-            self.results.itemconfigure(END, fg=fg_color)
-            self.results.update()
+        self.btnRun.config(state=DISABLED)
+       
+        #setting up a worker thread to run pylint
+        worker = Thread(target=lint_thread, args=(module, self.reporter, 
self,))
+        self.periodic_call()
+        worker.start()
+       
+        # Overwrite the .pylint-gui-history file with all the new recently 
added files
+        # in order from filenames but only save last 10 files
+        write_history = open(HOME+HISTORY, 'w')        
+        write_history.writelines(self.filenames)
+        write_history.close()
+        self.set_history_window()  
+       
         self.root.configure(cursor='')
 
+        
+def lint_thread(module, reporter, gui):
+    """thread for pylint"""
+    gui.status.text = "processing module(s)"
+    lint_obj = pylint.lint.Run(args=[module], reporter=reporter)
+    gui.msg_queue.put("DONE")
+
+        
 def Run(args):
     """launch pylint gui from args"""
     if args:
diff -r 16f098a0c3ae lint.py
--- a/lint.py   Tue Mar 30 14:54:42 2010 +0200
+++ b/lint.py   Thu Apr 01 12:46:36 2010 -0400
@@ -883,8 +883,6 @@
             data.print_stats(30)
         else:
             linter.check(args)
-        sys.path.pop(0)
-        sys.exit(self.linter.msg_status)
 
     def cb_set_rcfile(self, name, value):
         """callback for option preprocessing (i.e. before optik parsing)"""
diff -r 16f098a0c3ae reporters/guireporter.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/reporters/guireporter.py  Thu Apr 01 12:46:36 2010 -0400
@@ -0,0 +1,37 @@
+""" reporter used by gui.py """
+
+import os
+import sys
+
+from pylint.interfaces import IReporter
+from pylint.reporters import BaseReporter
+from logilab.common.ureports import TextWriter
+
+
+class GUIReporter(BaseReporter):
+    """saves messages"""
+
+    __implements__ = IReporter
+    extension = ''
+    
+    def __init__(self, gui, output=sys.stdout):
+        """init"""
+        BaseReporter.__init__(self, output)
+        self.msgs = []
+        self.gui = gui
+
+    def add_message(self, msg_id, location, msg):
+        """manage message of different type and in the context of path"""
+        module, obj, line = location[1:]
+        if self.include_ids:
+            sigle = msg_id
+        else:
+            sigle = msg_id[0]
+            
+        full_msg = [sigle, module, obj, str(line), msg]
+        self.msgs += [[sigle, module, obj, str(line)]]
+        self.gui.msg_queue.put(full_msg)
+        
+    def _display(self, layout):
+        """launch layouts display"""
+        TextWriter().format(layout, self.out)
_______________________________________________
Python-Projects mailing list
Python-Projects@lists.logilab.org
http://lists.logilab.org/mailman/listinfo/python-projects

Reply via email to