Skip to main content
added code in post
Source Link

One more note, this app was designed only to function on Windows.

Since it's a bit long, the The full code can be viewed here. Thanks!

def path_shorten(path):
    path = path.split('/')
    if len(path) <= 4:
        return os.sep.join(path)
    else:
        return os.sep.join(path[:2]+['...']+path[-2:])

def open_file(selection,file_path_list):
    os.startfile(file_path_list[selection-1])

def msgbox(msg, dryrun_list=0, file_name_len=0, file_path_len = 0):
    mb = Tk()
    if isinstance(dryrun_list, list):
        mb.wm_title("Notice")
        label = ttk.Label(mb, text=msg, font=NORM_FONT)
        label.pack(side=TOP, fill=BOTH)
        scrollbar = Scrollbar(mb)
        scrollbar.pack(side=RIGHT, fill=Y)
        listbox = Listbox(mb, yscrollcommand=scrollbar.set, height=30, width=120, font='TkFixedFont')
        listbox.insert(END, 'File name'.ljust(file_path_len + 2) + 'Date Created') # plus 2 for column spacing
        listbox.itemconfig(0, {'bg': 'lightblue'})
        file_path_list = []
        for i in dryrun_list:
            manip_path = path_shorten(str(i[2]))
            justify = file_path_len

            listbox.insert(END, manip_path.ljust(justify+2) + str(i[1]) )
            file_path_list.append(i[2])
        listbox.pack(side=TOP, fill=BOTH)
        scrollbar.config(command=listbox.yview)
        listbox.bind('<Double-1>', lambda x: open_file(listbox.curselection()[0],file_path_list))

    else:
        mb.wm_title("Warning!")
        label = ttk.Label(mb, text=msg, font=NORM_FONT)
        label.pack(side=TOP, fill=BOTH)

    button = ttk.Button(mb, text="Okay", command=mb.destroy)
    button.pack(side=BOTTOM, fill=BOTH)
    mb.mainloop()


def walk_dir(main_obj, path, daydif, filetype):
    current_time = datetime.datetime.now().strftime("%m_%d_%y")
    dryrun_list = []
    file_name_len = 0
    file_path_len = 0
    if os.path.isdir(path) and os.path.exists(path):
        file_cnt = 0
        # this is for counting for prog bar increment
        for dirpath, dirnames, filenames in os.walk(path):
            for file in filenames:
                full_file_path = os.path.join(dirpath, file).replace("\\","/")
                seconds_dif = calendar.timegm(time.gmtime()) - os.path.getmtime(full_file_path)
                days, seconds = divmod(seconds_dif, 24 * 60 * 60)
                if int(days) >= daydif:
                    if file.endswith("." + filetype):
                        file_cnt += 1
        if file_cnt == 0:
            msgbox('No files found meeting the selected conditions. There may be empty directories but they cannot be deleted indepedent of deleting files')
            return False

        with open(path + '/Files removed ' + current_time + '.csv', 'w', newline='') as output:
            csv_output = csv.writer(output, delimiter=',')
            csv_output.writerows([['File Name', 'Removed From']])
            # this is for deleting
            for dirpath, dirnames, filenames in os.walk(path):
                for file in filenames:

                    full_file_path = os.path.join(dirpath, file).replace("\\","/")
                    time_created = time.ctime(os.path.getmtime(full_file_path))

                    seconds_dif = calendar.timegm(time.gmtime()) - os.path.getmtime(full_file_path)
                    days, seconds = divmod(seconds_dif, 24 * 60 * 60)

                    if int(days) >= daydif:
                        if file.endswith("." + filetype):
                            main_obj.progbar.step((1 / file_cnt) * 100)
                            main_obj.progbar.update()

                            if main_obj.checkvar.get() == '0':
                                #dry run not selected
                                os.remove(os.path.join(dirpath, file))
                                csv_output.writerows([[file,dirpath]])
                            else:
                                #dry run selected')
                                if len(file) > file_name_len:
                                    file_name_len = len(file)
                                if len(path_shorten(full_file_path)) > file_path_len:
                                    file_path_len = len(path_shorten(full_file_path))
                                dryrun_list.append([file, time_created, full_file_path])



            if dryrun_list != []:
                msgbox('If you run with the current settings these are the files you will delete.', dryrun_list,
                       file_name_len,file_path_len)
                dryrun_list = []
                return

            if main_obj.empdir_var.get() == '0':  # rmdir checkbox
                print('remove dir not selected')
                msgbox('Processing complete!')
                return
            else:
                for dirpath, n, f in os.walk(path, topdown=False):
                    try:
                        os.rmdir(dirpath)
                    except OSError as ex:
                        print("Directory not empty.")
                msgbox('Processing complete!')
                return
            return # close csv????
    elif path == 'Click Browse to add folder':
        msgbox('Select a directory to run the script on.')
    else:
        msgbox("'" + path + "'" + ' does not exist or is not a valid path')
    file_cnt = 0



class MainFrame:
    def __init__(self, master):
        master.title('Dated File Removal Tool')
        # TOP FRAME
        self.topframe = ttk.Frame()
        self.topframe.grid(row=0, column=0, padx=10, pady=2, sticky='W')
        # browse button
        self.browseButton = Button(self.topframe, text="Browse", command=self.load_dir, width=15).grid(row=0, column=0)
        # okbutton test
        button = Button(self.topframe, text="Execute", command=self.ok_click, width=15)
        button.grid(row=0, column=1, sticky='E')

        # MIDDLE FRAME
        self.middleFrame = ttk.Frame()
        self.middleFrame.grid(row=1, column=0, sticky='W', padx=10, pady=5)
        # path display box
        self.dir_path = StringVar()
        browse_entry = Entry(self.middleFrame, width=65, textvariable=self.dir_path, state=DISABLED)
        browse_entry.grid(row=0, column=0)
        self.dir_path.set("Click Browse to add folder")


        # label frame
        self.options_lf = ttk.Labelframe(self.middleFrame, text='Options')
        # days combobox
        days = ('00 days', '30 Days', '60 Days', '90 Days')
        self.days_cmb = ttk.Combobox(self.options_lf, values=days, state='readonly')
        self.days_cmb.current(0)  # set selection
        self.days_cmb.grid(row=0, column=0, padx=25)
        # file types combobox
        filetypes = ('jpg', 'mp3', 'avi')
        self.file_cmb = ttk.Combobox(self.options_lf, values=filetypes, state='readonly')
        self.file_cmb.current(0)  # set selection
        self.file_cmb.grid(row=0, column=1, padx=25, pady=2)
        # test run checkbox
        self.checkvar = StringVar()
        dryrun_cb = Checkbutton(self.options_lf, text="Test Run", variable=self.checkvar)
        dryrun_cb.grid(row=1, column=0, sticky='W', padx=25)
        self.checkvar.set(1)
        # Remove dirs checkbox
        self.empdir_var = StringVar()
        empdir_cb = Checkbutton(self.options_lf, text="Remove Empty Dirs", variable=self.empdir_var)
        empdir_cb.grid(row=1, column=1, sticky='W', padx=25)
        self.empdir_var.set(0)
        # place in frame
        self.options_lf.grid(row=1, column=0, sticky='W')

        # BOTTOM FRAME
        self.bottomframe = ttk.Frame()
        self.bottomframe.grid(row=3, column=0)
        # prog bar
        self.progbar = ttk.Progressbar(self.bottomframe, orient='horizontal', mode='determinate', length=420)
        self.progbar.grid(row=1, column=0)

    def load_dir(self):
        dirname = askdirectory()
        if not dirname:
            pass  # file upload cancelled
        self.dir_path.set(dirname)

    def ok_click(self):
        daydif = int(self.days_cmb.get()[:2])
        walk_dir(self, self.dir_path.get(), daydif, self.file_cmb.get())

One more note, this app was designed only to function on Windows.

Since it's a bit long, the code can be viewed here. Thanks!

One more note, this app was designed only to function on Windows. The full code can be viewed here. Thanks!

def path_shorten(path):
    path = path.split('/')
    if len(path) <= 4:
        return os.sep.join(path)
    else:
        return os.sep.join(path[:2]+['...']+path[-2:])

def open_file(selection,file_path_list):
    os.startfile(file_path_list[selection-1])

def msgbox(msg, dryrun_list=0, file_name_len=0, file_path_len = 0):
    mb = Tk()
    if isinstance(dryrun_list, list):
        mb.wm_title("Notice")
        label = ttk.Label(mb, text=msg, font=NORM_FONT)
        label.pack(side=TOP, fill=BOTH)
        scrollbar = Scrollbar(mb)
        scrollbar.pack(side=RIGHT, fill=Y)
        listbox = Listbox(mb, yscrollcommand=scrollbar.set, height=30, width=120, font='TkFixedFont')
        listbox.insert(END, 'File name'.ljust(file_path_len + 2) + 'Date Created') # plus 2 for column spacing
        listbox.itemconfig(0, {'bg': 'lightblue'})
        file_path_list = []
        for i in dryrun_list:
            manip_path = path_shorten(str(i[2]))
            justify = file_path_len

            listbox.insert(END, manip_path.ljust(justify+2) + str(i[1]) )
            file_path_list.append(i[2])
        listbox.pack(side=TOP, fill=BOTH)
        scrollbar.config(command=listbox.yview)
        listbox.bind('<Double-1>', lambda x: open_file(listbox.curselection()[0],file_path_list))

    else:
        mb.wm_title("Warning!")
        label = ttk.Label(mb, text=msg, font=NORM_FONT)
        label.pack(side=TOP, fill=BOTH)

    button = ttk.Button(mb, text="Okay", command=mb.destroy)
    button.pack(side=BOTTOM, fill=BOTH)
    mb.mainloop()


def walk_dir(main_obj, path, daydif, filetype):
    current_time = datetime.datetime.now().strftime("%m_%d_%y")
    dryrun_list = []
    file_name_len = 0
    file_path_len = 0
    if os.path.isdir(path) and os.path.exists(path):
        file_cnt = 0
        # this is for counting for prog bar increment
        for dirpath, dirnames, filenames in os.walk(path):
            for file in filenames:
                full_file_path = os.path.join(dirpath, file).replace("\\","/")
                seconds_dif = calendar.timegm(time.gmtime()) - os.path.getmtime(full_file_path)
                days, seconds = divmod(seconds_dif, 24 * 60 * 60)
                if int(days) >= daydif:
                    if file.endswith("." + filetype):
                        file_cnt += 1
        if file_cnt == 0:
            msgbox('No files found meeting the selected conditions. There may be empty directories but they cannot be deleted indepedent of deleting files')
            return False

        with open(path + '/Files removed ' + current_time + '.csv', 'w', newline='') as output:
            csv_output = csv.writer(output, delimiter=',')
            csv_output.writerows([['File Name', 'Removed From']])
            # this is for deleting
            for dirpath, dirnames, filenames in os.walk(path):
                for file in filenames:

                    full_file_path = os.path.join(dirpath, file).replace("\\","/")
                    time_created = time.ctime(os.path.getmtime(full_file_path))

                    seconds_dif = calendar.timegm(time.gmtime()) - os.path.getmtime(full_file_path)
                    days, seconds = divmod(seconds_dif, 24 * 60 * 60)

                    if int(days) >= daydif:
                        if file.endswith("." + filetype):
                            main_obj.progbar.step((1 / file_cnt) * 100)
                            main_obj.progbar.update()

                            if main_obj.checkvar.get() == '0':
                                #dry run not selected
                                os.remove(os.path.join(dirpath, file))
                                csv_output.writerows([[file,dirpath]])
                            else:
                                #dry run selected')
                                if len(file) > file_name_len:
                                    file_name_len = len(file)
                                if len(path_shorten(full_file_path)) > file_path_len:
                                    file_path_len = len(path_shorten(full_file_path))
                                dryrun_list.append([file, time_created, full_file_path])



            if dryrun_list != []:
                msgbox('If you run with the current settings these are the files you will delete.', dryrun_list,
                       file_name_len,file_path_len)
                dryrun_list = []
                return

            if main_obj.empdir_var.get() == '0':  # rmdir checkbox
                print('remove dir not selected')
                msgbox('Processing complete!')
                return
            else:
                for dirpath, n, f in os.walk(path, topdown=False):
                    try:
                        os.rmdir(dirpath)
                    except OSError as ex:
                        print("Directory not empty.")
                msgbox('Processing complete!')
                return
            return # close csv????
    elif path == 'Click Browse to add folder':
        msgbox('Select a directory to run the script on.')
    else:
        msgbox("'" + path + "'" + ' does not exist or is not a valid path')
    file_cnt = 0



class MainFrame:
    def __init__(self, master):
        master.title('Dated File Removal Tool')
        # TOP FRAME
        self.topframe = ttk.Frame()
        self.topframe.grid(row=0, column=0, padx=10, pady=2, sticky='W')
        # browse button
        self.browseButton = Button(self.topframe, text="Browse", command=self.load_dir, width=15).grid(row=0, column=0)
        # okbutton test
        button = Button(self.topframe, text="Execute", command=self.ok_click, width=15)
        button.grid(row=0, column=1, sticky='E')

        # MIDDLE FRAME
        self.middleFrame = ttk.Frame()
        self.middleFrame.grid(row=1, column=0, sticky='W', padx=10, pady=5)
        # path display box
        self.dir_path = StringVar()
        browse_entry = Entry(self.middleFrame, width=65, textvariable=self.dir_path, state=DISABLED)
        browse_entry.grid(row=0, column=0)
        self.dir_path.set("Click Browse to add folder")


        # label frame
        self.options_lf = ttk.Labelframe(self.middleFrame, text='Options')
        # days combobox
        days = ('00 days', '30 Days', '60 Days', '90 Days')
        self.days_cmb = ttk.Combobox(self.options_lf, values=days, state='readonly')
        self.days_cmb.current(0)  # set selection
        self.days_cmb.grid(row=0, column=0, padx=25)
        # file types combobox
        filetypes = ('jpg', 'mp3', 'avi')
        self.file_cmb = ttk.Combobox(self.options_lf, values=filetypes, state='readonly')
        self.file_cmb.current(0)  # set selection
        self.file_cmb.grid(row=0, column=1, padx=25, pady=2)
        # test run checkbox
        self.checkvar = StringVar()
        dryrun_cb = Checkbutton(self.options_lf, text="Test Run", variable=self.checkvar)
        dryrun_cb.grid(row=1, column=0, sticky='W', padx=25)
        self.checkvar.set(1)
        # Remove dirs checkbox
        self.empdir_var = StringVar()
        empdir_cb = Checkbutton(self.options_lf, text="Remove Empty Dirs", variable=self.empdir_var)
        empdir_cb.grid(row=1, column=1, sticky='W', padx=25)
        self.empdir_var.set(0)
        # place in frame
        self.options_lf.grid(row=1, column=0, sticky='W')

        # BOTTOM FRAME
        self.bottomframe = ttk.Frame()
        self.bottomframe.grid(row=3, column=0)
        # prog bar
        self.progbar = ttk.Progressbar(self.bottomframe, orient='horizontal', mode='determinate', length=420)
        self.progbar.grid(row=1, column=0)

    def load_dir(self):
        dirname = askdirectory()
        if not dirname:
            pass  # file upload cancelled
        self.dir_path.set(dirname)

    def ok_click(self):
        daydif = int(self.days_cmb.get()[:2])
        walk_dir(self, self.dir_path.get(), daydif, self.file_cmb.get())
Source Link

Tkinter File Removal Program

This was my first foray into a Tkinter app and so I chose a simple and certainly overkill task to make into a gui.

Aside from one small aspect, this code functions as I was intending and seems to have adequate performance. I'm looking for help to make it more pythonic, not by simply pep8-ing it but by helping me better design the structure of functions and the code within them. For instance, do I really need self. for just about everything in my class mainframe?

The one thing that isn't performing as I want is the writing to CSV. It keeps the CSV file open in python until the tkinter window is closed and it also creates a CSV file when the dry run checkbox is checked.

One more note, this app was designed only to function on Windows.

Since it's a bit long, the code can be viewed here. Thanks!