def add(self, itemType, cnf={}, **kw): end = self.index('end') if end is None: end = 1 else: end += 2 # end is the index of the last item starting from 0 so the # nb of items after the addition is end + 2 if not end % self.max_height: kw['columnbreak'] = True Menu.add(self, itemType, cnf, **kw)
def popup_menu(event): right_click_menu = Menu(None, tearoff=0, takefocus=0) right_click_menu.add_command( label='Select all', command=lambda: on_click(event, 'SelectAll')) right_click_menu.add_command(label='Copy', command=lambda: on_click(event, 'Copy')) right_click_menu.add_command(label='Paste', command=lambda: on_click(event, 'Paste')) right_click_menu.add_command(label='Cut', command=lambda: on_click(event, 'Cut')) right_click_menu.add(constants.SEPARATOR) right_click_menu.add_command( label='Close window', command=lambda: utils.get_toplevel('winpath', mainwin).destroy()) right_click_menu.tk_popup(event.x_root + 10, event.y_root + 15)
def init_gui(self): """ Initializes all widgets for the main screen and calls grid_widgets() to place them """ self.title("exp_check") self.config(bg='black') style = Style() style.configure("TMenubutton", foreground="white", background="black") # setup widgets self.add_button = Button(self, text="Add Food", **widget_options, command=self.add_food) self.delete_button = Button(self, text="Delete Food", **widget_options, command=self.delete_food) self.search_box = Entry(self, **widget_options, insertbackground='white') self.search_box.bind("<Key>", self.search) self.data_display = DataDisplay(widget_options) vals = self.data_manager.get_keylist() vals.insert(0, 'name') menu1 = Menu(tearoff=0) menu1.add('radiobutton', label=vals[0], command=lambda: self.update_data_display(sort_key=vals[0])) menu1.add('radiobutton', label=vals[1], command=lambda: self.update_data_display(sort_key=vals[1])) menu1.add('radiobutton', label=vals[2], command=lambda: self.update_data_display(sort_key=vals[2])) self.sort_menu = Menubutton(self, text='sort by', menu=menu1, style="TMenubutton") search_icon = self.generate_icon_object("./data/search_icon.png", (20, 20)) self.search_label = Label(image=search_icon, **widget_options) self.search_label.image = search_icon # setup message box dialog self.message = Label(self, text='', **widget_options) self.okay_button = Button( self, text=" OK ", **widget_options, command=lambda: self.okay_button_press(self.cur_instance)) self.grid_widgets()
class RandomSelector(Frame): def __init__(self, master): super().__init__(master) self.set_vars() self.set_frames() self.set_widgets() self.set_menu() self._items = [] def set_vars(self): # tkinter variable self.item = StringVar() self.item.set('Item Name') self.hide = BooleanVar() self.hide.set(False) def set_frames(self): self.seladd_frame = Frame(self) self.itemframe = LabelFrame(self, text='Items') self.seladd_frame.pack() self.itemframe.pack(fill='both', expand=1) def set_widgets(self): self.entry = Entry(self.seladd_frame, width=30, textvariable=self.item) self.entry.pack(side='left') self.sel_button = Button(self.seladd_frame, text="Select", command=self.sel, width=8) self.add_button = Button(self.seladd_frame, text="Add", command=self.add, width=8) self.sel_button.pack(side='left') self.add_button.pack(side='left') self.listbox = Listbox(self.itemframe) self.listbox.pack(fill='both', expand=1) def set_menu(self): self.top_menu = Menu(self) self.cmd_menu = Menu(self.top_menu) self.cmd_menu.add(itemType='command', command=self.sel, label='Select') self.cmd_menu.add(itemType='command', command=self.add, label='Add') self.cmd_menu.add(itemType='separator') self.cmd_menu.add(itemType='command', command=self.quit, label='Quit') self.view_menu = Menu(self.top_menu) self.view_menu.add(itemType='checkbutton', label='Hide items', onvalue=1, offvalue=0, variable=self.hide, command=self.show) self.top_menu.add_cascade(menu=self.cmd_menu, label='Command', underline=0) self.top_menu.add_cascade(menu=self.view_menu, label='View', underline=0) self.master['menu'] = self.top_menu def sel(self): if self._items: self.item.set(random.choice(self._items)) def add(self): self._items.append(self.item.get()) self.listbox.insert('end', self.item.get()) def show(self): if self.hide.get(): self.itemframe.pack_forget() else: self.itemframe.pack(fill="both", expand="1") def quit(self): self.master.destroy()
def __init__(self, master): self.dirname = os.path.abspath( os.curdir ) self.initComplete = 0 self.master = master self.x, self.y, self.w, self.h = -1,-1,-1,-1 # bind master to <Configure> in order to handle any resizing, etc. # postpone self.master.bind("<Configure>", self.Master_Configure) self.master.bind('<Enter>', self.bindConfigure) self.menuBar = Menu(master, relief = "raised", bd=2) top_Directory = Menu(self.menuBar, tearoff=0) top_Directory.add("command", label = "Change Dir", command = self.menu_Directory_Change_Dir) self.menuBar.add("cascade", label="Directory", menu=top_Directory) #top_Snippet = Menu(self.menuBar, tearoff=0) self.menuBar.add("command", label = "Run", command = self.menu_Run) master.config(menu=self.menuBar) # make a Status Bar self.statusMessage = StringVar() self.statusMessage.set(self.dirname) self.statusbar = Label(self.master, textvariable=self.statusMessage, bd=1, relief=SUNKEN) self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM) self.statusbar_bg = self.statusbar.cget('bg') # save bg for restore myFont = tkinter.font.Font(family="Arial", size=12, weight=tkinter.font.BOLD) self.statusbar.config( font=myFont ) frame = Frame(master) frame.pack(anchor=NE, fill=BOTH, side=TOP) self.Pass_Fail_Button = Button(frame,text="Pass/Fail Will Be Shown Here", image="", width="15", background="green", anchor=W, justify=LEFT, padx=2) self.Pass_Fail_Button.pack(anchor=NE, fill=X, side=TOP) self.Pass_Fail_Button.bind("<ButtonRelease-1>", self.Pass_Fail_Button_Click) #self.master.title("tk_nosy") self.master.title('Python %s.%s.%s '%sys.version_info[:3]) self.oscillator = 1 # animates character on title self.oscillator_B = 0 # used to return statusbar to statusbar_bg self.lbframe = Frame( frame ) self.lbframe.pack(anchor=SE, side=LEFT, fill=BOTH, expand=1) scrollbar = Scrollbar(self.lbframe, orient=VERTICAL) self.Text_1 = Text(self.lbframe, width="80", height="24", yscrollcommand=scrollbar.set) scrollbar.config(command=self.Text_1.yview) scrollbar.pack(side=RIGHT, fill=Y) self.Text_1.pack(side=LEFT, fill=BOTH, expand=1) self.master.resizable(1,1) # Linux may not respect this self.numNosyCalls = 0 self.need_to_pick_dir = 1 if len(sys.argv)>1: # I don't care what the exception is, if there's a problem, bail # pylint: disable=W0702 try: dirname = os.path.abspath( sys.argv[1] ) self.try_change_to_new_dir( dirname ) except: pass # let Alarm force dir selection else: try: if os.path.isdir(os.path.join( self.dirname, 'tests' )): self.try_change_to_new_dir( self.dirname ) except: pass # let Alarm force dir selection print(LICENSE) self.Alarm()
class _Tk_Nosy(object): """This class is the tkinter GUI object""" def __init__(self, master): self.dirname = os.path.abspath( os.curdir ) self.initComplete = 0 self.master = master self.x, self.y, self.w, self.h = -1,-1,-1,-1 # bind master to <Configure> in order to handle any resizing, etc. # postpone self.master.bind("<Configure>", self.Master_Configure) self.master.bind('<Enter>', self.bindConfigure) self.menuBar = Menu(master, relief = "raised", bd=2) top_Directory = Menu(self.menuBar, tearoff=0) top_Directory.add("command", label = "Change Dir", command = self.menu_Directory_Change_Dir) self.menuBar.add("cascade", label="Directory", menu=top_Directory) #top_Snippet = Menu(self.menuBar, tearoff=0) self.menuBar.add("command", label = "Run", command = self.menu_Run) master.config(menu=self.menuBar) # make a Status Bar self.statusMessage = StringVar() self.statusMessage.set(self.dirname) self.statusbar = Label(self.master, textvariable=self.statusMessage, bd=1, relief=SUNKEN) self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM) self.statusbar_bg = self.statusbar.cget('bg') # save bg for restore myFont = tkinter.font.Font(family="Arial", size=12, weight=tkinter.font.BOLD) self.statusbar.config( font=myFont ) frame = Frame(master) frame.pack(anchor=NE, fill=BOTH, side=TOP) self.Pass_Fail_Button = Button(frame,text="Pass/Fail Will Be Shown Here", image="", width="15", background="green", anchor=W, justify=LEFT, padx=2) self.Pass_Fail_Button.pack(anchor=NE, fill=X, side=TOP) self.Pass_Fail_Button.bind("<ButtonRelease-1>", self.Pass_Fail_Button_Click) #self.master.title("tk_nosy") self.master.title('Python %s.%s.%s '%sys.version_info[:3]) self.oscillator = 1 # animates character on title self.oscillator_B = 0 # used to return statusbar to statusbar_bg self.lbframe = Frame( frame ) self.lbframe.pack(anchor=SE, side=LEFT, fill=BOTH, expand=1) scrollbar = Scrollbar(self.lbframe, orient=VERTICAL) self.Text_1 = Text(self.lbframe, width="80", height="24", yscrollcommand=scrollbar.set) scrollbar.config(command=self.Text_1.yview) scrollbar.pack(side=RIGHT, fill=Y) self.Text_1.pack(side=LEFT, fill=BOTH, expand=1) self.master.resizable(1,1) # Linux may not respect this self.numNosyCalls = 0 self.need_to_pick_dir = 1 if len(sys.argv)>1: # I don't care what the exception is, if there's a problem, bail # pylint: disable=W0702 try: dirname = os.path.abspath( sys.argv[1] ) self.try_change_to_new_dir( dirname ) except: pass # let Alarm force dir selection else: try: if os.path.isdir(os.path.join( self.dirname, 'tests' )): self.try_change_to_new_dir( self.dirname ) except: pass # let Alarm force dir selection print(LICENSE) self.Alarm() def try_change_to_new_dir(self, dirname): """A legal abspath will switch to dirname.""" # I don't care what the exception is, if there's a problem, bail # pylint: disable=W0702 if dirname: try: dirname = os.path.abspath( dirname ) except: return # let Alarm force dir selection else: return self.dirname = dirname print('Selected dirname =',dirname) fileD.clear() os.chdir( self.dirname ) self.reset_statusbar_bg() self.need_to_pick_dir = 0 #with open(NOSY_USER_DATA_FILE, 'w') as text_file: # text_file.write( self.dirname ) self.numNosyCalls = 0 def reset_statusbar_bg(self): """Return status bar to default state""" self.statusbar.config(bg=self.statusbar_bg) self.statusMessage.set(self.dirname) def set_statusbar_bg(self, c): """Set status bar to show new color and message""" self.statusbar.config(bg=c) self.oscillator_B = 1 # will return to initial color after a few cycles def menu_Directory_Change_Dir(self): """Menu selection to set directory in which to run nosetests""" dirname = self.AskDirectory( title='Choose Directory For Nose Tests', initialdir=".") if dirname: self.try_change_to_new_dir( dirname ) # >>>>>>insert any user code below this comment for section "menu_Directory_Change_Dir" # replace, delete, or comment-out the following print("called menu_Directory_Change_Dir") def menu_Run(self): """User initiates a nosetests run, not file change detection.""" print("called menu_Run") self.callNosy() def callNosy(self): """Run nosetests and display results""" self.numNosyCalls += 1 self.Text_1.delete(1.0, END) # turn indicator button gray while running the tests myFont = tkinter.font.Font(family="Arial", size=12, weight=tkinter.font.BOLD) self.Pass_Fail_Button.config(background="#999999", text='TESTING...', font=myFont) self.master.update() self.master.update_idletasks() # pylint: disable=W0201 self.passedAllTests, numPassed, numFailed, numErrors, numSkipped, outputTextL = \ run_nosetests(self.numNosyCalls) max_len_s = 42 num_lines = 1 for s in outputTextL: self.Text_1.insert(END, s) sL = s.split('\n') for ss in sL: max_len_s = max(max_len_s, len(ss)) num_lines += 1 if self.numNosyCalls % 2: myFont = tkinter.font.Font(family="Arial", size=12, weight=tkinter.font.BOLD) else: myFont = tkinter.font.Font(family="Arial", size=12) if self.passedAllTests: s = 'PASSED' if numPassed > 1: s = 'PASSED ALL %i TESTS'%numPassed elif numPassed == 1: s = 'PASSED ONE TEST' bg="#00ff00" if numSkipped==1: s = 'passed with 1 SKIP' bg = "#00cc00" elif numSkipped > 1: s = 'passed with %i SKIPS'%numSkipped bg = "#00cc00" elif numPassed==0: s = 'No Tests Found' bg="#ff8000" self.Pass_Fail_Button.config(background=bg, text=s, font=myFont) #self.master.geometry('200x50') else: s = 'FAILED %i, ERRORS %i, SKIP %i, PASSED %i'%(numFailed, numErrors, numSkipped, numPassed) self.Pass_Fail_Button.config(background="#ff0000", text=s, font=myFont) #self.master.geometry('516x385') # Show list of files being watched. #self.Text_1.insert(END, '_'*40+'\n') self.Text_1.insert(END, 'WATCHED *.py FILES'.center(40,'_') + '\n' ) self.Text_1.insert(END, '%s%s..\n\n'%(self.dirname,os.path.sep) ) num_lines += 3 len_dirname = len( self.dirname ) keyL = list(fileD.keys()) keyL.sort() lastdir = '' for key in keyL: dn = os.path.dirname( key ) if dn != lastdir: self.Text_1.insert(END, '..'+dn[len_dirname:] + '\n') max_len_s = max(max_len_s, len(dn)+1) lastdir = dn num_lines += 1 s = ' ' +os.path.basename( key ) self.Text_1.insert(END, s + '\n') max_len_s = max(max_len_s, len(s)+1) num_lines += 1 self.Text_1.config(width=max_len_s) self.Text_1.config(height=min(40, num_lines)) self.master.winfo_toplevel().wm_geometry("") def bindConfigure(self, event): """Part of goofy main window setup in tkinter.""" # tkinter requires arguments, but I don't use them # pylint: disable=W0613 if not self.initComplete: self.master.bind("<Configure>", self.Master_Configure) self.initComplete = 1 # return a string containing directory name def AskDirectory(self, title='Choose Directory', initialdir="."): """Run pop-up menu for user to select directory.""" # This is not an error # pylint: disable=E1101 if sys.version_info < (3,): dirname = tkFileDialog.askdirectory(parent=self.master, initialdir=initialdir,title=title) else: dirname = tkinter.filedialog.askdirectory(parent=self.master, initialdir=initialdir,title=title) return dirname # <-- string def Master_Configure(self, event): """Part of tkinter main window initialization""" if event.widget != self.master: if self.w != -1: return x = int(self.master.winfo_x()) y = int(self.master.winfo_y()) w = int(self.master.winfo_width()) h = int(self.master.winfo_height()) if (self.x, self.y, self.w, self.h) == (-1,-1,-1,-1): self.x, self.y, self.w, self.h = x,y,w,h if self.w!=w or self.h!=h: #print "Master reconfigured... make resize adjustments" self.w=w self.h=h def Pass_Fail_Button_Click(self, event): """Place-holder routine for user clicking Pass/Fail Button""" pass # alarm function is called after specified number of milliseconds def SetAlarm(self, milliseconds=1000): """Reinitialize tkinter alarm mechanism as well as update seconds counter in main window title bar. """ self.master.after( milliseconds, self.Alarm ) self.oscillator += 1 if self.oscillator > 5: self.oscillator = 0 if self.oscillator_B>0: self.oscillator_B += 1 if self.oscillator_B>5: self.oscillator_B = 0 self.reset_statusbar_bg() pad = '|'*self.oscillator #self.master.title("%i) tk_nosy "%self.numNosyCalls + pad ) s = '%s.%s.%s '%sys.version_info[:3] self.master.title('%i) Python %s '%(self.numNosyCalls , s + pad )) def Alarm(self): """Look for changed files every second, then reset alarm""" if self.need_to_pick_dir: dirname = self.AskDirectory( title='Choose Directory For Nose Tests', initialdir=".") self.try_change_to_new_dir( dirname ) #first call to numberOfChangedFiles will be > 0 if any .py files are found elif numberOfChangedFiles( self.dirname ) > 0: # or self.numNosyCalls==0 self.callNosy() self.SetAlarm()
def __init__(self, master): self.dirname = os.path.abspath( os.curdir ) self.initComplete = 0 self.master = master self.x, self.y, self.w, self.h = -1,-1,-1,-1 # bind master to <Configure> in order to handle any resizing, etc. # postpone self.master.bind("<Configure>", self.Master_Configure) self.master.bind('<Enter>', self.bindConfigure) self.menuBar = Menu(master, relief = "raised", bd=2) self.menuBar.add("command", label = "Change_Dir", command = self.menu_Directory_Change_Dir) disp_Choices = Menu(self.menuBar, tearoff=0) self.display_test_details = StringVar() self.display_test_details.set('N') disp_Choices.add_checkbutton(label='Display Test Details', variable=self.display_test_details, onvalue='Y', offvalue='N') self.display_watched_files = StringVar() self.display_watched_files.set('N') disp_Choices.add_checkbutton(label='Show Watched Files', variable=self.display_watched_files, onvalue='Y', offvalue='N') self.menuBar.add("cascade", label="Display", menu=disp_Choices) py_choices = Menu(self.menuBar, tearoff=0) py_choices.add("command", label = "Change Python Version", command = self.changePythonVersion) py_choices.add("command", label = "Find New Python Interpreter", command = self.findNewPythonInterpreter) py_choices.add("command", label = "Launch Another Python Interpreter", command = self.launchAnotherPythonInterpreter) self.menuBar.add("cascade", label="Python", menu=py_choices) #top_Snippet = Menu(self.menuBar, tearoff=0) self.menuBar.add("command", label = "Run", command = self.menu_Run) self.display_test_details.trace("w", self.rerun_tests) self.display_watched_files.trace("w", self.rerun_tests) master.config(menu=self.menuBar) # make a Status Bar self.statusMessage = StringVar() self.statusMessage.set(self.dirname) self.statusbar = Label(self.master, textvariable=self.statusMessage, bd=1, relief=SUNKEN) self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM) self.statusbar_bg = self.statusbar.cget('bg') # save bg for restore self.arial_12_bold_font = tkinter.font.Font(family="Arial", size=12, weight=tkinter.font.BOLD) self.arial_12_font = tkinter.font.Font(family="Arial", size=12) self.statusbar.config( font=self.arial_12_bold_font ) frame = Frame(master) frame.pack(anchor=NE, fill=BOTH, side=TOP) self.Pass_Fail_Button = Button(frame,text="Pass/Fail Will Be Shown Here", image="", width="15", background="green", anchor=W, justify=LEFT, padx=2) self.Pass_Fail_Button.pack(anchor=NE, fill=X, side=TOP) self.Pass_Fail_Button.bind("<ButtonRelease-1>", self.Pass_Fail_Button_Click) self.master.title("tk_nosy") self.oscillator = 1 # animates character on title self.oscillator_B = 0 # used to return statusbar to statusbar_bg self.lbframe = Frame( frame ) self.lbframe.pack(anchor=SE, side=LEFT, fill=BOTH, expand=1) scrollbar = Scrollbar(self.lbframe, orient=VERTICAL) self.Text_1 = Text(self.lbframe, width="80", height="24", yscrollcommand=scrollbar.set) scrollbar.config(command=self.Text_1.yview) scrollbar.pack(side=RIGHT, fill=Y) self.Text_1.pack(side=LEFT, fill=BOTH, expand=1) self.master.resizable(1,1) # Linux may not respect this self.numNosyCalls = 0 self.need_to_pick_dir = 1 print('sys.argv =',sys.argv) if len(sys.argv)>1: # I don't care what the exception is, if there's a problem, bail # pylint: disable=W0702 print( "Try Dir =",sys.argv[1] ) try: dirname = os.path.abspath( sys.argv[1] ) self.try_change_to_new_dir( dirname ) except Exception: pass # let Alarm force dir selection else: try: if os.path.isdir(os.path.join( self.dirname, 'tests' )): self.try_change_to_new_dir( self.dirname ) except Exception: pass # let Alarm force dir selection print(LICENSE) self.defaultPyInterp = None # need to identify default python interpreter if Tk_Nosy.pythonInterpreterCollection == None: Tk_Nosy.pythonInterpreterCollection = PyInterpsOnSys() self.defaultPyInterp = Tk_Nosy.pythonInterpreterCollection.get_PI_obj_by_py_path( sys.executable ) #print( Tk_Nosy.pythonInterpreterCollection ) self.Alarm()
class Tk_Nosy(object): """This class is the tkinter GUI object""" # make a collection of python interpreters to choose from pythonInterpreterCollection = None # will be PyInterpsOnSys object # extra python interpreters can run nosetests concurrently to main window # concurrent_versionL contains tuples = (PI, Popup) concurrent_versionL = [] # additional running python interpreters def __init__(self, master): self.dirname = os.path.abspath( os.curdir ) self.initComplete = 0 self.master = master self.x, self.y, self.w, self.h = -1,-1,-1,-1 # bind master to <Configure> in order to handle any resizing, etc. # postpone self.master.bind("<Configure>", self.Master_Configure) self.master.bind('<Enter>', self.bindConfigure) self.menuBar = Menu(master, relief = "raised", bd=2) self.menuBar.add("command", label = "Change_Dir", command = self.menu_Directory_Change_Dir) disp_Choices = Menu(self.menuBar, tearoff=0) self.display_test_details = StringVar() self.display_test_details.set('N') disp_Choices.add_checkbutton(label='Display Test Details', variable=self.display_test_details, onvalue='Y', offvalue='N') self.display_watched_files = StringVar() self.display_watched_files.set('N') disp_Choices.add_checkbutton(label='Show Watched Files', variable=self.display_watched_files, onvalue='Y', offvalue='N') self.menuBar.add("cascade", label="Display", menu=disp_Choices) py_choices = Menu(self.menuBar, tearoff=0) py_choices.add("command", label = "Change Python Version", command = self.changePythonVersion) py_choices.add("command", label = "Find New Python Interpreter", command = self.findNewPythonInterpreter) py_choices.add("command", label = "Launch Another Python Interpreter", command = self.launchAnotherPythonInterpreter) self.menuBar.add("cascade", label="Python", menu=py_choices) #top_Snippet = Menu(self.menuBar, tearoff=0) self.menuBar.add("command", label = "Run", command = self.menu_Run) self.display_test_details.trace("w", self.rerun_tests) self.display_watched_files.trace("w", self.rerun_tests) master.config(menu=self.menuBar) # make a Status Bar self.statusMessage = StringVar() self.statusMessage.set(self.dirname) self.statusbar = Label(self.master, textvariable=self.statusMessage, bd=1, relief=SUNKEN) self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM) self.statusbar_bg = self.statusbar.cget('bg') # save bg for restore self.arial_12_bold_font = tkinter.font.Font(family="Arial", size=12, weight=tkinter.font.BOLD) self.arial_12_font = tkinter.font.Font(family="Arial", size=12) self.statusbar.config( font=self.arial_12_bold_font ) frame = Frame(master) frame.pack(anchor=NE, fill=BOTH, side=TOP) self.Pass_Fail_Button = Button(frame,text="Pass/Fail Will Be Shown Here", image="", width="15", background="green", anchor=W, justify=LEFT, padx=2) self.Pass_Fail_Button.pack(anchor=NE, fill=X, side=TOP) self.Pass_Fail_Button.bind("<ButtonRelease-1>", self.Pass_Fail_Button_Click) self.master.title("tk_nosy") self.oscillator = 1 # animates character on title self.oscillator_B = 0 # used to return statusbar to statusbar_bg self.lbframe = Frame( frame ) self.lbframe.pack(anchor=SE, side=LEFT, fill=BOTH, expand=1) scrollbar = Scrollbar(self.lbframe, orient=VERTICAL) self.Text_1 = Text(self.lbframe, width="80", height="24", yscrollcommand=scrollbar.set) scrollbar.config(command=self.Text_1.yview) scrollbar.pack(side=RIGHT, fill=Y) self.Text_1.pack(side=LEFT, fill=BOTH, expand=1) self.master.resizable(1,1) # Linux may not respect this self.numNosyCalls = 0 self.need_to_pick_dir = 1 print('sys.argv =',sys.argv) if len(sys.argv)>1: # I don't care what the exception is, if there's a problem, bail # pylint: disable=W0702 print( "Try Dir =",sys.argv[1] ) try: dirname = os.path.abspath( sys.argv[1] ) self.try_change_to_new_dir( dirname ) except Exception: pass # let Alarm force dir selection else: try: if os.path.isdir(os.path.join( self.dirname, 'tests' )): self.try_change_to_new_dir( self.dirname ) except Exception: pass # let Alarm force dir selection print(LICENSE) self.defaultPyInterp = None # need to identify default python interpreter if Tk_Nosy.pythonInterpreterCollection == None: Tk_Nosy.pythonInterpreterCollection = PyInterpsOnSys() self.defaultPyInterp = Tk_Nosy.pythonInterpreterCollection.get_PI_obj_by_py_path( sys.executable ) #print( Tk_Nosy.pythonInterpreterCollection ) self.Alarm() def try_change_to_new_dir(self, dirname): """A legal abspath will switch to dirname.""" # I don't care what the exception is, if there's a problem, bail # pylint: disable=W0702 if dirname: try: dirname = os.path.abspath( dirname ) except: return # let Alarm force dir selection else: return self.dirname = dirname print('Selected dirname =',dirname) fileD.clear() os.chdir( self.dirname ) self.reset_statusbar_bg() self.need_to_pick_dir = 0 #with open(NOSY_USER_DATA_FILE, 'w') as text_file: # text_file.write( self.dirname ) self.numNosyCalls = 0 def reset_statusbar_bg(self): """Return status bar to default state""" self.statusbar.config(bg=self.statusbar_bg) self.statusMessage.set(self.dirname) def set_statusbar_bg(self, c): """Set status bar to show new color and message""" self.statusbar.config(bg=c) self.oscillator_B = 1 # will return to initial color after a few cycles def menu_Directory_Change_Dir(self): """Menu selection to set directory in which to run nosetests""" dirname = self.AskDirectory( title='Choose Directory For Nose Tests', initialdir=".") if dirname: self.try_change_to_new_dir( dirname ) # >>>>>>insert any user code below this comment for section "menu_Directory_Change_Dir" # replace, delete, or comment-out the following print("called menu_Directory_Change_Dir") def menu_Run(self): """User initiates a nosetests run, not file change detection.""" print("called menu_Run") self.callNosy() def rerun_tests(self,*args): self.menu_Run() def callNosy(self): """Run nosetests and display results""" self.numNosyCalls += 1 runL = [(self.defaultPyInterp, self)] for PI,Popup in Tk_Nosy.concurrent_versionL: runL.append( (PI, Popup) ) for PI, tkwindow in runL: tkwindow.Text_1.delete(1.0, END) # turn indicator button gray while running the tests tkwindow.Pass_Fail_Button.config(background="#999999", text='TESTING...', font=self.arial_12_bold_font) self.master.update() self.master.update_idletasks() for PI, tkwindow in runL: self.run_tkwin_nosetests( PI, tkwindow) self.master.winfo_toplevel().wm_geometry("") def run_tkwin_nosetests(self, PI, tkwindow): """Run nosetests for main python interpreter and any concurrent python interpreters. Update GUI to show results. """ if PI.nose_version == None: # if nose was not installed last time we checked, check again PI.nose_version, err_msg = get_nose_version_info( PI.full_path ) if PI.nose_version == None: print( "\a" ) # make beep s = 'Can not verify nose for:\nPython ' + PI.name() tkwindow.Pass_Fail_Button.config(background='orange', text=s, font=self.arial_12_bold_font) s = 'Please verify nose installed for:\n'+str(PI) +\ '\n\n' + err_msg+\ '\n\nFor install instructions see:\n'+\ 'https://nose.readthedocs.org/en/latest/' tkwindow.Text_1.insert(END, s ) ShowError(title='Can not verify nose', message=s) return # pylint: disable=W0201 passedAllTests, numPassed, numFailed, numErrors, numSkipped, outputTextL = \ run_nosetests(self.numNosyCalls, PI, display_test_details=self.display_test_details.get()) max_len_s = 42 num_lines = 1 for s in outputTextL: tkwindow.Text_1.insert(END, s) sL = s.split('\n') for ss in sL: max_len_s = max(max_len_s, len(ss)) num_lines += 1 if self.numNosyCalls % 2: myFont = self.arial_12_bold_font else: myFont = self.arial_12_font if passedAllTests: s = 'PASSED' if numPassed > 1: s = 'PASSED ALL %i TESTS'%numPassed elif numPassed == 1: s = 'PASSED ONE TEST' bg="#00ff00" if numSkipped==1: s = 'passed with 1 SKIP' bg = "#00cc00" elif numSkipped > 1: s = 'passed with %i SKIPS'%numSkipped bg = "#00cc00" elif numPassed==0: s = 'No Tests Found' bg="#ff8000" tkwindow.Pass_Fail_Button.config(background=bg, text=s, font=myFont) #self.master.geometry('200x50') else: s = 'FAILED %i, ERRORS %i, SKIP %i, PASSED %i'%(numFailed, numErrors, numSkipped, numPassed) tkwindow.Pass_Fail_Button.config(background="#ff0000", text=s, font=myFont) #self.master.geometry('516x385') # Show list of files being watched. #self.Text_1.insert(END, '_'*40+'\n') tkwindow.Text_1.insert(END, 'WATCHED *.py FILES'.center(40,'_') + '\n' ) tkwindow.Text_1.insert(END, '%s%s..\n\n'%(self.dirname,os.path.sep) ) num_lines += 3 len_dirname = len( self.dirname ) if self.display_watched_files.get()=='Y': keyL = list(fileD.keys()) keyL.sort() lastdir = '' for key in keyL: dn = os.path.dirname( key ) if dn != lastdir: tkwindow.Text_1.insert(END, '..'+dn[len_dirname:] + '\n') max_len_s = max(max_len_s, len(dn)+1) lastdir = dn num_lines += 1 s = ' ' +os.path.basename( key ) tkwindow.Text_1.insert(END, s + '\n') max_len_s = max(max_len_s, len(s)+1) num_lines += 1 else: num_lines += 1 tkwindow.Text_1.insert(END, ' %i files watched.\n'%len(fileD)) tkwindow.Text_1.config(width=max_len_s) tkwindow.Text_1.config(height=min(40, num_lines)) def bindConfigure(self, event): """Part of goofy main window setup in tkinter.""" # tkinter requires arguments, but I don't use them # pylint: disable=W0613 if not self.initComplete: self.master.bind("<Configure>", self.Master_Configure) self.initComplete = 1 def change_python_exe(self, full_path ): """Allow nosetests to be run under any available python version """ PI = Tk_Nosy.pythonInterpreterCollection.add_interp( full_path ) if PI: self.defaultPyInterp = PI def findNewPythonInterpreter(self): """Find a new python interpreter, one that is not already in the PyInterpsOnSys object (pythonInterpreterCollection). """ if Tk_Nosy.pythonInterpreterCollection == None: print( 'pythonInterpreterCollection NOT yet initialized' ) self.statusMessage.set('Interpreter Collection NOT initialized') self.set_statusbar_bg( '#FF9999' ) return print('Open File') filetypes = [ ('python executable','py*'), ('Any File','*.*')] pathopen = tkFileDialog.askopenfilename(parent=self.master, title='Select Python Executable', filetypes=filetypes, initialdir=self.defaultPyInterp.full_path) if pathopen: self.change_python_exe( pathopen ) self.menu_Run() def kill_popup_window(self, popup_name): """Close a popup window running another verions of python interpreter""" for itup, tup in enumerate(Tk_Nosy.concurrent_versionL): PI, Popup = tup s = '%s %s' % (PI.exe_name, PI.version_str) if popup_name == s: Tk_Nosy.concurrent_versionL.pop( itup ) return True # removed popup from list return False # no popup found def launchAnotherPythonInterpreter(self): """Launch a pop-up window that concurrently runs another python version""" removeNameL=[self.defaultPyInterp.name()] for PI,Popup in Tk_Nosy.concurrent_versionL: removeNameL.append( PI.name() ) piL = Tk_Nosy.pythonInterpreterCollection.get_PI_list( removeNameL=removeNameL ) if len(piL)==0: print( 'All identified python interpreters in use.' ) else: print( [pi.name() for pi in piL] ) rbL = [PI.name() for PI in piL] dialog = Select_Py_Version(self.master, "Launch Another Python Version", dialogOptions={'rbL':rbL}) if dialog.result: PI = Tk_Nosy.pythonInterpreterCollection.get_PI_obj_by_name( dialog.result['selection']) s = '%s %s' % (PI.exe_name, PI.version_str) Popup = SatelliteWindow(self, self.master, s) Tk_Nosy.concurrent_versionL.append( (PI, Popup) ) self.menu_Run() def changePythonVersion(self): """Change to a different python version. If the PyInterpsOnSys object (pythonInterpreterCollection) has been initialized, select from its list. Otherwise find the python interpreter executable (ex. python.exe or python) """ if (Tk_Nosy.pythonInterpreterCollection == None) or \ (Tk_Nosy.pythonInterpreterCollection.num_terps() == 0): # If there is no list of available python interpreters, look for python file print('Open File') filetypes = [ ('python executable','py*'), ('Any File','*.*')] pathopen = tkFileDialog.askopenfilename(parent=self.master, title='Select Python Executable', filetypes=filetypes, initialdir=self.defaultPyInterp.full_path) if pathopen: self.change_python_exe( pathopen ) self.menu_Run() else: rbL = [PI.name() for PI in Tk_Nosy.pythonInterpreterCollection.interpL] dialog = Select_Py_Version(self.master, "Select Python Version", dialogOptions={'rbL':rbL}) if dialog.result: PI = Tk_Nosy.pythonInterpreterCollection.get_PI_obj_by_name( dialog.result['selection'] ) pathopen = PI.full_path self.change_python_exe( pathopen ) self.menu_Run() # return a string containing directory name def AskDirectory(self, title='Choose Directory', initialdir="."): """Run pop-up menu for user to select directory.""" # This is not an error # pylint: disable=E1101 if sys.version_info < (3,): dirname = tkFileDialog.askdirectory(parent=self.master, initialdir=initialdir,title=title) else: dirname = tkFileDialog.askdirectory(parent=self.master, initialdir=initialdir,title=title) return dirname # <-- string def Master_Configure(self, event): """Part of tkinter main window initialization""" if event.widget != self.master: if self.w != -1: return x = int(self.master.winfo_x()) y = int(self.master.winfo_y()) w = int(self.master.winfo_width()) h = int(self.master.winfo_height()) if (self.x, self.y, self.w, self.h) == (-1,-1,-1,-1): self.x, self.y, self.w, self.h = x,y,w,h if self.w!=w or self.h!=h: #print "Master reconfigured... make resize adjustments" self.w=w self.h=h # pylint: disable=W0613 def Pass_Fail_Button_Click(self, event): """Routine for user clicking Pass/Fail Button""" print('Arranging Windows by User Request') num_popups = len(Tk_Nosy.concurrent_versionL) DX = 50 DY = 70 x = 10 y = 10 + num_popups * DY self.master.geometry( '+%i+%i'%(x,y)) for PI,Popup in Tk_Nosy.concurrent_versionL: x += DX y -= DY Popup.geometry( '+%i+%i'%(x,y)) # alarm function is called after specified number of milliseconds def SetAlarm(self, milliseconds=1000): """Reinitialize tkinter alarm mechanism as well as update seconds counter in main window title bar. """ self.master.after( milliseconds, self.Alarm ) self.oscillator += 1 if self.oscillator > 5: self.oscillator = 0 if self.oscillator_B>0: self.oscillator_B += 1 if self.oscillator_B>5: self.oscillator_B = 0 self.reset_statusbar_bg() pad = '|'*self.oscillator s = '%s (v%s)'%(self.defaultPyInterp.exe_name, self.defaultPyInterp.version_str) self.master.title('%i) %s '%(self.numNosyCalls , s + pad )) for PI,Popup in Tk_Nosy.concurrent_versionL: s = '%s (v%s)'%(PI.exe_name, PI.version_str) Popup.title( '%i) %s '%(self.numNosyCalls , s + pad ) ) def Alarm(self): """Look for changed files every second, then reset alarm""" if self.need_to_pick_dir: dirname = self.AskDirectory( title='Choose Directory For Nose Tests', initialdir=".") self.try_change_to_new_dir( dirname ) #first call to numberOfChangedFiles will be > 0 if any .py files are found elif numberOfChangedFiles( self.dirname ) > 0: # or self.numNosyCalls==0 self.callNosy() self.SetAlarm()
def __init__(self, master): self.dirname = os.path.abspath(os.curdir) self.initComplete = 0 self.master = master self.x, self.y, self.w, self.h = -1, -1, -1, -1 # bind master to <Configure> in order to handle any resizing, etc. # postpone self.master.bind("<Configure>", self.Master_Configure) self.master.bind('<Enter>', self.bindConfigure) self.menuBar = Menu(master, relief="raised", bd=2) self.menuBar.add("command", label="Change_Dir", command=self.menu_Directory_Change_Dir) disp_Choices = Menu(self.menuBar, tearoff=0) self.display_test_details = StringVar() self.display_test_details.set('N') disp_Choices.add_checkbutton(label='Display Test Details', variable=self.display_test_details, onvalue='Y', offvalue='N') self.display_watched_files = StringVar() self.display_watched_files.set('N') disp_Choices.add_checkbutton(label='Show Watched Files', variable=self.display_watched_files, onvalue='Y', offvalue='N') self.menuBar.add("cascade", label="Display", menu=disp_Choices) py_choices = Menu(self.menuBar, tearoff=0) py_choices.add("command", label="Change Python Version", command=self.changePythonVersion) py_choices.add("command", label="Find New Python Interpreter", command=self.findNewPythonInterpreter) py_choices.add("command", label="Launch Another Python Interpreter", command=self.launchAnotherPythonInterpreter) self.menuBar.add("cascade", label="Python", menu=py_choices) #top_Snippet = Menu(self.menuBar, tearoff=0) self.menuBar.add("command", label="Run", command=self.menu_Run) self.display_test_details.trace("w", self.rerun_tests) self.display_watched_files.trace("w", self.rerun_tests) master.config(menu=self.menuBar) # make a Status Bar self.statusMessage = StringVar() self.statusMessage.set(self.dirname) self.statusbar = Label(self.master, textvariable=self.statusMessage, bd=1, relief=SUNKEN) self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM) self.statusbar_bg = self.statusbar.cget('bg') # save bg for restore self.arial_12_bold_font = tkinter.font.Font(family="Arial", size=12, weight=tkinter.font.BOLD) self.arial_12_font = tkinter.font.Font(family="Arial", size=12) self.statusbar.config(font=self.arial_12_bold_font) frame = Frame(master) frame.pack(anchor=NE, fill=BOTH, side=TOP) self.Pass_Fail_Button = Button(frame, text="Pass/Fail Will Be Shown Here", image="", width="15", background="green", anchor=W, justify=LEFT, padx=2) self.Pass_Fail_Button.pack(anchor=NE, fill=X, side=TOP) self.Pass_Fail_Button.bind("<ButtonRelease-1>", self.Pass_Fail_Button_Click) self.master.title("tk_nosy") self.oscillator = 1 # animates character on title self.oscillator_B = 0 # used to return statusbar to statusbar_bg self.lbframe = Frame(frame) self.lbframe.pack(anchor=SE, side=LEFT, fill=BOTH, expand=1) scrollbar = Scrollbar(self.lbframe, orient=VERTICAL) self.Text_1 = Text(self.lbframe, width="80", height="24", yscrollcommand=scrollbar.set) scrollbar.config(command=self.Text_1.yview) scrollbar.pack(side=RIGHT, fill=Y) self.Text_1.pack(side=LEFT, fill=BOTH, expand=1) self.master.resizable(1, 1) # Linux may not respect this self.numNosyCalls = 0 self.need_to_pick_dir = 1 print('sys.argv =', sys.argv) if len(sys.argv) > 1: # I don't care what the exception is, if there's a problem, bail # pylint: disable=W0702 print("Try Dir =", sys.argv[1]) try: dirname = os.path.abspath(sys.argv[1]) self.try_change_to_new_dir(dirname) except Exception: pass # let Alarm force dir selection else: try: if os.path.isdir(os.path.join(self.dirname, 'tests')): self.try_change_to_new_dir(self.dirname) except Exception: pass # let Alarm force dir selection print(LICENSE) self.defaultPyInterp = None # need to identify default python interpreter if Tk_Nosy.pythonInterpreterCollection == None: Tk_Nosy.pythonInterpreterCollection = PyInterpsOnSys() self.defaultPyInterp = Tk_Nosy.pythonInterpreterCollection.get_PI_obj_by_py_path( sys.executable) #print( Tk_Nosy.pythonInterpreterCollection ) self.Alarm()
class Tk_Nosy(object): """This class is the tkinter GUI object""" # make a collection of python interpreters to choose from pythonInterpreterCollection = None # will be PyInterpsOnSys object # extra python interpreters can run nosetests concurrently to main window # concurrent_versionL contains tuples = (PI, Popup) concurrent_versionL = [] # additional running python interpreters def __init__(self, master): self.dirname = os.path.abspath(os.curdir) self.initComplete = 0 self.master = master self.x, self.y, self.w, self.h = -1, -1, -1, -1 # bind master to <Configure> in order to handle any resizing, etc. # postpone self.master.bind("<Configure>", self.Master_Configure) self.master.bind('<Enter>', self.bindConfigure) self.menuBar = Menu(master, relief="raised", bd=2) self.menuBar.add("command", label="Change_Dir", command=self.menu_Directory_Change_Dir) disp_Choices = Menu(self.menuBar, tearoff=0) self.display_test_details = StringVar() self.display_test_details.set('N') disp_Choices.add_checkbutton(label='Display Test Details', variable=self.display_test_details, onvalue='Y', offvalue='N') self.display_watched_files = StringVar() self.display_watched_files.set('N') disp_Choices.add_checkbutton(label='Show Watched Files', variable=self.display_watched_files, onvalue='Y', offvalue='N') self.menuBar.add("cascade", label="Display", menu=disp_Choices) py_choices = Menu(self.menuBar, tearoff=0) py_choices.add("command", label="Change Python Version", command=self.changePythonVersion) py_choices.add("command", label="Find New Python Interpreter", command=self.findNewPythonInterpreter) py_choices.add("command", label="Launch Another Python Interpreter", command=self.launchAnotherPythonInterpreter) self.menuBar.add("cascade", label="Python", menu=py_choices) #top_Snippet = Menu(self.menuBar, tearoff=0) self.menuBar.add("command", label="Run", command=self.menu_Run) self.display_test_details.trace("w", self.rerun_tests) self.display_watched_files.trace("w", self.rerun_tests) master.config(menu=self.menuBar) # make a Status Bar self.statusMessage = StringVar() self.statusMessage.set(self.dirname) self.statusbar = Label(self.master, textvariable=self.statusMessage, bd=1, relief=SUNKEN) self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM) self.statusbar_bg = self.statusbar.cget('bg') # save bg for restore self.arial_12_bold_font = tkinter.font.Font(family="Arial", size=12, weight=tkinter.font.BOLD) self.arial_12_font = tkinter.font.Font(family="Arial", size=12) self.statusbar.config(font=self.arial_12_bold_font) frame = Frame(master) frame.pack(anchor=NE, fill=BOTH, side=TOP) self.Pass_Fail_Button = Button(frame, text="Pass/Fail Will Be Shown Here", image="", width="15", background="green", anchor=W, justify=LEFT, padx=2) self.Pass_Fail_Button.pack(anchor=NE, fill=X, side=TOP) self.Pass_Fail_Button.bind("<ButtonRelease-1>", self.Pass_Fail_Button_Click) self.master.title("tk_nosy") self.oscillator = 1 # animates character on title self.oscillator_B = 0 # used to return statusbar to statusbar_bg self.lbframe = Frame(frame) self.lbframe.pack(anchor=SE, side=LEFT, fill=BOTH, expand=1) scrollbar = Scrollbar(self.lbframe, orient=VERTICAL) self.Text_1 = Text(self.lbframe, width="80", height="24", yscrollcommand=scrollbar.set) scrollbar.config(command=self.Text_1.yview) scrollbar.pack(side=RIGHT, fill=Y) self.Text_1.pack(side=LEFT, fill=BOTH, expand=1) self.master.resizable(1, 1) # Linux may not respect this self.numNosyCalls = 0 self.need_to_pick_dir = 1 print('sys.argv =', sys.argv) if len(sys.argv) > 1: # I don't care what the exception is, if there's a problem, bail # pylint: disable=W0702 print("Try Dir =", sys.argv[1]) try: dirname = os.path.abspath(sys.argv[1]) self.try_change_to_new_dir(dirname) except Exception: pass # let Alarm force dir selection else: try: if os.path.isdir(os.path.join(self.dirname, 'tests')): self.try_change_to_new_dir(self.dirname) except Exception: pass # let Alarm force dir selection print(LICENSE) self.defaultPyInterp = None # need to identify default python interpreter if Tk_Nosy.pythonInterpreterCollection == None: Tk_Nosy.pythonInterpreterCollection = PyInterpsOnSys() self.defaultPyInterp = Tk_Nosy.pythonInterpreterCollection.get_PI_obj_by_py_path( sys.executable) #print( Tk_Nosy.pythonInterpreterCollection ) self.Alarm() def try_change_to_new_dir(self, dirname): """A legal abspath will switch to dirname.""" # I don't care what the exception is, if there's a problem, bail # pylint: disable=W0702 if dirname: try: dirname = os.path.abspath(dirname) except: return # let Alarm force dir selection else: return self.dirname = dirname print('Selected dirname =', dirname) fileD.clear() os.chdir(self.dirname) self.reset_statusbar_bg() self.need_to_pick_dir = 0 #with open(NOSY_USER_DATA_FILE, 'w') as text_file: # text_file.write( self.dirname ) self.numNosyCalls = 0 def reset_statusbar_bg(self): """Return status bar to default state""" self.statusbar.config(bg=self.statusbar_bg) self.statusMessage.set(self.dirname) def set_statusbar_bg(self, c): """Set status bar to show new color and message""" self.statusbar.config(bg=c) self.oscillator_B = 1 # will return to initial color after a few cycles def menu_Directory_Change_Dir(self): """Menu selection to set directory in which to run nosetests""" dirname = self.AskDirectory(title='Choose Directory For Nose Tests', initialdir=".") if dirname: self.try_change_to_new_dir(dirname) # >>>>>>insert any user code below this comment for section "menu_Directory_Change_Dir" # replace, delete, or comment-out the following print("called menu_Directory_Change_Dir") def menu_Run(self): """User initiates a nosetests run, not file change detection.""" print("called menu_Run") self.callNosy() def rerun_tests(self, *args): self.menu_Run() def callNosy(self): """Run nosetests and display results""" self.numNosyCalls += 1 runL = [(self.defaultPyInterp, self)] for PI, Popup in Tk_Nosy.concurrent_versionL: runL.append((PI, Popup)) for PI, tkwindow in runL: tkwindow.Text_1.delete(1.0, END) # turn indicator button gray while running the tests tkwindow.Pass_Fail_Button.config(background="#999999", text='TESTING...', font=self.arial_12_bold_font) self.master.update() self.master.update_idletasks() for PI, tkwindow in runL: self.run_tkwin_nosetests(PI, tkwindow) self.master.winfo_toplevel().wm_geometry("") def run_tkwin_nosetests(self, PI, tkwindow): """Run nosetests for main python interpreter and any concurrent python interpreters. Update GUI to show results. """ if PI.nose_version == None: # if nose was not installed last time we checked, check again PI.nose_version, err_msg = get_nose_version_info(PI.full_path) if PI.nose_version == None: print("\a") # make beep s = 'Can not verify nose for:\nPython ' + PI.name() tkwindow.Pass_Fail_Button.config(background='orange', text=s, font=self.arial_12_bold_font) s = 'Please verify nose installed for:\n'+str(PI) +\ '\n\n' + err_msg+\ '\n\nFor install instructions see:\n'+\ 'https://nose.readthedocs.org/en/latest/' tkwindow.Text_1.insert(END, s) ShowError(title='Can not verify nose', message=s) return # pylint: disable=W0201 passedAllTests, numPassed, numFailed, numErrors, numSkipped, outputTextL = \ run_nosetests(self.numNosyCalls, PI, display_test_details=self.display_test_details.get()) max_len_s = 42 num_lines = 1 for s in outputTextL: tkwindow.Text_1.insert(END, s) sL = s.split('\n') for ss in sL: max_len_s = max(max_len_s, len(ss)) num_lines += 1 if self.numNosyCalls % 2: myFont = self.arial_12_bold_font else: myFont = self.arial_12_font if passedAllTests: s = 'PASSED' if numPassed > 1: s = 'PASSED ALL %i TESTS' % numPassed elif numPassed == 1: s = 'PASSED ONE TEST' bg = "#00ff00" if numSkipped == 1: s = 'passed with 1 SKIP' bg = "#00cc00" elif numSkipped > 1: s = 'passed with %i SKIPS' % numSkipped bg = "#00cc00" elif numPassed == 0: s = 'No Tests Found' bg = "#ff8000" tkwindow.Pass_Fail_Button.config(background=bg, text=s, font=myFont) #self.master.geometry('200x50') else: s = 'FAILED %i, ERRORS %i, SKIP %i, PASSED %i' % ( numFailed, numErrors, numSkipped, numPassed) tkwindow.Pass_Fail_Button.config(background="#ff0000", text=s, font=myFont) #self.master.geometry('516x385') # Show list of files being watched. #self.Text_1.insert(END, '_'*40+'\n') tkwindow.Text_1.insert(END, 'WATCHED *.py FILES'.center(40, '_') + '\n') tkwindow.Text_1.insert(END, '%s%s..\n\n' % (self.dirname, os.path.sep)) num_lines += 3 len_dirname = len(self.dirname) if self.display_watched_files.get() == 'Y': keyL = list(fileD.keys()) keyL.sort() lastdir = '' for key in keyL: dn = os.path.dirname(key) if dn != lastdir: tkwindow.Text_1.insert(END, '..' + dn[len_dirname:] + '\n') max_len_s = max(max_len_s, len(dn) + 1) lastdir = dn num_lines += 1 s = ' ' + os.path.basename(key) tkwindow.Text_1.insert(END, s + '\n') max_len_s = max(max_len_s, len(s) + 1) num_lines += 1 else: num_lines += 1 tkwindow.Text_1.insert(END, ' %i files watched.\n' % len(fileD)) tkwindow.Text_1.config(width=max_len_s) tkwindow.Text_1.config(height=min(40, num_lines)) def bindConfigure(self, event): """Part of goofy main window setup in tkinter.""" # tkinter requires arguments, but I don't use them # pylint: disable=W0613 if not self.initComplete: self.master.bind("<Configure>", self.Master_Configure) self.initComplete = 1 def change_python_exe(self, full_path): """Allow nosetests to be run under any available python version """ PI = Tk_Nosy.pythonInterpreterCollection.add_interp(full_path) if PI: self.defaultPyInterp = PI def findNewPythonInterpreter(self): """Find a new python interpreter, one that is not already in the PyInterpsOnSys object (pythonInterpreterCollection). """ if Tk_Nosy.pythonInterpreterCollection == None: print('pythonInterpreterCollection NOT yet initialized') self.statusMessage.set('Interpreter Collection NOT initialized') self.set_statusbar_bg('#FF9999') return print('Open File') filetypes = [('python executable', 'py*'), ('Any File', '*.*')] pathopen = tkFileDialog.askopenfilename( parent=self.master, title='Select Python Executable', filetypes=filetypes, initialdir=self.defaultPyInterp.full_path) if pathopen: self.change_python_exe(pathopen) self.menu_Run() def kill_popup_window(self, popup_name): """Close a popup window running another versions of python interpreter""" for itup, tup in enumerate(Tk_Nosy.concurrent_versionL): PI, Popup = tup s = '%s %s' % (PI.exe_name, PI.version_str) if popup_name == s: Tk_Nosy.concurrent_versionL.pop(itup) return True # removed popup from list return False # no popup found def launchAnotherPythonInterpreter(self): """Launch a pop-up window that concurrently runs another python version""" removeNameL = [self.defaultPyInterp.name()] for PI, Popup in Tk_Nosy.concurrent_versionL: removeNameL.append(PI.name()) piL = Tk_Nosy.pythonInterpreterCollection.get_PI_list( removeNameL=removeNameL) if len(piL) == 0: print('All identified python interpreters in use.') else: print([pi.name() for pi in piL]) rbL = [PI.name() for PI in piL] dialog = Select_Py_Version(self.master, "Launch Another Python Version", dialogOptions={'rbL': rbL}) if dialog.result: PI = Tk_Nosy.pythonInterpreterCollection.get_PI_obj_by_name( dialog.result['selection']) s = '%s %s' % (PI.exe_name, PI.version_str) Popup = SatelliteWindow(self, self.master, s) Tk_Nosy.concurrent_versionL.append((PI, Popup)) self.menu_Run() def changePythonVersion(self): """Change to a different python version. If the PyInterpsOnSys object (pythonInterpreterCollection) has been initialized, select from its list. Otherwise find the python interpreter executable (ex. python.exe or python) """ if (Tk_Nosy.pythonInterpreterCollection == None) or \ (Tk_Nosy.pythonInterpreterCollection.num_terps() == 0): # If there is no list of available python interpreters, look for python file print('Open File') filetypes = [('python executable', 'py*'), ('Any File', '*.*')] pathopen = tkFileDialog.askopenfilename( parent=self.master, title='Select Python Executable', filetypes=filetypes, initialdir=self.defaultPyInterp.full_path) if pathopen: self.change_python_exe(pathopen) self.menu_Run() else: rbL = [ PI.name() for PI in Tk_Nosy.pythonInterpreterCollection.interpL ] dialog = Select_Py_Version(self.master, "Select Python Version", dialogOptions={'rbL': rbL}) if dialog.result: PI = Tk_Nosy.pythonInterpreterCollection.get_PI_obj_by_name( dialog.result['selection']) pathopen = PI.full_path self.change_python_exe(pathopen) self.menu_Run() # return a string containing directory name def AskDirectory(self, title='Choose Directory', initialdir="."): """Run pop-up menu for user to select directory.""" # This is not an error # pylint: disable=E1101 if sys.version_info < (3, ): dirname = tkFileDialog.askdirectory(parent=self.master, initialdir=initialdir, title=title) else: dirname = tkFileDialog.askdirectory(parent=self.master, initialdir=initialdir, title=title) return dirname # <-- string def Master_Configure(self, event): """Part of tkinter main window initialization""" if event.widget != self.master: if self.w != -1: return x = int(self.master.winfo_x()) y = int(self.master.winfo_y()) w = int(self.master.winfo_width()) h = int(self.master.winfo_height()) if (self.x, self.y, self.w, self.h) == (-1, -1, -1, -1): self.x, self.y, self.w, self.h = x, y, w, h if self.w != w or self.h != h: #print "Master reconfigured... make resize adjustments" self.w = w self.h = h # pylint: disable=W0613 def Pass_Fail_Button_Click(self, event): """Routine for user clicking Pass/Fail Button""" print('Arranging Windows by User Request') num_popups = len(Tk_Nosy.concurrent_versionL) DX = 50 DY = 70 x = 10 y = 10 + num_popups * DY self.master.geometry('+%i+%i' % (x, y)) for PI, Popup in Tk_Nosy.concurrent_versionL: x += DX y -= DY Popup.geometry('+%i+%i' % (x, y)) # alarm function is called after specified number of milliseconds def SetAlarm(self, milliseconds=1000): """Reinitialize tkinter alarm mechanism as well as update seconds counter in main window title bar. """ self.master.after(milliseconds, self.Alarm) self.oscillator += 1 if self.oscillator > 5: self.oscillator = 0 if self.oscillator_B > 0: self.oscillator_B += 1 if self.oscillator_B > 5: self.oscillator_B = 0 self.reset_statusbar_bg() pad = '|' * self.oscillator s = '%s (v%s)' % (self.defaultPyInterp.exe_name, self.defaultPyInterp.version_str) self.master.title('%i) %s ' % (self.numNosyCalls, s + pad)) for PI, Popup in Tk_Nosy.concurrent_versionL: s = '%s (v%s)' % (PI.exe_name, PI.version_str) Popup.title('%i) %s ' % (self.numNosyCalls, s + pad)) def Alarm(self): """Look for changed files every second, then reset alarm""" if self.need_to_pick_dir: dirname = self.AskDirectory( title='Choose Directory For Nose Tests', initialdir=".") self.try_change_to_new_dir(dirname) #first call to numberOfChangedFiles will be > 0 if any .py files are found elif numberOfChangedFiles(self.dirname) > 0: # or self.numNosyCalls==0 self.callNosy() self.SetAlarm()
class mgmainmenu: # init application menubar, the Dump Options menu and the Database Select options + another Info/help/about # the callbacks are in a dictionary like "newfilefn":MGU_newfilefn ... # the statevars are in a dictionary like "dumpfileopt":MGU_dumpfileoptval # caller provides them... menu state changes update them/ call them def __init__(self, topwin, keyvalcallbacks, keyvalstatevars): self.parent = topwin self.menubar = Menu(self.parent) self.keyvalstatevars = keyvalstatevars #???self.view_menu = Menu(self.menubar) # the file menu Command_button = Menubutton(self.menubar, text='Simple Button Commands', underline=0) Command_button.menu = Menu(Command_button) #Command_button.menu = Menu(self.menubar) Command_button.menu.add_command(label="Undo") # undo is the 0th entry... Command_button.menu.entryconfig(0, state=DISABLED) Command_button.menu.add_command(label='New...', underline=0, command=keyvalcallbacks["newfilefn"]) Command_button.menu.add_command(label='Open...', underline=0, command=keyvalcallbacks["openfilefn"]) Command_button.menu.add_command( label='ReScan...', underline=0, command=keyvalcallbacks["rescanmenufn"]) # alternate font example Command_button.menu.add_command( label='Print', underline=0, font='-*-helvetica-*-r-*-*-*-180-*-*-*-*-*-*', command=keyvalcallbacks["printmenufn"]) # separator example Command_button.menu.add('separator') Command_button.menu.add_command( label='Options', underline=0, font='-*-helvetica-*-r-*-*-*-180-*-*-*-*-*-*', command=keyvalcallbacks["optionmenufn"]) # aLternate color example Command_button.menu.add_command(label='Quit', underline=0, background='red', activebackground='green', command=keyvalcallbacks["quitmenufn"]) self.menubar.add_cascade(label='File', menu=Command_button.menu) #self.menubar.add_cascade(label='View', menu=self.view_menu) # add a menubar menu to select option for dumping all elements, or only Dups or only Unique self.dumpselect_menu = Menu(self.menubar) self.dumpradioval = IntVar() self.dumpradioval.set(1) self.dumpselect_menu.add_radiobutton( label="Dump All", value=1, variable=keyvalstatevars['DumpOptions']) self.dumpselect_menu.add_radiobutton( label="Dump only unique", value=2, variable=keyvalstatevars['DumpOptions']) self.dumpselect_menu.add_radiobutton( label="Dump only Dups", value=3, variable=keyvalstatevars['DumpOptions']) self.dumpselect_menu.add('separator') self.dumpselect_menu.add_command( label='Default header log path', underline=0, background='red', activebackground='green', command=keyvalcallbacks["dumppath1menufn"]) self.menubar.add_cascade(label='Dump File options', menu=self.dumpselect_menu) self.dumpdbselect_menu1 = Menu(self.menubar) self.menubar.add_cascade(label='Dump DB selection', menu=self.dumpdbselect_menu1) # add a placeholder for this menu with zero databases added in memory # this DUMP DB menu will be dynamically extended as new databases are scanned. # the parent owner of the class instance must call the add method of this class to extend the menu self.dumpdbselect_menu1.add_command(label="<None>") # <None> is the 0th entry... self.dumpdbselect_menu1.entryconfig(0, state=DISABLED) # set a flag just so we can delete this <None> placeholder during first menu add operation self.newmenu = True self.dumpvolselect_menu1 = Menu(self.menubar) self.menubar.add_cascade(label='Dump Volume selection', menu=self.dumpvolselect_menu1) # add a placeholder for this menu with zero databases added in memory # this DUMP DB menu will be dynamically extended as new databases are scanned. # the parent owner of the class instance must call the add method of this class to extend the menu self.dumpvolselect_menu1.add_command(label="<None>") # <None> is the 0th entry... self.dumpvolselect_menu1.entryconfig(0, state=DISABLED) # set a flag just so we can delete this <None> placeholder during first menu add operation self.newvolmenu = True # menu begins with only one option- dump all #self.dumpdbselect_menu1.add_checkbutton(label="<None>", onvalue=False, offvalue=False, variable=self.var01)#variable=self.show_all) # # add a menubar menu for the app info Help/ about/ etc self.show_all = IntVar() self.show_all.set(True) self.vendorhelp_menu = Menu(self.menubar) self.help001 = {"Help": self.show_all} # menu begins with only one option- dump all self.vendorhelp_menu.add_checkbutton( label="Show _Hints", onvalue=True, offvalue=False, variable=keyvalstatevars['HintsFlag']) self.vendorhelp_menu.add_checkbutton( label="Monitor volumes (10second timer activity)", onvalue=True, offvalue=False, variable=keyvalstatevars['TimerCheck']) self.vendorhelp_menu.add_command(label='Help...', underline=0, command=keyvalcallbacks["helpmenufn"]) # separator example self.vendorhelp_menu.add('separator') self.vendorhelp_menu.add_command(label='Dbg info dump...', underline=0, command=self.MGmenudumpdbg) self.vendorhelp_menu.add_checkbutton( label='Dbg runtime info@HIGH', onvalue=True, offvalue=False, variable=keyvalstatevars['DebuginfohighFlag']) self.vendorhelp_menu.add_command( label='About...', underline=0, command=keyvalcallbacks["aboutmenufn"]) self.menubar.add_cascade(label='Help', menu=self.vendorhelp_menu) # register all this with the callers parent window frame self.parent.config(menu=self.menubar) # add a menuitem to the check options in the database selection menu list # this option allows the databases to be added as they are specified & scanned by user # later used as criteria for which source data to include in the dump of memory database # NOTE that the caller MUST extend the @keyvalstatevars[] list to include the newlabel Key-Value pair for this new item with an associated BooleanVar() # and init the associated variable (I default to False i.e. unchecked) def mgmenuitem_adddb(self, newlabel, addseparator=False): # if this is the first database added, lets remove the <None> menu option! if self.newmenu: self.newmenu = False self.dumpdbselect_menu1.delete(0, END) self.dumpdbselect_menu1.add_checkbutton( label=newlabel, onvalue=True, offvalue=False, variable=self.keyvalstatevars[newlabel]) if addseparator: self.dumpdbselect_menu1.add('separator') def mgmenuitem_addvol(self, newlabel, addseparator=False): # if this is the first database added, lets remove the <None> menu option! if self.newmenu: self.newmenu = False self.dumpdbselect_menu1.delete(0, END) self.dumpvolselect_menu1.add_checkbutton( label=newlabel, onvalue=True, offvalue=False, variable=self.keyvalstatevars[newlabel]) if addseparator: self.dumpvolselect_menu1.add( 'separator' ) # get the menu radio selection for including All/Unique/Duplicate files in the dump #def mgmenuselection_dumpoptions_get(self): # return self.dumpradioval.get() ALL OF THE MENU STATES SHOULD LIE IN PARENT OF THIS INSTANCE! see keyvalstatevars{} # def MGmenugroups_get(self): # return self.mgmenuselection_dumpoptions_get(), self.keyvalstatevars.it # tutorial dump of the state of the menu vars dictionary def MGmenudumpdbg(self): for i, (k, v) in enumerate(self.keyvalstatevars.items()): print(i, k, v.get())