class TestMultiItemsList(unittest.TestCase): """ Test the GUI application and it's different GUI events """ def setUp(self): self.root = tk.Tk() self.root.withdraw() #Create list of headers self.headers = ['A', 'B', 'C'] self.multi_items_list = MultiItemsList(self.root, self.headers) self.number_of_elements = 8 + random.randrange(15) #Create a result tuple for testing multi_items_list results_tuple = [] for i in range(self.number_of_elements): results_tuple.append(('X'+str(i), 'Y'+str(i), 'Z'+str(i))) self.multi_items_list.populate_rows(results_tuple) #Get Id of all elements in treeview self.iid_tuple = self.multi_items_list.scroll_tree.get_children() def test_only_single_selection_is_allowed(self): check_browse_option = self.multi_items_list.scroll_tree['selectmode'] self.assertEqual(str(check_browse_option),'browse') def test_number_of_elements_in_tree_view(self): self.assertEqual(self.number_of_elements, len(self.iid_tuple)) def test_number_of_headers_in_tree_view(self): count_headers = 0 headers_list = [] while True: try: headers_list.append( self.multi_items_list.scroll_tree.heading( column=count_headers, option='text')) except tk.TclError: break count_headers = count_headers + 1 self.assertTrue(count_headers<=len(self.headers)) def tearDown(self): self.root.destroy() del self.root
def setUp(self): self.root = tk.Tk() self.root.withdraw() #Create list of headers self.headers = ['A', 'B', 'C'] self.multi_items_list = MultiItemsList(self.root, self.headers) self.number_of_elements = 8 + random.randrange(15) #Create a result tuple for testing multi_items_list results_tuple = [] for i in range(self.number_of_elements): results_tuple.append(('X' + str(i), 'Y' + str(i), 'Z' + str(i))) self.multi_items_list.populate_rows(results_tuple) #Get Id of all elements in treeview self.iid_tuple = self.multi_items_list.scroll_tree.get_children()
def create_multitem_treeview(self): """ Create multitem treeview to show search results with headers : 1. Python Module 2. Installed version 3. Available versions """ self.headers = ['Python Module','Installed Version'] from pip_tkinter.utils import MultiItemsList self.multi_items_list = MultiItemsList(self, self.headers) self.multi_items_list.myframe.grid( row=0, column=0, columnspan=3, sticky='nswe') self.multi_items_list.scroll_tree.bind( '<<TreeviewSelect>>', lambda x : self.scroll_tree_select()) #self.refresh_installed_packages() self.package_subwindow = tk.LabelFrame( self, text="Package Details", padx=5, pady=5) self.package_subwindow.grid( row=1, column=0, columnspan=3, sticky='nswe') self.package_details = tk.Text( self.package_subwindow, wrap='word', height=5) self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') self.package_details.pack(side='left', fill='x', expand='yes') yscrollbar=ttk.Scrollbar( self.package_subwindow, orient='vertical', command=self.package_details.yview) yscrollbar.pack(side='right', fill='y') self.package_details["yscrollcommand"]=yscrollbar.set self.multi_items_list.scroll_tree.bind( "<Double-Button-1>", lambda x: self.show_summary())
class TestMultiItemsList(unittest.TestCase): """ Test the GUI application and it's different GUI events """ def setUp(self): self.root = tk.Tk() self.root.withdraw() #Create list of headers self.headers = ['A', 'B', 'C'] self.multi_items_list = MultiItemsList(self.root, self.headers) self.number_of_elements = 8 + random.randrange(15) #Create a result tuple for testing multi_items_list results_tuple = [] for i in range(self.number_of_elements): results_tuple.append(('X' + str(i), 'Y' + str(i), 'Z' + str(i))) self.multi_items_list.populate_rows(results_tuple) #Get Id of all elements in treeview self.iid_tuple = self.multi_items_list.scroll_tree.get_children() def test_only_single_selection_is_allowed(self): check_browse_option = self.multi_items_list.scroll_tree['selectmode'] self.assertEqual(str(check_browse_option), 'browse') def test_number_of_elements_in_tree_view(self): self.assertEqual(self.number_of_elements, len(self.iid_tuple)) def test_number_of_headers_in_tree_view(self): count_headers = 0 headers_list = [] while True: try: headers_list.append( self.multi_items_list.scroll_tree.heading( column=count_headers, option='text')) except tk.TclError: break count_headers = count_headers + 1 self.assertTrue(count_headers <= len(self.headers)) def tearDown(self): self.root.destroy() del self.root
def create_multitem_treeview(self): """ Create multitem treeview to show search results with headers : 1. Python Module 2. Installed version """ self.headers = ['Python Module','Installed Version'] from pip_tkinter.utils import MultiItemsList self.multi_items_list = MultiItemsList(self, self.headers) self.multi_items_list.myframe.grid( row=0, column=0, columnspan=4, sticky='nswe') self.multi_items_list.scroll_tree.bind( '<<TreeviewSelect>>', lambda x : self.scroll_tree_select()) self.multi_items_list.scroll_tree.config(selectmode='extended')
def create_multitem_treeview(self): """ Create multitem treeview to show search results with headers : 1. Python Module 2. Installed Version 3. Available Version List of buttons : 1. navigate_back 2. navigate_next 3. search_button """ self.headers = ['Python Module', 'Available Version'] from pip_tkinter.utils import MultiItemsList self.multi_items_list = MultiItemsList(self, self.headers) self.multi_items_list.scroll_tree.bind( '<<TreeviewSelect>>', lambda x : self.scroll_tree_select()) self.multi_items_list.myframe.grid( row=1, column=0, columnspan=4, sticky='nsew') self.package_subwindow = tk.LabelFrame( self, text="Package Details", padx=5, pady=5) self.package_subwindow.grid( row=2, column=0, columnspan=4, sticky='nswe') self.package_details = tk.Text( self.package_subwindow, wrap='word', height=5) self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') self.package_details.pack(side='left', fill='x', expand='yes') yscrollbar=ttk.Scrollbar( self.package_subwindow, orient='vertical', command=self.package_details.yview) yscrollbar.pack(side='right', fill='y') self.package_details["yscrollcommand"]=yscrollbar.set self.multi_items_list.scroll_tree.bind( "<Double-Button-1>", lambda x: self.show_summary())
def setUp(self): self.root = tk.Tk() self.root.withdraw() #Create list of headers self.headers = ['A', 'B', 'C'] self.multi_items_list = MultiItemsList(self.root, self.headers) self.number_of_elements = 8 + random.randrange(15) #Create a result tuple for testing multi_items_list results_tuple = [] for i in range(self.number_of_elements): results_tuple.append(('X'+str(i), 'Y'+str(i), 'Z'+str(i))) self.multi_items_list.populate_rows(results_tuple) #Get Id of all elements in treeview self.iid_tuple = self.multi_items_list.scroll_tree.get_children()
class InstallFromPythonlibs(ttk.Frame): def __init__(self, parent, controller): ttk.Frame.__init__(self, parent, borderwidth=3, padding=0.5, relief='ridge') self.grid(row=0, column=0, sticky='nse', pady=(1, 1), padx=(1, 1)) self.controller = controller self.rowconfigure(1, weight=1) self.columnconfigure(0, weight=1) self.create_buttons() self.create_multitem_treeview() self.create_search_bar() def create_buttons(self): """ Create back and next buttons, Also creates option menu for selecting compatibility tag """ self.navigate_back = ttk.Button( self, text='Back', command=lambda: self.navigate_previous_frame()) self.navigate_back.grid(row=3, column=0, sticky='w') options = ('Select compatible dist.', ) self.options_var = tk.StringVar(self) self.options_var.set(options[0]) self.option_menu = tk.OptionMenu(self, self.options_var, *options) self.option_menu.grid(row=3, column=1, sticky='e') self.option_menu.config(state='disabled') self.sync_button = ttk.Button( self, text='Sync', command=lambda: self.sync_pythonlibs_packages()) self.sync_button.grid(row=3, column=2, sticky='e') self.navigate_next = ttk.Button( self, text='Install', command=lambda: self.execute_pip_commands()) self.navigate_next.grid(row=3, column=3, sticky='e') def navigate_previous_frame(self): """ Navigate to previous frame """ self.controller.controller.show_frame('WelcomePage') def sync_pythonlibs_packages(self): """ Sync the json file for PythonLibs at : https://raw.githubusercontent.com/upendra-k14/pythonlibs_modules/master/pythonlibs.json """ from pip_tkinter.utils import create_resource_directory resource_dir = create_resource_directory() url = "https://raw.githubusercontent.com/upendra-k14/pythonlibs_modules/master/pythonlibs.json" self.update_queue = multiprocessing.Queue() self.after(10, self.update_sync_messages) self.sync_button.config(state='disabled') from pip_tkinter.utils import downloadfile downloadfile(url, self.update_queue) def update_sync_messages(self): try: message = self.update_queue.get(0) if (message[0] == 3): self.controller.debug_bar.config(text=message[1]) self.sync_button.config(state='normal') return elif (message[0] == 1 or message[0] == 0): self.controller.debug_bar.config( text='Syncing : {}'.format(str(message[1]))) self.after(10, self.update_sync_messages) elif (message[0] == 2): self.controller.debug_bar.config(text=message[1]) self.sync_button.config(state='normal') return except queue.Empty: self.after(10, self.update_sync_messages) def create_search_bar(self): style = ttk.Style() style.configure('Search.entry') #Create search bar and button self.search_var = tk.StringVar() self.entry = ttk.Entry(self, style='Search.entry', textvariable=self.search_var) self.entry.bind('<Return>', lambda event: self.update_search_results()) self.search_button = ttk.Button( self, text='Search', command=lambda: self.update_search_results()) self.entry.grid(row=0, column=0, columnspan=3, padx=3, pady=3, sticky='nwe') self.search_button.grid(row=0, column=3, padx=1, pady=0, sticky='nw') def create_multitem_treeview(self): """ Create multitem treeview to show search results with headers : 1. Python Module 2. Installed Version 3. Available Version List of buttons : 1. navigate_back 2. navigate_next 3. search_button """ self.headers = ['Python Module', 'Available Version'] from pip_tkinter.utils import MultiItemsList self.multi_items_list = MultiItemsList(self, self.headers) self.multi_items_list.scroll_tree.bind( '<<TreeviewSelect>>', lambda x: self.scroll_tree_select()) self.multi_items_list.myframe.grid(row=1, column=0, columnspan=4, sticky='nsew') self.package_subwindow = tk.LabelFrame(self, text="Package Details", padx=5, pady=5) self.package_subwindow.grid(row=2, column=0, columnspan=4, sticky='nswe') self.package_details = tk.Text(self.package_subwindow, wrap='word', height=5) self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') self.package_details.pack(side='left', fill='x', expand='yes') yscrollbar = ttk.Scrollbar(self.package_subwindow, orient='vertical', command=self.package_details.yview) yscrollbar.pack(side='right', fill='y') self.package_details["yscrollcommand"] = yscrollbar.set self.multi_items_list.scroll_tree.bind("<Double-Button-1>", lambda x: self.show_summary()) def scroll_tree_select(self): """ If treeview is selected, enable update buttons """ self.navigate_next.config(state='normal') def show_summary(self): """ Show the details of the selected package """ try: curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) selected_module = 'Module Name : {}'.format(item_dict['values'][0]) available_version = 'Version : {}'.format(item_dict['values'][1]) module_summary = 'Summary : {}'.format(item_dict['values'][2]) home_page = 'Home Page : {}'.format(item_dict['values'][3]) last_updated = 'Last Updated : {}'.format(item_dict['values'][4]) selected_package_details = '{}\n{}\n{}\n{}\n{}'.format( selected_module, available_version, module_summary, home_page, last_updated, ) self.package_details.configure(state='normal') self.package_details.delete(1.0, 'end') self.package_details.insert(1.0, selected_package_details) self.package_details.configure(state='disabled') #search for module name in self.search_results new_options = [] for items in self.search_results: if items[0] == item_dict['values'][0]: self.module_details = items for x in items[5:]: new_options.append(x[0]) new_options = tuple(new_options) #Update compatibility options in option menu self.option_menu.config(state='normal') self.option_menu['menu'].delete(0, 'end') #update options menu for opt_tag in new_options: self.option_menu['menu'].add_command(label=opt_tag, command=tk._setit( self.options_var, opt_tag)) except Exception as e: print(e) self.package_details.configure(state='normal') self.package_details.delete(1.0, 'end') self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') def update_search_results(self): """ Show search results """ self.search_term = self.search_var.get() #Update the bottom message bar to inform user that the program #is fetching search results self.controller.debug_bar.config(text='Fetching search results ...') #Disable buttons like : self.navigate_back.config(state='disabled') self.navigate_next.config(state='disabled') self.search_button.config(state='disabled') #Spawn a new thread for searching packages, #Search results will be returned in the @param : self.search_queue self.search_queue = multiprocessing.Queue() from pip_tkinter.utils import pythonlibs_search_command self.search_thread = multiprocessing.Process( target=pythonlibs_search_command, kwargs={ 'package_name': self.search_term, 'thread_queue': self.search_queue }) self.search_thread.start() self.after(100, self.check_search_queue) def check_search_queue(self): try: results_tuple = self.search_queue.get(0) self.search_results = results_tuple try: self.multi_items_list.populate_rows(results_tuple) self.module_details = None self.controller.debug_bar.config(text='Fetched search results') except TypeError: self.controller.debug_bar.config( text='Unable to fetch results. Please verify your internet\ connection') self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') except queue.Empty: self.after(100, self.check_search_queue) def execute_pip_commands(self): """ Execute pip commands """ self.navigate_back.config(state='disabled') self.navigate_next.config(state='disabled') self.search_button.config(state='disabled') self.after( 100, self.controller.debug_bar.config( text='Installing package. Please wait ...')) self.after(100, self.update_installation_log) def update_installation_log(self): from pip_tkinter.utils import pip_install_from_pythonlibs try: curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) dists = item_dict['values'][5] self.controller.show_task_frame() self.install_queue = multiprocessing.Queue() selected_url = '' if self.module_details == None: return else: for x in self.module_details[5:]: if x[0] == self.options_var.get(): selected_url = x[3] self.update_thread = multiprocessing.Process( target=pip_install_from_pythonlibs, kwargs={ 'package_url': selected_url, 'install_queue': self.install_queue }) self.install_log_started = False self.error_log_started = False self.after(100, self.log_from_download_queue) #self.after(100, self.log_from_install_queue) self.update_thread.start() self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') except IndexError: self.controller.debug_bar.config(text='Select correct package') def log_from_download_queue(self): try: self.install_message = self.install_queue.get(0) if (self.install_message[0] == 0): self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0, 'end') self.controller.process_details.config(state='disabled') elif (self.install_message[0] == 1): self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0, 'end') self.controller.process_details.insert( 'end', 'Downloading {}\%\n'.format(self.install_message[1])) self.controller.process_details.config(state='disabled') elif (self.install_message[0] == 2): self.after(20, self.log_from_install_queue) return else: self.controller.process_details.config(state='normal') self.controller.process_details.insert('end', self.install_message[1]) self.controller.process_details.config(state='disabled') return self.after(20, self.log_from_download_queue) except queue.Empty: self.after(100, self.log_from_download_queue) def log_from_install_queue(self): try: self.install_message = self.install_queue.get(0) if ((self.install_message[1] == 'process_started') and (self.install_log_started == False)): self.install_log_started = True self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0, 'end') self.controller.process_details.config(state='disabled') elif (self.install_log_started == True): if self.install_message[0] == 3: if self.install_message[1] == 0: self.controller.debug_bar.config(text='Done') else: self.controller.debug_bar.config( text='Error in installing package') self.install_log_started = False self.controller.go_back_button.config(state='normal') self.controller.abort_install_button.config( state='disabled') return else: self.controller.process_details.config(state='normal') self.controller.process_details.insert( 'end', self.install_message[1]) self.controller.process_details.config(state='disabled') self.after(20, self.log_from_install_queue) except queue.Empty: self.after(100, self.log_from_install_queue) def abort_search_command(self): """ Stop searching for packages """ self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') self.search_thread.stop() def abort_installation(self): """ Stop pip installation : Currently not sure to provide option for aborting installation in between """ self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') self.update_thread.terminate()
class InstallFromPyPI(ttk.Frame): def __init__(self, parent, controller): ttk.Frame.__init__(self, parent, borderwidth=3, padding=0.5, relief='ridge') self.grid(row=0, column=0, sticky='nse', pady=(1, 1), padx=(1, 1)) self.controller = controller self.rowconfigure(1, weight=1) self.columnconfigure(0, weight=1) self.create_nav_buttons() self.create_search_bar() self.create_multitem_treeview() def create_search_bar(self): import pkg_resources, os #Configure style for search bar data = pkg_resources.resource_string(__name__, 'resources/pic.dat') global s1, s2 s1 = tk.PhotoImage('search1', data=data, format='gif -index 0') s2 = tk.PhotoImage('search2', data=data, format='gif -index 1') style = ttk.Style() style.element_create('Search.field1', 'image', 'search1', ('focus', 'search2'), border=[25, 9, 14], sticky='ew') style.layout('Search.entry', [('Search.field1', { 'sticky': 'nswe', 'border': 1, 'children': [('Entry.padding', { 'sticky': 'nswe', 'children': [('Entry.textarea', { 'sticky': 'nswe' })] })] })]) style.configure('Search.entry') #Create search bar and button self.search_var = tk.StringVar() self.entry = ttk.Entry(self, style='Search.entry', textvariable=self.search_var) self.entry.bind('<Return>', lambda event: self.update_search_results()) self.search_button = ttk.Button( self, text='Search', command=lambda: self.update_search_results()) self.entry.grid(row=0, column=0, padx=3, pady=3, sticky='nwe') self.search_button.grid(row=0, column=1, padx=1, pady=0, sticky='nw') def create_multitem_treeview(self): """ Create multitem treeview to show search results with headers : 1. Python Module 2. Installed version 3. Available versions List of buttons : 1. navigate_back 2. navigate_next 3. search_button """ self.headers = [ 'Python Module', 'Installed Version', 'Available Versions' ] from pip_tkinter.utils import MultiItemsList self.multi_items_list = MultiItemsList(self, self.headers) self.multi_items_list.scroll_tree.bind( '<<TreeviewSelect>>', lambda x: self.scroll_tree_select()) self.package_subwindow = tk.LabelFrame(self, text="Package Details", padx=5, pady=5) self.package_subwindow.grid(row=2, column=0, columnspan=2, sticky='nswe') self.package_details = tk.Text(self.package_subwindow, wrap='word', height=5) self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') self.package_details.pack(side='left', fill='x', expand='yes') yscrollbar = ttk.Scrollbar(self.package_subwindow, orient='vertical', command=self.package_details.yview) yscrollbar.pack(side='right', fill='y') self.package_details["yscrollcommand"] = yscrollbar.set self.multi_items_list.scroll_tree.bind("<Double-Button-1>", lambda x: self.show_summary()) def scroll_tree_select(self): """ If treeview is selected, enable update buttons """ self.navigate_next.config(state='normal') def show_summary(self): """ Show the details of the selected package """ try: curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) selected_module = 'Module Name : {}'.format(item_dict['values'][0]) installed_version = 'Installed : {}'.format(item_dict['values'][1]) latest_version = 'Latest : {}'.format(item_dict['values'][2]) module_summary = "Not available" for module in self.search_results: if module[0] == item_dict['values'][0]: module_summary = module[3] break module_summary = 'Summary : {}'.format(module_summary) selected_package_details = '{}\n{}\n{}\n{}'.format( selected_module, module_summary, installed_version, latest_version) self.package_details.configure(state='normal') self.package_details.delete(1.0, 'end') self.package_details.insert(1.0, selected_package_details) self.package_details.configure(state='disabled') except: self.package_details.configure(state='normal') self.package_details.delete(1.0, 'end') self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') def update_search_results(self): """ Show search results """ self.search_term = self.search_var.get() #Update the bottom message bar to inform user that the program #is fetching search results self.controller.debug_bar.config(text='Fetching search results ...') #Disable buttons like : self.navigate_back.config(state='disabled') self.navigate_next.config(state='disabled') self.search_button.config(state='disabled') #Spawn a new thread for searching packages, #Search results will be returned in the @param : self.thread_queue self.search_queue = queue.Queue() from pip_tkinter.utils import pip_search_command self.search_thread = threading.Thread(target=pip_search_command, kwargs={ 'package_name': self.search_term, 'thread_queue': self.search_queue }) self.search_thread.start() self.after(100, self.check_search_queue) def check_search_queue(self): try: results_tuple = self.search_queue.get(0) self.search_results = results_tuple try: self.multi_items_list.populate_rows(results_tuple) self.controller.debug_bar.config(text='Fetched search results') except TypeError: self.controller.debug_bar.config( text='Unable to fetch results. Please verify your internet\ connection') self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') except queue.Empty: self.after(100, self.check_search_queue) def create_nav_buttons(self): """ Create back and next buttons """ self.navigate_back = ttk.Button( self, text="Back", command=lambda: self.navigate_previous_frame()) self.navigate_back.grid(row=3, column=0, sticky='w') self.navigate_next = ttk.Button( self, text="Install", command=lambda: self.execute_pip_commands()) self.navigate_next.grid(row=3, column=1, sticky='e') def navigate_previous_frame(self): """ Navigate to previous frame """ self.controller.controller.show_frame('WelcomePage') def execute_pip_commands(self): """ Execute pip commands """ self.navigate_back.config(state='disabled') self.navigate_next.config(state='disabled') self.search_button.config(state='disabled') self.after( 100, self.controller.debug_bar.config( text='Installing package. Please wait ...')) self.after(100, self.update_installation_log) def update_installation_log(self): from pip_tkinter.utils import pip_install_from_PyPI try: curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) selected_module = item_dict['values'][0] self.controller.show_task_frame() self.install_queue = multiprocessing.Queue() self.update_thread = multiprocessing.Process( target=pip_install_from_PyPI, kwargs={ 'package_args': selected_module, 'install_queue': self.install_queue }) self.install_log_started = False self.error_log_started = False self.after(100, self.log_from_install_queue) self.update_thread.start() self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') except IndexError: self.controller.debug_bar.config(text='Select correct package') def log_from_install_queue(self): try: self.install_message = self.install_queue.get(0) if ((self.install_message[1] == 'process_started') and (self.install_log_started == False)): self.install_log_started = True self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0, 'end') self.controller.process_details.config(state='disabled') elif (self.install_log_started == True): if self.install_message[0] == 3: if self.install_message[1] == 0: self.controller.debug_bar.config(text='Done') else: self.controller.debug_bar.config( text='Error in installing package') self.install_log_started = False self.controller.go_back_button.config(state='normal') self.controller.abort_install_button.config( state='disabled') return else: self.controller.process_details.config(state='normal') self.controller.process_details.insert( 'end', self.install_message[1]) self.controller.process_details.config(state='disabled') self.after(20, self.log_from_install_queue) except queue.Empty: self.after(100, self.log_from_install_queue) def abort_search_command(self): """ Stop searching for packages """ self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') self.search_thread.stop() def abort_installation(self): """ Stop pip installation : Currently not sure to provide option for aborting installation in between """ self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') self.update_thread.terminate()
class FreezeRequirementsPage(ttk.Frame): """ Page for providing options for 'pip freeze'. User can generate requirement file and save it to desired location """ def __init__(self, parent, controller): ttk.Frame.__init__( self, parent, borderwidth=3, padding=0.5, relief='ridge') self.grid(row=0, column=0, sticky='nse', pady=(1,1), padx=(1,1)) self.controller = controller self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.create_multitem_treeview() self.create_buttons() def create_multitem_treeview(self): """ Create multitem treeview to show search results with headers : 1. Python Module 2. Installed version """ self.headers = ['Python Module','Installed Version'] from pip_tkinter.utils import MultiItemsList self.multi_items_list = MultiItemsList(self, self.headers) self.multi_items_list.myframe.grid( row=0, column=0, columnspan=4, sticky='nswe') self.multi_items_list.scroll_tree.bind( '<<TreeviewSelect>>', lambda x : self.scroll_tree_select()) self.multi_items_list.scroll_tree.config(selectmode='extended') def scroll_tree_select(self): """ Update debug bar with number of packages selected """ self.controller.debug_bar.config( text="No. of packages selected {}".format( str(len(self.multi_items_list.scroll_tree.selection())))) def refresh_installed_packages(self): """ Show search results """ from pip_tkinter.utils import pip_list_command self.installed_packages_list = pip_list_command() results_tuple = self.installed_packages_list self.multi_items_list.populate_rows(results_tuple) self.controller.debug_bar.config(text='Found installed packages') def create_buttons(self): """ Create nav and control buttons """ self.navigate_back = ttk.Button( self, text="Back", command=lambda: self.navigate_previous_frame()) self.navigate_back.grid(row=3, column=0, sticky='w', padx=1, pady=1) self.refresh_button = ttk.Button( self, text="Refresh", command=lambda: self.refresh_installed_packages()) self.refresh_button.grid(row=3, column=1, sticky='e', padx=1, pady=1) self.navigate_next = ttk.Button( self, text="Generate Requirements", command=lambda: self.execute_pip_commands()) self.navigate_next.grid(row=3, column=2, sticky='e', padx=1, pady=1) def navigate_previous_frame(self): """ Navigate to previous frame """ self.controller.controller.show_frame('WelcomePage') def refresh_installed_packages(self): """ Update list of installed packages """ from pip_tkinter.utils import pip_freeze_command self.installed_packages_list = pip_freeze_command() results_tuple = self.installed_packages_list self.multi_items_list.populate_rows(results_tuple) self.controller.debug_bar.config(text='Found installed packages') def execute_pip_commands(self): """ Execute the command for generating requirements file """ requirements_text = '' for item in self.multi_items_list.scroll_tree.selection(): item_dict = self.multi_items_list.scroll_tree.item(item) requirements_text += '{}=={}\n'.format( item_dict['values'][0], item_dict['values'][1]) from tkinter.filedialog import asksaveasfile from os.path import expanduser file_pt = asksaveasfile( mode='w', defaultextension='.txt', initialdir=expanduser('~')) if file_pt is None: return file_pt.write(requirements_text) file_pt.close()
class UninstallPackage(ttk.Frame): def __init__(self, parent, controller): ttk.Frame.__init__( self, parent, borderwidth=3, padding=0.5, relief='ridge') self.grid(row=0, column=0, sticky='nse', pady=(1,1), padx=(1,1)) self.controller = controller self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.create_multitem_treeview() self.create_buttons() def create_multitem_treeview(self): """ Create multitem treeview to show search results with headers : 1. Python Module 2. Installed version 3. Available versions """ self.headers = ['Python Module','Installed Version'] from pip_tkinter.utils import MultiItemsList self.multi_items_list = MultiItemsList(self, self.headers) self.multi_items_list.myframe.grid( row=0, column=0, columnspan=3, sticky='nswe') self.multi_items_list.scroll_tree.bind( '<<TreeviewSelect>>', lambda x : self.scroll_tree_select()) #self.refresh_installed_packages() self.package_subwindow = tk.LabelFrame( self, text="Package Details", padx=5, pady=5) self.package_subwindow.grid( row=1, column=0, columnspan=3, sticky='nswe') self.package_details = tk.Text( self.package_subwindow, wrap='word', height=5) self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') self.package_details.pack(side='left', fill='x', expand='yes') yscrollbar=ttk.Scrollbar( self.package_subwindow, orient='vertical', command=self.package_details.yview) yscrollbar.pack(side='right', fill='y') self.package_details["yscrollcommand"]=yscrollbar.set self.multi_items_list.scroll_tree.bind( "<Double-Button-1>", lambda x: self.show_summary()) def scroll_tree_select(self): """ If treeview is selected, enable update buttons """ self.navigate_next.config(state='normal') def show_summary(self): """ Show the details of the selected package """ curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) selected_module = 'Module Name : {}'.format(item_dict['values'][0]) from pip_tkinter.utils import pip_show_command status_code, selected_package_details, serror = pip_show_command( selected_module) self.package_details.configure(state='normal') self.package_details.delete(1.0, 'end') self.package_details.insert(1.0, selected_package_details) self.package_details.configure(state='disabled') def refresh_installed_packages(self): """ Show search results """ from pip_tkinter.utils import pip_list_command self.installed_packages_list = pip_list_command() results_tuple = self.installed_packages_list self.multi_items_list.populate_rows(results_tuple) self.controller.debug_bar.config(text='Found installed packages') def create_buttons(self): """ Create back and next buttons """ self.navigate_back = ttk.Button( self, text="Back", command=lambda: self.navigate_previous_frame()) self.navigate_back.grid(row=3, column=0, sticky='w') self.refresh_button = ttk.Button( self, text="Refresh", command=lambda: self.refresh_installed_packages()) self.refresh_button.grid(row=3, column=1, sticky='e') self.navigate_next = ttk.Button( self, text="Uninstall", command=lambda: self.execute_pip_commands()) self.navigate_next.grid(row=3, column=2, sticky='e') def navigate_previous_frame(self): """ Navigate to previous frame """ self.controller.controller.show_frame('WelcomePage') def execute_pip_commands(self): """ Execute pip commands """ self.navigate_back.config(state='disabled') self.navigate_next.config(state='disabled') self.refresh_button.config(state='disabled') self.after(100, self.controller.debug_bar.config( text='Uninstalling package. Please wait ...')) self.after(100, self.update_uninstallation_log) def update_uninstallation_log(self): from pip_tkinter.utils import pip_uninstall try: curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) selected_module = item_dict['values'][0] self.controller.show_task_frame() self.uninstall_queue = multiprocessing.Queue() self.update_thread = multiprocessing.Process( target=pip_uninstall, kwargs={ 'package_args':selected_module, 'uninstall_queue':self.uninstall_queue}) self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0,'end') self.controller.process_details.config(state='disabled') self.uninstall_log_started = False self.error_log_started = False self.after(100, self.log_from_uninstall_queue) self.update_thread.start() self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.refresh_button.config(state='normal') except IndexError: self.controller.debug_bar.config(text='Select correct package') def log_from_uninstall_queue(self): try: self.uninstall_message = self.uninstall_queue.get(0) if ((self.uninstall_message[1]=='process_started') and (self.uninstall_log_started==False)): self.uninstall_log_started = True self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0,'end') self.controller.process_details.config(state='disabled') elif (self.uninstall_log_started==True): if self.uninstall_message[0]==3: if self.uninstall_message[1]==0: self.controller.debug_bar.config(text='Done') else: self.controller.debug_bar.config( text='Error in uninstalling package') self.uninstall_log_started = False self.controller.go_back_button.config(state='normal') self.controller.abort_process_button.config(state='disabled') return else: self.controller.process_details.config(state='normal') self.controller.process_details.insert( 'end', self.uninstall_message[1]) self.controller.process_details.config(state='disabled') self.after(20, self.log_from_uninstall_queue) except queue.Empty: self.after(100, self.log_from_uninstall_queue) def abort_process(self): """ Stop pip process : Currently not sure to provide option for aborting process in between """ self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.refresh_button.config(state='normal') self.update_thread.terminate()
class InstallFromPythonlibs(ttk.Frame): def __init__(self, parent, controller): ttk.Frame.__init__( self, parent, borderwidth=3, padding=0.5, relief='ridge') self.grid(row=0, column=0, sticky='nse', pady=(1,1), padx=(1,1)) self.controller = controller self.rowconfigure(1, weight=1) self.columnconfigure(0, weight=1) self.create_buttons() self.create_multitem_treeview() self.create_search_bar() def create_buttons(self): """ Create back and next buttons, Also creates option menu for selecting compatibility tag """ self.navigate_back = ttk.Button( self, text='Back', command=lambda: self.navigate_previous_frame()) self.navigate_back.grid(row=3, column=0, sticky='w') options = ('Select compatible dist.',) self.options_var = tk.StringVar(self) self.options_var.set(options[0]) self.option_menu = tk.OptionMenu(self, self.options_var, *options) self.option_menu.grid(row=3, column=1, sticky='e') self.option_menu.config(state='disabled') self.sync_button = ttk.Button( self, text='Sync', command=lambda: self.sync_pythonlibs_packages()) self.sync_button.grid(row=3, column=2, sticky='e') self.navigate_next = ttk.Button( self, text='Install', command=lambda: self.execute_pip_commands()) self.navigate_next.grid(row=3, column=3, sticky='e') def navigate_previous_frame(self): """ Navigate to previous frame """ self.controller.controller.show_frame('WelcomePage') def sync_pythonlibs_packages(self): """ Sync the json file for PythonLibs at : https://raw.githubusercontent.com/upendra-k14/pythonlibs_modules/master/pythonlibs.json """ from pip_tkinter.utils import create_resource_directory resource_dir = create_resource_directory() url = "https://raw.githubusercontent.com/upendra-k14/pythonlibs_modules/master/pythonlibs.json" self.update_queue = multiprocessing.Queue() self.after(10, self.update_sync_messages) self.sync_button.config(state='disabled') from pip_tkinter.utils import downloadfile downloadfile(url, self.update_queue) def update_sync_messages(self): try: message = self.update_queue.get(0) if (message[0]==3): self.controller.debug_bar.config(text=message[1]) self.sync_button.config(state='normal') return elif (message[0]==1 or message[0]==0): self.controller.debug_bar.config(text='Syncing : {}'.format(str(message[1]))) self.after(10, self.update_sync_messages) elif (message[0]==2): self.controller.debug_bar.config(text=message[1]) self.sync_button.config(state='normal') return except queue.Empty: self.after(10, self.update_sync_messages) def create_search_bar(self): style = ttk.Style() style.configure('Search.entry') #Create search bar and button self.search_var = tk.StringVar() self.entry = ttk.Entry( self, style='Search.entry', textvariable=self.search_var) self.entry.bind('<Return>', lambda event : self.update_search_results()) self.search_button = ttk.Button( self, text='Search', command=lambda : self.update_search_results()) self.entry.grid( row=0, column=0, columnspan=3, padx=3, pady=3, sticky='nwe') self.search_button.grid( row=0, column=3, padx=1, pady = 0, sticky='nw') def create_multitem_treeview(self): """ Create multitem treeview to show search results with headers : 1. Python Module 2. Installed Version 3. Available Version List of buttons : 1. navigate_back 2. navigate_next 3. search_button """ self.headers = ['Python Module', 'Available Version'] from pip_tkinter.utils import MultiItemsList self.multi_items_list = MultiItemsList(self, self.headers) self.multi_items_list.scroll_tree.bind( '<<TreeviewSelect>>', lambda x : self.scroll_tree_select()) self.multi_items_list.myframe.grid( row=1, column=0, columnspan=4, sticky='nsew') self.package_subwindow = tk.LabelFrame( self, text="Package Details", padx=5, pady=5) self.package_subwindow.grid( row=2, column=0, columnspan=4, sticky='nswe') self.package_details = tk.Text( self.package_subwindow, wrap='word', height=5) self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') self.package_details.pack(side='left', fill='x', expand='yes') yscrollbar=ttk.Scrollbar( self.package_subwindow, orient='vertical', command=self.package_details.yview) yscrollbar.pack(side='right', fill='y') self.package_details["yscrollcommand"]=yscrollbar.set self.multi_items_list.scroll_tree.bind( "<Double-Button-1>", lambda x: self.show_summary()) def scroll_tree_select(self): """ If treeview is selected, enable update buttons """ self.navigate_next.config(state='normal') def show_summary(self): """ Show the details of the selected package """ try: curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) selected_module = 'Module Name : {}'.format(item_dict['values'][0]) available_version = 'Version : {}'.format(item_dict['values'][1]) module_summary = 'Summary : {}'.format(item_dict['values'][2]) home_page = 'Home Page : {}'.format(item_dict['values'][3]) last_updated = 'Last Updated : {}'.format(item_dict['values'][4]) selected_package_details = '{}\n{}\n{}\n{}\n{}'.format( selected_module, available_version, module_summary, home_page, last_updated,) self.package_details.configure(state='normal') self.package_details.delete(1.0, 'end') self.package_details.insert(1.0, selected_package_details) self.package_details.configure(state='disabled') #search for module name in self.search_results new_options = [] for items in self.search_results: if items[0]==item_dict['values'][0]: self.module_details = items for x in items[5:]: new_options.append(x[0]) new_options = tuple(new_options) #Update compatibility options in option menu self.option_menu.config(state='normal') self.option_menu['menu'].delete(0,'end') #update options menu for opt_tag in new_options: self.option_menu['menu'].add_command( label=opt_tag, command=tk._setit(self.options_var, opt_tag)) except Exception as e: print (e) self.package_details.configure(state='normal') self.package_details.delete(1.0, 'end') self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') def update_search_results(self): """ Show search results """ self.search_term = self.search_var.get() #Update the bottom message bar to inform user that the program #is fetching search results self.controller.debug_bar.config(text='Fetching search results ...') #Disable buttons like : self.navigate_back.config(state='disabled') self.navigate_next.config(state='disabled') self.search_button.config(state='disabled') #Spawn a new thread for searching packages, #Search results will be returned in the @param : self.search_queue self.search_queue = multiprocessing.Queue() from pip_tkinter.utils import pythonlibs_search_command self.search_thread = multiprocessing.Process( target=pythonlibs_search_command, kwargs={ 'package_name':self.search_term, 'thread_queue':self.search_queue}) self.search_thread.start() self.after(100, self.check_search_queue) def check_search_queue(self): try: results_tuple = self.search_queue.get(0) self.search_results = results_tuple try: self.multi_items_list.populate_rows(results_tuple) self.module_details = None self.controller.debug_bar.config(text='Fetched search results') except TypeError: self.controller.debug_bar.config( text='Unable to fetch results. Please verify your internet\ connection') self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') except queue.Empty: self.after(100, self.check_search_queue) def execute_pip_commands(self): """ Execute pip commands """ self.navigate_back.config(state='disabled') self.navigate_next.config(state='disabled') self.search_button.config(state='disabled') self.after(100, self.controller.debug_bar.config( text='Installing package. Please wait ...')) self.after(100, self.update_installation_log) def update_installation_log(self): from pip_tkinter.utils import pip_install_from_pythonlibs try: curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) dists = item_dict['values'][5] self.controller.show_task_frame() self.install_queue = multiprocessing.Queue() selected_url = '' if self.module_details==None: return else: for x in self.module_details[5:]: if x[0]==self.options_var.get(): selected_url = x[3] self.update_thread = multiprocessing.Process( target=pip_install_from_pythonlibs, kwargs={ 'package_url':selected_url, 'install_queue':self.install_queue}) self.install_log_started = False self.error_log_started = False self.after(100, self.log_from_download_queue) #self.after(100, self.log_from_install_queue) self.update_thread.start() self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') except IndexError: self.controller.debug_bar.config(text='Select correct package') def log_from_download_queue(self): try: self.install_message = self.install_queue.get(0) if (self.install_message[0]==0): self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0,'end') self.controller.process_details.config(state='disabled') elif (self.install_message[0]==1): self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0,'end') self.controller.process_details.insert( 'end', 'Downloading {}\%\n'.format(self.install_message[1])) self.controller.process_details.config(state='disabled') elif (self.install_message[0]==2): self.after(20, self.log_from_install_queue) return else: self.controller.process_details.config(state='normal') self.controller.process_details.insert( 'end', self.install_message[1]) self.controller.process_details.config(state='disabled') return self.after(20, self.log_from_download_queue) except queue.Empty: self.after(100, self.log_from_download_queue) def log_from_install_queue(self): try: self.install_message = self.install_queue.get(0) if ((self.install_message[1]=='process_started') and (self.install_log_started==False)): self.install_log_started = True self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0,'end') self.controller.process_details.config(state='disabled') elif (self.install_log_started==True): if self.install_message[0]==3: if self.install_message[1]==0: self.controller.debug_bar.config(text='Done') else: self.controller.debug_bar.config( text='Error in installing package') self.install_log_started = False self.controller.go_back_button.config(state='normal') self.controller.abort_install_button.config(state='disabled') return else: self.controller.process_details.config(state='normal') self.controller.process_details.insert( 'end', self.install_message[1]) self.controller.process_details.config(state='disabled') self.after(20, self.log_from_install_queue) except queue.Empty: self.after(100, self.log_from_install_queue) def abort_search_command(self): """ Stop searching for packages """ self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') self.search_thread.stop() def abort_installation(self): """ Stop pip installation : Currently not sure to provide option for aborting installation in between """ self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') self.update_thread.terminate()
class InstallFromPyPI(ttk.Frame): def __init__(self, parent, controller): ttk.Frame.__init__( self, parent, borderwidth=3, padding=0.5, relief='ridge') self.grid(row=0, column=0, sticky='nse', pady=(1,1), padx=(1,1)) self.controller = controller self.rowconfigure(1, weight=1) self.columnconfigure(0, weight=1) self.create_nav_buttons() self.create_search_bar() self.create_multitem_treeview() def create_search_bar(self): import pkg_resources, os #Configure style for search bar data= pkg_resources.resource_string(__name__, 'resources/pic.dat') global s1,s2 s1 = tk.PhotoImage('search1', data=data, format='gif -index 0') s2 = tk.PhotoImage('search2', data=data, format='gif -index 1') style = ttk.Style() style.element_create('Search.field1', 'image', 'search1', ('focus', 'search2'), border=[25, 9, 14], sticky='ew') style.layout('Search.entry', [ ('Search.field1', {'sticky': 'nswe', 'border': 1, 'children': [('Entry.padding', {'sticky': 'nswe', 'children': [('Entry.textarea', {'sticky': 'nswe'})] })] })] ) style.configure('Search.entry') #Create search bar and button self.search_var = tk.StringVar() self.entry = ttk.Entry( self, style='Search.entry', textvariable=self.search_var) self.entry.bind('<Return>', lambda event : self.update_search_results()) self.search_button = ttk.Button( self, text='Search', command=lambda : self.update_search_results()) self.entry.grid(row=0, column=0, padx=3, pady=3, sticky='nwe') self.search_button.grid(row=0, column=1, padx=1, pady = 0, sticky='nw') def create_multitem_treeview(self): """ Create multitem treeview to show search results with headers : 1. Python Module 2. Installed version 3. Available versions List of buttons : 1. navigate_back 2. navigate_next 3. search_button """ self.headers = ['Python Module','Installed Version','Available Versions'] from pip_tkinter.utils import MultiItemsList self.multi_items_list = MultiItemsList(self, self.headers) self.multi_items_list.scroll_tree.bind( '<<TreeviewSelect>>', lambda x : self.scroll_tree_select()) self.package_subwindow = tk.LabelFrame( self, text="Package Details", padx=5, pady=5) self.package_subwindow.grid(row=2, column=0, columnspan=2, sticky='nswe') self.package_details = tk.Text( self.package_subwindow, wrap='word', height=5) self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') self.package_details.pack(side='left', fill='x', expand='yes') yscrollbar=ttk.Scrollbar( self.package_subwindow, orient='vertical', command=self.package_details.yview) yscrollbar.pack(side='right', fill='y') self.package_details["yscrollcommand"]=yscrollbar.set self.multi_items_list.scroll_tree.bind( "<Double-Button-1>", lambda x: self.show_summary()) def scroll_tree_select(self): """ If treeview is selected, enable update buttons """ self.navigate_next.config(state='normal') def show_summary(self): """ Show the details of the selected package """ try: curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) selected_module = 'Module Name : {}'.format(item_dict['values'][0]) installed_version = 'Installed : {}'.format(item_dict['values'][1]) latest_version = 'Latest : {}'.format(item_dict['values'][2]) module_summary = "Not available" for module in self.search_results: if module[0] == item_dict['values'][0]: module_summary = module[3] break module_summary = 'Summary : {}'.format(module_summary) selected_package_details = '{}\n{}\n{}\n{}'.format( selected_module, module_summary, installed_version, latest_version) self.package_details.configure(state='normal') self.package_details.delete(1.0, 'end') self.package_details.insert(1.0, selected_package_details) self.package_details.configure(state='disabled') except: self.package_details.configure(state='normal') self.package_details.delete(1.0, 'end') self.package_details.insert(1.0, 'No module selected') self.package_details.configure(state='disabled') def update_search_results(self): """ Show search results """ self.search_term = self.search_var.get() #Update the bottom message bar to inform user that the program #is fetching search results self.controller.debug_bar.config(text='Fetching search results ...') #Disable buttons like : self.navigate_back.config(state='disabled') self.navigate_next.config(state='disabled') self.search_button.config(state='disabled') #Spawn a new thread for searching packages, #Search results will be returned in the @param : self.thread_queue self.search_queue = queue.Queue() from pip_tkinter.utils import pip_search_command self.search_thread = threading.Thread( target=pip_search_command, kwargs={ 'package_name':self.search_term, 'thread_queue':self.search_queue}) self.search_thread.start() self.after(100, self.check_search_queue) def check_search_queue(self): try: results_tuple = self.search_queue.get(0) self.search_results = results_tuple try: self.multi_items_list.populate_rows(results_tuple) self.controller.debug_bar.config(text='Fetched search results') except TypeError: self.controller.debug_bar.config( text='Unable to fetch results. Please verify your internet\ connection') self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') except queue.Empty: self.after(100, self.check_search_queue) def create_nav_buttons(self): """ Create back and next buttons """ self.navigate_back = ttk.Button( self, text="Back", command=lambda: self.navigate_previous_frame()) self.navigate_back.grid(row=3, column=0, sticky='w') self.navigate_next = ttk.Button( self, text="Install", command=lambda: self.execute_pip_commands()) self.navigate_next.grid(row=3, column=1, sticky='e') def navigate_previous_frame(self): """ Navigate to previous frame """ self.controller.controller.show_frame('WelcomePage') def execute_pip_commands(self): """ Execute pip commands """ self.navigate_back.config(state='disabled') self.navigate_next.config(state='disabled') self.search_button.config(state='disabled') self.after(100, self.controller.debug_bar.config( text='Installing package. Please wait ...')) self.after(100, self.update_installation_log) def update_installation_log(self): from pip_tkinter.utils import pip_install_from_PyPI try: curr_item = self.multi_items_list.scroll_tree.focus() item_dict = self.multi_items_list.scroll_tree.item(curr_item) selected_module = item_dict['values'][0] self.controller.show_task_frame() self.install_queue = multiprocessing.Queue() self.update_thread = multiprocessing.Process( target=pip_install_from_PyPI, kwargs={ 'package_args':selected_module, 'install_queue':self.install_queue}) self.install_log_started = False self.error_log_started = False self.after(100, self.log_from_install_queue) self.update_thread.start() self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') except IndexError: self.controller.debug_bar.config(text='Select correct package') def log_from_install_queue(self): try: self.install_message = self.install_queue.get(0) if ((self.install_message[1]=='process_started') and (self.install_log_started==False)): self.install_log_started = True self.controller.process_details.config(state='normal') self.controller.process_details.delete(1.0,'end') self.controller.process_details.config(state='disabled') elif (self.install_log_started==True): if self.install_message[0]==3: if self.install_message[1]==0: self.controller.debug_bar.config(text='Done') else: self.controller.debug_bar.config( text='Error in installing package') self.install_log_started = False self.controller.go_back_button.config(state='normal') self.controller.abort_install_button.config(state='disabled') return else: self.controller.process_details.config(state='normal') self.controller.process_details.insert( 'end', self.install_message[1]) self.controller.process_details.config(state='disabled') self.after(20, self.log_from_install_queue) except queue.Empty: self.after(100, self.log_from_install_queue) def abort_search_command(self): """ Stop searching for packages """ self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') self.search_thread.stop() def abort_installation(self): """ Stop pip installation : Currently not sure to provide option for aborting installation in between """ self.navigate_back.config(state='normal') self.navigate_next.config(state='normal') self.search_button.config(state='normal') self.update_thread.terminate()