-1

I'm having trouble writing a function that could take a list of tarfile items via the .getmembers() method and put them in a proper tree structure (files within folders and subfolders) in the Treeview widget. I found a post similar to what I wanted: Tkinter: Treeview widget, but I just couldn't get it adapted for viewing archives.
The problem with the solution I referenced is that it uses os to walk a given directory and insert the items into a Treeview. Of course that won't work on a tarfile because it's a file, not a folder so when I tried modifying the solution I stored the tarfile members in a list and tried to feed it through the function but it's just not working for me.

Essentially, I need help with writing a function that takes a list of directory and file names and can insert parent directories into the root of the treeview, and child items into their containing folders.

import os
import tkinter as tk
import tkinter.ttk as ttk
import tarfile

window = tk.Tk()
window.title("Testing")
window.geometry("500x500")

tree = ttk.Treeview(window)
tree.pack()
tree.heading('#0', text="Item")
tree.column('#0', width=495)

# Get TAR items
with tarfile.TarFile("testing.tar") as topen:
    tarlist = topen.getmembers()

# Get our first directory in the list and remove it from stack
for i in tarlist:
    if i.isdir() == True:
        start_node = i.name
        del tarlist[tarlist.index(i)]
        break

# Insert root folder
root_node = tree.insert('', 'end', text=start_node)

def insert():
    # Go through the rest of the member list and put the member in the proper place
    # within the tree structure

window.mainloop()

j_4321
  • 15,431
  • 3
  • 34
  • 61
Jimmy-John
  • 31
  • 1
  • 8
  • "**it's just not working for me**" could you please add your function here with the Traceback error? – FrainBr33z3 Dec 19 '19 at 08:16
  • Well, if you want some traceback I used the proposed solution below and it gave "Item pylzma-master/pylzma-master/src already exists". But I'm assuming your talking about what I had before I asked which I couldn't really get my original best solution since I couldnt Ctrl-Z back to it. Essentially there was no traceback error; It was just displaying contents in a way which was undesirable. My original solution used some combination of os.dirname to get the dirname of tree items and compare it to the dirname of list items to determine if it's a child item, it was messy and obtuse. – Jimmy-John Dec 19 '19 at 18:01
  • Also I understand the way I worded my question was like "Make this function for me" but I have been spending so much time trying to figure this out with every function I write not giving me the desired outcome. Picking one to put in my code example would be difficult and just add unneeded fluff. Thanks and have a nice day! – Jimmy-John Dec 19 '19 at 18:52

2 Answers2

0

The idea is to use the full item's path as its iid in the tree so that you can get both the item's parent and the item's label with parent, label = os.path.split(item.path).

According to .getmembers() docstring,

Return the members of the archive as a list of TarInfo objects. The list has the same order as the members in the archive.

So you don't need to worry about the existence parent, it will have been created before if you go through tarlist with a for loop, like in the code below.

import os
import tkinter as tk
import tkinter.ttk as ttk
import tarfile

window = tk.Tk()
window.title("Testing")
window.geometry("500x500")

tree = ttk.Treeview(window)
tree.pack()
tree.heading('#0', text="Item")
tree.column('#0', width=495)

# Get TAR items
with tarfile.TarFile("testing.tar") as topen:
    tarlist = topen.getmembers()


def insert():
    for item in tarlist:
        parent, label = os.path.split(item.path)
        tree.insert(parent, 'end', iid=item.path, text=label)

insert()
window.mainloop()
j_4321
  • 15,431
  • 3
  • 34
  • 61
  • This worked to an extent, it was unable to display files that were in the base level of the Tarfile though. This must be because I'm getting an error that I had to catch, which is "Item pylzma-master/pylzma-master/src already exists" so I'm going to print the list and find what's causing the error and I'll get back to you. This was so much simpler than using os.dirname and fetching the name with tree.item('text') and seeing if the item was a child item. Thank you. – Jimmy-John Dec 19 '19 at 17:58
  • Ok just did some investigative work, the error arises because there is a copy of said item above, but because one of them is directory, and the other is a file without an extension but it's being treated like a copy of said directory. I was wondering if this could possibly be circumvented using the .isdir() method from the tarfile module? To detect what item is a directory and what is a file, regardless of extension/name. – Jimmy-John Dec 19 '19 at 18:16
  • I'm accepting your answer since you're the one who helped reach my goal, many thanks. I posted an answer as well showing what modifications I did to fine tune it to my liking and rule out any anomalies. Once again, thank you so much and have a wonderful day. – Jimmy-John Dec 20 '19 at 04:02
  • @Jimmy-John Thanks, I'm glad I could help. – j_4321 Dec 20 '19 at 09:03
0

Thanks to j_4321, here is what I did to get what I desired. I split the tarlist into a tardirs and tarfiles list, then added the tardirs first since I wanted them to be order hierarchically. Tarfiles then came next and were inserted in their proper place. I used an exception handler to catch any anomalies where a file has the same name as a directory, and avoid using iid in that instance. Result is a nicely structured view of a TAR archive, next would be adding folder icons next to items identified as directories and what not to make it look presentable.

tardirs = []
tarfiles = []

for i in tarlist:
    if i.isdir() == True:
        tardirs.append(i)
    else:
        tarfiles.append(i)

def insert():
    for item in tardirs:
        parent, label = os.path.split(item.path)
        try:
            tree.insert(parent, 'end', iid=item.path, text=label)
        except Exception:
            tree.insert(parent, 'end', text=label)
    for item in tarfiles:
        parent, label = os.path.split(item.path)
        try:
            tree.insert(parent, 'end', iid=item.path, text=label)
        except Exception:
            tree.insert(parent, 'end', text=label)
Jimmy-John
  • 31
  • 1
  • 8
  • For the icons, it is pretty straightforward, just use the `image` option when inserting the item. – j_4321 Dec 20 '19 at 09:02