How to list all Toolboxes names in a specific folder or geodatabase?

3979
8
Jump to solution
09-08-2015 12:20 PM
SaidAkif
New Contributor III

Hi all

I tried to retrive a names list of all toolboxes and tools I reated and that are located in a specific folder. I used arcpy.ListToolBoxes() and arcpy.ListTools(). The problem those two functions list that is located in the ArcMap AcrToolBox, not in my folder. The functions arcpy.da.Walk(workspace, topdown=True,datatype='Toolbox') also dont give any results even if in my forlder there are tools and toolboxes.

Any help please?

Thanks

0 Kudos
1 Solution

Accepted Solutions
FreddieGibson
Occasional Contributor III

ListTools and ListToolboxes are designed to display the toolboxes that have been loaded into the arcpy site package (i.e. tools that are setup to load by default, such as the out-of-the-box ArcGIS tools and tools loaded via a call to the arcpy.ImportToolbox function).

This workflow works for me using the arcpy.da.Walk method, but it appears that if you specify the datatype as Toolbox it will not locate the toolboxes stored within a geodatabase. I've listed the logic I used below for you to review. You should see that the first two options return all toolboxes within a directory except for those that exist within a geodatabase structure. I believe this is what you're seeing. My third example shows how I get around this and list all of the toolboxes regardless if they're a file on disk or stored within the geodatabase structure.

import arcpy
import os
import uuid

# First Option
def LocateToolboxes1(workspace):
    walk = arcpy.da.Walk(workspace, datatype="Toolbox")
    for dirpath, dirnames, filenames in walk:    
        for filename in filenames:
            print(os.path.join(dirpath, filename))
            
# Second Option
def LocateToolboxes2(workspace):
    walk = arcpy.da.Walk(workspace, datatype="Toolbox")
    for dirpath, dirnames, filenames in walk:    
        if (dirpath.endswith(".tbx")):
            print("TBX: {0}".format(dirpath))
            
            alias = arcpy.ValidateFieldName(str(uuid.uuid4()).split("-")[-1])
            arcpy.ImportToolbox(dirpath, alias)
            
            for tool in arcpy.ListTools("*_{0}".format(alias)):
                print("...TOOL: {0}".format(tool))     
                
# Third Option
def LocateToolboxes3(workspace):
    walk = arcpy.da.Walk(workspace)
    for dirpath, dirnames, filenames in walk:      
        tbxPaths = []
        
        if (dirpath.endswith(".tbx")):
            tbxPaths.append(dirpath)
            
        elif (dirpath.endswith(".gdb")):
            for dirname in dirnames:
                tbxPath = os.path.join(dirpath, dirname)
                if (arcpy.Describe(tbxPath).dataType == "Toolbox"):
                    tbxPaths.append(tbxPath)
        
        if (tbxPaths == []):
            continue
        
        for tbxPath in tbxPaths:
            print("TBX: {0}".format(tbxPath))
            alias = arcpy.ValidateFieldName(str(uuid.uuid4()).split("-")[-1])
            arcpy.ImportToolbox(tbxPath, alias)
        
            for tool in arcpy.ListTools("*_{0}".format(alias)):
                print("...TOOL: {0}".format(tool))  
    
                
if __name__ == '__main__':
    tbxFolder = r"C:\Users\Freddie\Desktop\Toolboxes"
    
    print("### OPTION 1 ###")
    LocateToolboxes1(tbxFolder)
    
    print("\n### OPTION 2 ###")
    LocateToolboxes2(tbxFolder)
    
    print("\n### OPTION 3 ###")
    LocateToolboxes3(tbxFolder)

View solution in original post

8 Replies
FreddieGibson
Occasional Contributor III

ListTools and ListToolboxes are designed to display the toolboxes that have been loaded into the arcpy site package (i.e. tools that are setup to load by default, such as the out-of-the-box ArcGIS tools and tools loaded via a call to the arcpy.ImportToolbox function).

This workflow works for me using the arcpy.da.Walk method, but it appears that if you specify the datatype as Toolbox it will not locate the toolboxes stored within a geodatabase. I've listed the logic I used below for you to review. You should see that the first two options return all toolboxes within a directory except for those that exist within a geodatabase structure. I believe this is what you're seeing. My third example shows how I get around this and list all of the toolboxes regardless if they're a file on disk or stored within the geodatabase structure.

import arcpy
import os
import uuid

# First Option
def LocateToolboxes1(workspace):
    walk = arcpy.da.Walk(workspace, datatype="Toolbox")
    for dirpath, dirnames, filenames in walk:    
        for filename in filenames:
            print(os.path.join(dirpath, filename))
            
# Second Option
def LocateToolboxes2(workspace):
    walk = arcpy.da.Walk(workspace, datatype="Toolbox")
    for dirpath, dirnames, filenames in walk:    
        if (dirpath.endswith(".tbx")):
            print("TBX: {0}".format(dirpath))
            
            alias = arcpy.ValidateFieldName(str(uuid.uuid4()).split("-")[-1])
            arcpy.ImportToolbox(dirpath, alias)
            
            for tool in arcpy.ListTools("*_{0}".format(alias)):
                print("...TOOL: {0}".format(tool))     
                
# Third Option
def LocateToolboxes3(workspace):
    walk = arcpy.da.Walk(workspace)
    for dirpath, dirnames, filenames in walk:      
        tbxPaths = []
        
        if (dirpath.endswith(".tbx")):
            tbxPaths.append(dirpath)
            
        elif (dirpath.endswith(".gdb")):
            for dirname in dirnames:
                tbxPath = os.path.join(dirpath, dirname)
                if (arcpy.Describe(tbxPath).dataType == "Toolbox"):
                    tbxPaths.append(tbxPath)
        
        if (tbxPaths == []):
            continue
        
        for tbxPath in tbxPaths:
            print("TBX: {0}".format(tbxPath))
            alias = arcpy.ValidateFieldName(str(uuid.uuid4()).split("-")[-1])
            arcpy.ImportToolbox(tbxPath, alias)
        
            for tool in arcpy.ListTools("*_{0}".format(alias)):
                print("...TOOL: {0}".format(tool))  
    
                
if __name__ == '__main__':
    tbxFolder = r"C:\Users\Freddie\Desktop\Toolboxes"
    
    print("### OPTION 1 ###")
    LocateToolboxes1(tbxFolder)
    
    print("\n### OPTION 2 ###")
    LocateToolboxes2(tbxFolder)
    
    print("\n### OPTION 3 ###")
    LocateToolboxes3(tbxFolder)
Luke_Pinner
MVP Regular Contributor

Freddie, your code doesn't pick up Python Toolboxes.  I've tweaked your 3rd example to include .pyt's

import os, uuid
import arcview, arcpy

# Third Option
def LocateToolboxes3(workspace):
    walk = arcpy.da.Walk(workspace)
    for dirpath, dirnames, filenames in walk:
        tbxPaths = []

        if (os.path.splitext(dirpath)[1] in [".tbx", ".pyt"] ):
            tbxPaths.append(dirpath)

        elif (dirpath.endswith(".gdb")):
            for dirname in dirnames:
                tbxPath = os.path.join(dirpath, dirname)
                if (arcpy.Describe(tbxPath).dataType == "Toolbox"):
                    tbxPaths.append(tbxPath)

        if (tbxPaths == []):
            continue

        for tbxPath in tbxPaths:
            print("TBX: {0}".format(tbxPath))
            alias = arcpy.ValidateFieldName(str(uuid.uuid4()).split("-")[-1])
            arcpy.ImportToolbox(tbxPath, alias)

            for tool in arcpy.ListTools("*_{0}".format(alias)):
                print("...TOOL: {0}".format(tool))
RhettZufelt
MVP Frequent Contributor

I'm curious as to what this line is doing?

alias = arcpy.ValidateFieldName(str(uuid.uuid4()).split("-")[-1])

I am familiar with the ValidateFieldName, but not sure how the random, unique number is being used here?

R_

0 Kudos
FreddieGibson
Occasional Contributor III

I was using this approach to give each toolbox a unique alias. After creating a guid, I used this function to remove any special characters that may cause problems, such as dashes which would be replaced with underscores.

SaidAkif
New Contributor III

Thank you very much. this is very helpful

0 Kudos
SaidAkif
New Contributor III

Hi all

the third option of Freddie amended by Luke is interesting except that it take lot of time to have result.

Is there another way to do it faster?

By the way, can you explain please the use of __name__?

Thanks

0 Kudos
BlakeTerhune
MVP Regular Contributor

'__main__' is the name of the scope in which top-level code executes. A module’s __name__ is set equal to '__main__'when read from standard input, a script, or from an interactive prompt.

29.4. __main__ — Top-level script environment — Python 3.4.3 documentation

It's really just a way to make the starting point of the script.

0 Kudos
RhettZufelt
MVP Frequent Contributor

Mainly used to keep imported scripts from running on import.

If you had the above script but without the if __name__ part (so that everything below it were at the zero indentation level), if you were to import it, it would not only load the functions, but would execute the Loacatetoolbox() functions as well (will run everything at the zero indentation level) (default behavior of python).

In the above case, if you were to import the above script, it will load the functions and make sure they are available, but, the if __name__ would not see __name__= '__main__', __name__ would be equal to the name of the script you just imported, so, it would ignore the commands below that line, essentially just importing the functions waiting for you to call them specifically.

R_