Extract list of tools from a Python toolbox?

2130
3
10-28-2016 02:26 PM
curtvprice
MVP Esteemed Contributor

Trying to dynamically get a list of tools and labels from a Python toolbox to drop into value table that makes it easy to call said tools.

The closest I can come is this, but I don't see how I can "get at" the labels. ArcMap certainly can do this, why can't I?

>>> arcpy.ImportToolbox(r"D:\Users\cprice\tools\arcgis\PAPeakFlow\scripts\PolygonInfo.pyt")
<module 'pinf' (built-in)>
>>> dir(arcpy.pinf)
['AddFieldAndValue', 'CalcValuesToTable', 'IntersectArea', ...
  '__alias__', '__all__', '__builtins__', '__doc__', '__name__', ...]
0 Kudos
3 Replies
DanPatterson_Retired
MVP Emeritus
0 Kudos
curtvprice
MVP Esteemed Contributor

I discovered arcpy.ListTools() in the help - this won't give me labels, but it will work for what I'm doing here

arcpy.ImportToolbox(r'\\Mac\Home\Documents\ArcGIS\Toolbox.tbx', "z")
tools = arcpy.ListTools("*_z")
for t in tools:
    print(t)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

gives me

Model_z
Model1_z
FillPolygonHoles_z‍‍‍‍‍‍‍‍‍‍‍‍

The labels and descriptions seem out of reach so far from the limited of poking around that I've done, but this will do.

0 Kudos
DanPatterson_Retired
MVP Emeritus

If you can snag from namespace, then the inspect module is kind of useful.  This demo just inspects itself, but code inside shows how you might factor it to provide other information.

def num_41(func=None):
    """(num_41)...Documenting code using inspect
    :Requires:
    :--------
    :  import inspect  # module
    :Source code for...
    :  module level   => inspect.getsourcelines(sys.modules[__name__])[0]
    :  function level 
    :       as a list => inspect.getsourcelines(num_41)[0]
    :     as a string => inspect.getsource(num_41)
    :  file level => script = sys.argv[0]
    :Returns:  a listing of the source code with line numbers
    :-------
    :
    """
    def demo_def():
        """dummy...
        : Demonstrates retrieving and documenting module and function info.
        :
        """
        def sub():
           """sub in dummy"""
           pass
        return None
    import inspect
    if func is None:
        func = demo_def
    script = sys.argv[0]  # a useful way to get a file's name
    lines, line_num = inspect.getsourcelines(func)
    code = "".join(["{:4d}  {}".format(idx, line)
                    for idx, line in enumerate(lines)])
    defs = [key for key, value in globals().items()
            if callable(value) and value.__module__ == __name__]
    args = [line_num, code,
            inspect.getcomments(func), inspect.isfunction(func),
            inspect.ismethod(func), inspect.getmoduleinfo(script),
            defs
            ]
    frmt = """
    :----------------------------------------------------------------------
    :Code for a function on line...{}...
    {}
    :Comments preceeding function
    {}
    :function?... {} ... or method? {}
    :Module info...
    {}
    :
    :Module functions...
    {}    
    :----------------------------------------------------------------------
    """
    print(dedent(frmt).format(*args))
    return None‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

And here is the output if you use num_41() to inspect itself

Here is some output

>>> num_41()

:----------------------------------------------------------------------
:Code for a function on line...125...
   0      def demo_def():
   1          """dummy...
   2          : Demonstrates retrieving and documenting module and function info.
   3          :
   4          """
   5          def sub():
   6             """sub in dummy"""
   7             pass
   8          return None

:Comments preceeding function
None
:function?... True ... or method? False
:Module info...
ModuleInfo(name='testing_script_03', suffix='.py', mode='r', module_type=1)
:
:Module functions...
['num_46', 'num_47', 'num_44', 'num_40', 'num_41', 'num_42', 'num_43', 'dummy', 'num_45']    
:----------------------------------------------------------------------

Since the sample script is in a script (aka, module) there are a number of other functions in there.  For example.  I can pull in information from a particular module using

>>> locals().keys()
dict_keys(['dedent', ...snip ..., '__doc__', 'art', '__loader__', 'np', '__spec__', 'dummy', 'num_45'])

>>> num_41(art)

:----------------------------------------------------------------------
:Code for a function on line...0...
   0  # -*- coding: UTF-8 -*-
   1  """
   2  :Script:   arr_tools.py

...... huge snip .........

 682  
 683  # ----------------------------------------------------------------------
 684  # __main__ .... code section
 685  if __name__=="__main__":
 686      """   """
 687      #print("Script... {}".format(script))
 688      a, b, c, d = _demo()

By using other options in the inspect module, you can extract a lot of information.  I sometimes use this to get list of defs sometimes not revealed during the normal course of doing 'dir' or 'locals().keys()

0 Kudos