I'm still using 10.0 so can't actually test this, but have you tried using the standard python package structure?
Something like:
# \--SomeDir # | toolbox.pyt # \--toolpackage # | __init__.py # | script_a.py # | script_b.py #---------------------------- #The .pyt file #---------------------------- import arcpy from toolpackage.script_a import Tool1 from toolpackage.script_a import Tool2 from toolpackage.script_b import Tool3 class Toolbox(object): def __init__(self): """Define the toolbox (the name of the toolbox is the name of the .pyt file).""" self.label = "MultiTool Toolbox" self.alias = "mtt" # List of tool classes associated with this toolbox self.tools = [Tool1, Tool2, Tool3]
#---------------- # 10.0 script tool # script_10_0.py #---------------- import arcpy def do_some_stuff(arg1,arg2): print arg1,arg2 if __name__ == '__main__': arg1=arcpy.GetParameterAsText(0) arg2=arcpy.GetParameterAsText(1) do_some_stuff(arg1,arg2) #---------------------- # 10.1 Python Toolbox #---------------------- import arcpy import script_10_0 #import the old 10.0 script tool so you can call its functions. class Toolbox(object): def __init__(self): """Define the toolbox (the name of the toolbox is the name of the .pyt file).""" self.label = "10_0_Tool_Toolbox" self.alias = "Toolbox with 10.0 Tools" # List of tool classes associated with this toolbox self.tools = [Tool1] class Tool1(object): #... def execute(self, parameters, messages): arg1=parameters[0].valueAsText arg2=parameters[1].valueAsText script_10_0.do_some_stuff(arg1,arg2)
if i could find a way to just publish the pyt once then throw the extra scripts in there and have them recognized that would be the bomb
# \--SomeDir # | toolbox.pyt # | some_script.py # | another_script.py # | ... # | last_script.py # # Each *.py contains a class called Tool that's just a stub for your "main" def. #---------------------------- #The .pyt file (all Tools are dynamically imported not hardcoded) #---------------------------- import arcpy import os,sys,glob class Toolbox(object): def __init__(self): """Define the toolbox (the name of the toolbox is the name of the .pyt file).""" self.label = "MultiTool_Toolbox" self.alias = "Toolbox with Multiple Dynamically Imported Tools" # Dynamic list of tool classes associated with this toolbox path=os.path.dirname(__file__) self.tools=[] for py in glob.glob(os.path.join(path,'*.py')): if not __file__ in py: module=os.path.basename(py)[:-3] #Note: "Tool" class must have same #name as the script "Tool" classes self.tools.append(__import__(module).Tool) #---------------------------- #The .py script files #---------------------------- #"Tool" class can be called anything but must be # the same in each script and in the calling toolbox class Tool(object): # tool/parameter setup methods etc... def execute(self,*args,**kwargs): main(*args,**kwargs) def main(*args,**kwargs): #do stuff return if __name__=='__main__': #Run script main(sys.argv[1:])
This is somewhat similar to how the Spatial Analyst Supplemental tools area set up. This structure has the advantage of the .py files could be run either from the .pyt or added as pyx script tools.
I am finally getting into this and really appreciate the discussion and Luke's examples.
Another tip on tbx's that is helping me is to run the Jason Scheirer's tbx2pyt tool, and then stealing the results to copy and paste into the getParameterInfo() code, which seems to be the most time-consuming part of this.
One thing about this that is kind of unnerving is there really isn't a very standard way to do it (yet). That will take time I guess, as people do different things for example
I'm quite late, but I haven't been able to get this method to work. The syntax on the .pyt is OK (i.e.: I'm able to view the toolbox within arcmap without it displaying the red X), but when I click the drop-down for the toolbox, it displays no tools.
My directory is set up as such:
Tools/
- bhaTools.pyt
- publishing.py
-findingpath.pyc
The findingpath.pyc:
def findpath():
local_path = os.path.abspath(os.path.dirname(__file__))
return local_path
The bhaTools.pyt has the following:
import contextlib
import os
import sys
import arcpy
import glob
class Toolbox(object):
def __init__(self):
self.label = u'bhaTools'
self.alias = 'bhaTools'
import findingpath
path = findingpath.findpath()
self.tools=[]
for py in glob.glob(os.path.join(path,'*.py')):
if not __file__ in py:
module=os.path.basename(py)[:-3]
#Note: "Tool" class must have same
#name as the script "Tool" classes
self.tools.append(__import__(module).Tool)
The publishing.py:
class Tool(object):
def __init__(self):
self.label = u'Publish Parcel Fabric Parcels'
self.canRunInBackground = False
self.category = ["Parcel_Fabric_Migration_Tools"]
def getParameterInfo(self):
param_1 = arcpy.Parameter()
param_1.name = u'inputParcelFabricParcels'
param_1.displayName = u'Input Parcel Fabric Parcels'
param_1.parameterType = 'Required'
param_1.direction = 'Input'
param_1.datatype = u'DEFeatureClass'
#### .... more parameters .... ####
return [param_1,param_2,param_3,param_4,param_5]
def isLicensed(self):
return True
def updateParameters(self, parameters):
validator = getattr(self, 'ToolValidator', None)
if validator:
return validator(parameters).updateParameters()
def updateMessages(self, parameters):
validator = getattr(self, 'ToolValidator', None)
if validator:
return validator(parameters).updateMessages()
# tool/parameter setup methods etc...
def execute(self,*args,**kwargs):
main(*args,**kwargs)
def main(*args,**kwargs):
try:
# do stuff with params
except arcpy.ExecuteError:
arcpy.AddError(arcpy.GetMessages())
if __name__=='__main__':
#Run script
main(sys.argv[1:])