Select to view content in your preferred language

How to import module into python toolbox

394
6
4 weeks ago
chris_del101
Regular Contributor

I have a very basic module I used to try and simply import it into a python tool box. The point would be run a useful application like this. 

I tried from the same folder together

toolbox.pyt

# this is same folder as the toolbox
same_folder =  os.path.dirname(os.path.realpath(__file__))

if same_folder not in sys.path:
    sys.path.append(same_folder)​

 

And from an different folder, just in case it cannot be in the same folder (or vv).

 

toolbox.pyt

# this is diff folder than toolbox
same_folder =  "C:\some\folder\"

sys.path.append(same_folder)​

 

The import resolves, but calling the func always breaks tool. These are the things I tried (with only one func at a time named test_method):

test_class.puy
class TestClass:
    @staticmethod
     # 1 - return this to getParameterInfo and return as [TestClass.test_method(arcpy)]
    def test_method(arcpy_instance):
         param0 = arcpy_instance.Parameter(
            displayName="Input Features",
            name="in_features",
            datatype="string",
            parameterType="Required",
            direction="Input")
         return param0

     # 2 - add a message - I put this on getParameterInfo, updateParameters, and execute and it never adds any msgs
    def test_method(arcpy_instance):
         def test_method(arcpy_instance):
             arcpy.AddMessage("Test method executed successfully.")
             arcpy.AddError("xyzxyzxyz.")


     # 3 - write to a file - this doesn't work - or breaks the tool
    def test_method():
         def test_method():
             def test_method():
        with open(r"some_dir\output.txt", "w") as f:
            f.write("test_method was called")


When called from execute, #3 builds but gives this when executed, even though #3 does not even have a "self" arg. These are all static methods. #1and #2 just do nothing and fail silently - the worst kind of failure.

TestClass.test_method() missing 1 required positional argument: 'self'

All of them break getParameterInfo if put there.

Screenshot 2025-11-18 103045.png

 

 

 

 

 

 

 

 

 

 

 

If I move this inside the toolbox things now work.
Do you really need to put all the code inside one giant file?? B/c importing outside modules as shown is a total failure. 
What does it have to be so nasty to work with this....

# this causes PermissionError: [Errno 13] Permission denied: - no matter what and I'm an admin.
def test_method_write():
    with open(r"some_path/file.txt", "w") as f:
        f.write("test_method was called!!!!!")

# this works as exepected
def test_method_param(mod):
    param0 = mod.Parameter(
        displayName="Input Features",
        name="in_features",
        datatype="string",
        parameterType="Required",
        direction="Input")
    return param0

# this works as exepected
def test_method_msg(mod):
   mod.AddMessage("Test message from test_method_msg")
   mod.AddWarning("Test warning from test_method_msg")
   mod.AddError("Test error from test_method_msg")

class Tool:
    def getParameterInfo(self):        
         return [test_method_param(arcpy)]


    def execute(self, parameters, messages):
        test_method_msg(arcpy)

 

0 Kudos
6 Replies
CodyPatterson
MVP Regular Contributor

Hey @chris_del101 

I noticed that when you posted the error message, it mentions missing "self", this could be because the class methods on Python require a self variable to be in the function itself, so yours may be missing this self variable, for example this is a section of a toolbox I have:

 def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
    

        return

    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool
        parameter.  This method is called after internal validation."""
        return

I'm wondering if adding self will allow that?

Cody

chris_del101
Regular Contributor

Hi Cody,

I dont see any missing selfs. Here is the full code

test_class.py
class TestClass:
    def test_message_instance(self, arcpy_mod):
        arcpy_mod.AddMessage("Test message from test_method_msg instance")
    @staticmethod
    def test_message_static(arcpy_mod):
        arcpy_mod.AddMessage("Test message from test_method_msg static")
    @classmethod
    def test_message_class(cls, arcpy_mod):
        arcpy_mod.AddMessage("Test message from test_method_msg class")


my_toolbox.pyt
# tried with and without this - file in same dir - confirmed this is correct dir
import arcpy
sys.path.append(os.getcwd())
class Toolbox:
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the
        .pyt file)."""
        self.label = "Toolbox"
        self.alias = "toolbox"
       
        # List of tool classes associated with this toolbox
        self.tools = [Tool]


class Tool:
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Tool"
        self.description = ""
        self.test_class = TestClass()

    def getParameterInfo(self):
       
        param0 = arcpy.Parameter(
            displayName="Input Features",
            name="in_features",
            datatype="string",
            direction="Input")

        return [param0]
    def isLicensed(self):
        """Set whether the tool is licensed to execute."""
        return True

    def updateParameters(self, parameters):
        # TestClass.test_method()
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        return

    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool
        parameter. This m ethod is called after internal validation."""
        return

    def execute(self, parameters, messages):
        """The source code of the tool."""
        self.test_class.test_message_instance(arcpy)
        TestClass.test_message_static(arcpy)
        TestClass.test_message_class(arcpy)
    

        return

    def postExecute(self, parameters):
        """This method takes place after outputs are processed and
        added to the display."""
        return

 

AttributeError: 'TestClass' object has no attribute 'test_message_instance'

 

0 Kudos
chris_del101
Regular Contributor

Hi Cody,

I dont see any missing selfs. Here is the full code

test_class.py
class TestClass:
    def test_message_instance(self, arcpy_mod):
        arcpy_mod.AddMessage("Test message from test_method_msg instance")
    @staticmethod
    def test_message_static(arcpy_mod):
        arcpy_mod.AddMessage("Test message from test_method_msg static")
    @classmethod
    def test_message_class(cls, arcpy_mod):
        arcpy_mod.AddMessage("Test message from test_method_msg class")


my_toolbox.pyt
# tried with and without this - file in same dir - confirmed this is correct dir
from test_class import TestClass
sys.path.append(os.getcwd())
class Toolbox:
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the
        .pyt file)."""
        self.label = "Toolbox"
        self.alias = "toolbox"
       
        # List of tool classes associated with this toolbox
        self.tools = [Tool]


class Tool:
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Tool"
        self.description = ""
        self.test_class = TestClass()

    def getParameterInfo(self):
       
        param0 = arcpy.Parameter(
            displayName="Input Features",
            name="in_features",
            datatype="string",
            direction="Input")

        return [param0]
    def isLicensed(self):
        """Set whether the tool is licensed to execute."""
        return True

    def updateParameters(self, parameters):
        # TestClass.test_method()
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        return

    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool
        parameter. This m ethod is called after internal validation."""
        return

    def execute(self, parameters, messages):
        """The source code of the tool."""
        self.test_class.test_message_instance(arcpy)
        TestClass.test_message_static(arcpy)
        TestClass.test_message_class(arcpy)
    

        return

    def postExecute(self, parameters):
        """This method takes place after outputs are processed and
        added to the display."""
        return


I still get

 

AttributeError: 'TestClass' object has no attribute 'test_message_instance'

 

 

0 Kudos
chris_del101
Regular Contributor

After further investigation it might be that the modules are just not updating. I guess its this, although I'm not 100% sure: link 

I currently have no way to do development since every change requires restarting pro - and there a hundreds of changes during development. Each restart takes 3-5 minutes.
Surely there must be a more orthodox way to do this?

They do say this, but I can't find the Export click they speak of:

Workaround

To make permanent changes to the source code, export the script by right-clicking it and clicking Export Script, make changes to the exported script, and import the script back if desired.

0 Kudos
AlfredBaldenweck
MVP Regular Contributor

Try using importlib.reload()?

Reloading modules in Python - GeeksforGeeks

HaydenWelch
MVP Regular Contributor

I've got a simple framework that solves this here: https://github.com/hwelch-fle/pytframe2

 

This method also makes sure that submodules are refreshed when the toolbox is refreshed, since by default the imported modules aren't reloaded until the interpreter is restarted (reboot ArcPro). This definitely makes it easier to develop a tool since you just refresh the toolbox and the new code is loaded in instantly as long as it's part of that reload chain.

I'm trying to add a lot of that functionality into a more holistic library under https://github.com/hwelch-fle/arcpie

 

Another note, all class methods in Python require a self argument since calling a method on an object passes self as arg0 even with no arguments.