Multiple Paths Traversed and Displayed Filed type

2019-08-16 23:19发布

问题:

I'm new here so bare in mind that and I hope my questions are clearly asked for you lot to help me out. I am trying to alter Brent Tylers Dropbox script so that I will be able to list Python under Python, Mel under Mel and so on(eventually plugins and other files too but not for now)

Ok so my directory is like so:

1.
sf=C:/users/scripts/ a.py + b.mel
pf=C:/users/scripts/Python/c.py
mf=C:/users/scripts/Mel/d.mel

(These are the folders my scripts will be placed in)

Code :

absoluteFiles = []
relativeFiles = []
folders = []
allFiles = []
currentFile = ''

for root, dirs, files in os.walk(sf):
    for x in files:
        correct = root.replace('\\', '/')
        currentFile = (correct + '/' + x)
        allFiles.append(currentFile)
        if currentFile.endswith('.mel'):
            relativeFiles.append(currentFile.replace((mf + '/'), ""))
        if currentFile.endswith('.py'):
            relativeFiles.append(currentFile.replace((pf + '/'), ""))

relativeFiles.sort()

for relativeFile in relativeFiles:
    split = relativeFile.split('/')
    fileName = split[-1].split('.')
    i=0
    while i<(len(split)):
        ### Create Folders ###
        if i==0 and len(split) != 1:
            if cmds.menu(split[i] ,ex=1) == 0:
                cmds.menuItem(split[i], p=PadraigsTools, bld=1, sm=1, to=1, l=split[i])
        if i > 0 and i < (len(split)-1):
            if cmds.menu(split[i] ,ex=1) == 0:
                cmds.menuItem(split[i], p=split[i-1], bld=1, sm=1, to=1, l=split[i])

        ### Create .mel Files  ###
        if fileName[-1] == 'mel':
            if i==len(split)-1 and len(split) > 1:
                scriptName = split[-1].split('.')
                temp1 = 'source ' + '"' + sf + '/' + relativeFile + '"; ' + scriptName[0]
                command = '''mel.eval(''' + "'" + temp1 + '''')'''
                cmds.menuItem(split[i], p=split[i-1], c=command, l=split[i])
            if i==len(split)-1 and len(split) == 1:
                scriptName = split[-1].split('.')
                temp1 = 'source ' + '"' + sf + '/' + relativeFile + '"; ' + scriptName[0]
                command = '''mel.eval(''' + "'" + temp1 + '''')'''
                cmds.menuItem(split[i], p=Mel, c=command, l=split[i])

        ### Create .py Files  ###
        if fileName[-1] == 'py':
            if i==len(split)-1 and len(split) > 1:
                command = 'import ' + fileName[0] + '\n' + fileName[0] + '.' + fileName[0]+ '()'
                cmds.menuItem(split[i], p=split[i-1], c=command, l=split[i])
            if i==len(split)-1 and len(split) == 1:
                command = 'import ' + fileName[0] + '\n' + fileName[0] + '.' + fileName[0]+ '()'
                cmds.menuItem(split[i], p=Python, c=command, l=split[i])
        i+=1
  1. So far I can print out individually (sf, pf, mf) to the corresponding Directory but I cant list out everything at once and the files under sf will not show at all. regarding the folders created it ends up very odd. sometimes i would get a duplicate folder as a submenu and if i use sf it give me C:/.

  2. After days and hours of research trying to mend this script I have found no answer including

from itertools import chain paths = (mf, sf, pf) for path, dirs, files in chain.from_iterable(os.walk(path) for path in paths):

::QUESTION:: Is there a way i can put this together sanely so that new folders will show up with their contents on refresh as a submenu and the files will show up and allow me to execute them from their corresponding submenu.

I would appreciate any help possible including down votes haha. And bare in mind I don't want you to hand me the answer on a golden spoon because I wont know what is corrected or needs to be :)

Thanks Greatly -- Padraig

回答1:

There's a couple of things you can do to simplify things a bit.

First, it's a good idea to make this as data-driven as possible so you don't have to re-write it if your needs change. This does more or less what you do, but collects the results into a dictionary where the key are the root paths you supplied and the values are lists of relative paths:

def find_files(root, extensions = ('mel', 'py')):
    def clean_path(*p):
        return "/".join(p).replace('\\', '/')

    for root, _, files in os.walk(root):
        used = [f for f in files if f.split(".")[-1] in extensions]
        for u in used:
            yield clean_path(root, u)

def relativize(abs, roots):
    low_roots = map (str.lower, roots) # all lower for comparison
    for root, low_root in zip(roots,low_roots):
        if abs.lower().startswith(low_root):
            return root, abs[len(root):]
    return ("", abs)


relative_paths = find_files('c:/users/scripts')

root_dict = {}
for item in relative_paths :
    folder, file = relativize(item, ('C:/users/scripts/Python/', 'C:/users/scripts/Mel/', 'C:/users/scripts/'))
    if not folder in root_dict:
        root_dict[folder] = []
    root_dict[folder].append(file)

So now you have a dictionary with a bunch of root folders and lists of relative paths (files that were not in any relative path you supplied are keyed to empty string and show up as absolute paths). You can make the menus in a very generic way because they are all in the same format. If you need the entire list, you can get it like this:

 results = []
 for each_root in root_dict:
     for relpath in root_dict[each_root]:
         results.append(each_root + relpath)

For creating the actual menus, you want to use a single function and bind it to the filename for each menu item as you make it. This is a slightly tricky topic (more detail here). The easy way to do this is to use a functools.partial object, which bundles a command and a bunch of arguments into an object which looks like a function: you can create a partial and attach it to the command of your menu items so they all call the same function with their individual arguments. Here's a simple example using the variables from above and a menubar; you can see how to adapt it to other kinds of menus pretty easily:

from functools import partial

# call this on every button selection
def test(filepath, ignore):
    # maya will send "test(name, False)"; we just ignore the 'False'
    print "Here's where I would reload", filepath

example = cmds.window(title = 'example')
menubar = cmds.menuBarLayout()            

for name in folder_names:
    menuname = name
    if menuname:
        menuname = menuname.split("/")[-2] # we used trailing slashes
    else:
        menuname = "root"
    cmds.menu(label = menuname)
    file_names = root_dict[name]
    file_names.sort()
    for fn in file_names:
        mi = cmds.menuItem(label = fn, command = partial(test, fn))
    cmds.setParent(menubar)