Exemplo n.º 1
0
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
Exemplo n.º 2
0
    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())
Exemplo n.º 4
0
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')
Exemplo n.º 6
0
    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())
Exemplo n.º 7
0
    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()
Exemplo n.º 8
0
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()
Exemplo n.º 9
0
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()
Exemplo n.º 10
0
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()
Exemplo n.º 11
0
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()
Exemplo n.º 12
0
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()
Exemplo n.º 13
0
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()