2

I know that this is definitely an ambiguous question. However, I initially had my Python toolbox working great. I then wanted to have additional functionality with it and added some more coding. Unfortunately, I ran into some indentation errors and ultimately redid the indents from scratch (tried multiple tools).

Now when I run a syntax check in ArcMap, it passes fine. However, when I double click on my tool, called Apply_LayerFeatures, then nothing happens. I get absolutely no feedback from ArcMap.

Does anyone have any idea why this may be happening? The purpose of the tool is to be able to apply the same symbology to multiple layers. The additional feature I was trying to implement was to check if the input is a set of points, then to enable labels using the same font format.

The code I have been working on is shown below:

import arcpy

class Toolbox(object):
def __init__(self):
    """Define the toolbox (the name of the toolbox is the name of 
    the.pyt file)."""
    self.label = "Toolbox"
    self.alias = ""

    # List of tool classes associated with this toolbox
    self.tools = [Apply_LayerFeatures]

class Apply_LayerFeatures(object):
def __init__(self):
    """Define the tool (tool name is the name of the class)."""
    self.label = "Apply_LayerFeatures"
    self.description = "Applies feautures to multiple layers. Customize a single layer and use it as a source layer in the tool then select layers to be modified by the tool"
    self.canRunInBackground = False

def getParameterInfo(self):
    """Define parameter definitions"""

    # First parameter = layer with customized features
    source = arcpy.Parameter(
        displayName = "Source layer with customized features",
        name = "source",
        datatype = "Feature Layer",
        parameterType = "Required",
        direction = "Input")

    # Second parameter = layers to which customized features will be applied
    updlayers = arcpy.Parameter(
        displayName = "Layers with features to be updated",
        name = "updlayers",
        datatype = "GPValueTable",
        parameterType = "Required",
        direction = "Input")

    labelFontSize = arcpy.Parameter(
        displayName = "Label Font Size",
        name = "labelFontSize",
        datatype = "GPDouble",
        parameterType = "Required",
        direction = "Input")

    updlayers.columns = [['Feature Layer', 'Features']]

    params = [source,updlayers,labelFontSize]
return params

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

def execute(self, parameters, messages):
    """The source code of the tool."""

    #Get Inputs
    updlayers = parameters[1].values
    labelFontSize = parameters[2].values

    #labelFontSize = parameters[2].values

    for layers in updlayers:
        for labels in layers:
            labels.showLabels = True
            for a in labels.labelClasses:
                    a.expression = '"%s" + [Name] + "%s"' %  ("<BOL><FNT name='Arial' size=labelFontSize>","</FNT></BOL>")

    source = parameters[0].valueAsText
    updlayers = parameters[1].valueAsText.split(";")

    for app in updlayers:
        arcpy.ApplySymbologyFromLayer_management(app.strip("'"),source)

    arcpy.RefreshTOC
    arcpy.RefreshActiveView
return
6
  • 1
    debug python toolbox
    – klewis
    Sep 26, 2014 at 22:40
  • The indentation in the code you posted is definitely wrong. Is that how it's indented in your actual .tbx?
    – nmpeterson
    Sep 27, 2014 at 16:15
  • @nmpeterson Yes, that's actually how it's indented. Does anyone know of any useful tools for correcting the indentation in Python code?
    – coolDude
    Sep 29, 2014 at 16:19
  • ^ you can use a lint like pylint, but for this scope a pair of eyes should do. Everything nested in Python needs to be indented, it will be second-nature in no-time.
    – Sleep6
    Sep 29, 2014 at 18:09
  • 1
    Ah, yes, an easy thing to miss. Here's a tip: see if your text editor has an option to automatically convert tabs to spaces. Most of the editors designed for coding do have such an option.
    – nmpeterson
    Sep 30, 2014 at 23:24

2 Answers 2

2

There is excellent advice offered in the Esri Blog entitled How to Debug Python Toolboxes in 3 Easy Steps linked to by @klewis in his comment to your question. You should definitely read that blog which recommends:

  1. Add a main() function. Within this function, create an instance of the tool class and call it’s execute() method. The arguments for execute() include the parameter information created by the getParameterInfo() method and the messages which are set to None.
  2. Comment out existing lines for retrieving parameter values, and enter hard-coded parameter values.
  3. Set a break point at the position where you want to start stepping through the code.

However, if you are new to Python coding and Python Toolboxes, then you may find it easier to:

  1. Create a new Python toolbox from scratch
  2. Carefully copy/paste chunks of code from your broken script into the new one
  3. Test after each addition, and return to the previous version if/when you break it

Although this is a bit "trial and error" I think you will find that it makes you think about what each part of the code is doing, and to be able to pinpoint what is currently breaking it.

1
  • I apologize for the delay in my response. However, I really appreciate for your help on this. The debugging procedure you've pointed out to me is very useful (surprising that there still isn't already a means to do this!). I discovered that I had a mixture of tabs and spaces which was giving me the error. I converted each of the tabs into 4 spaces and that resolved my issue. Thanks again :)
    – coolDude
    Sep 30, 2014 at 19:09
2

As noted in a comment, your indentation is wrong. Here's your code with corrected indentation:

import arcpy

class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of 
        the.pyt file)."""
        self.label = "Toolbox"
        self.alias = ""

        # List of tool classes associated with this toolbox
        self.tools = [Apply_LayerFeatures]

class Apply_LayerFeatures(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Apply_LayerFeatures"
        self.description = "Applies feautures to multiple layers. Customize a single layer and use it as a source layer in the tool then select layers to be modified by the tool"
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""

        # First parameter = layer with customized features
        source = arcpy.Parameter(
            displayName = "Source layer with customized features",
            name = "source",
            datatype = "Feature Layer",
            parameterType = "Required",
            direction = "Input")

        # Second parameter = layers to which customized features will be applied
        updlayers = arcpy.Parameter(
            displayName = "Layers with features to be updated",
            name = "updlayers",
            datatype = "GPValueTable",
            parameterType = "Required",
            direction = "Input")

        labelFontSize = arcpy.Parameter(
            displayName = "Label Font Size",
            name = "labelFontSize",
            datatype = "GPDouble",
            parameterType = "Required",
            direction = "Input")

        updlayers.columns = [['Feature Layer', 'Features']]

        params = [source,updlayers,labelFontSize]
        return params

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

    def execute(self, parameters, messages):
        """The source code of the tool."""

        #Get Inputs
        updlayers = parameters[1].values
        labelFontSize = parameters[2].values

        #labelFontSize = parameters[2].values

        for layers in updlayers:
            for labels in layers:
                labels.showLabels = True
                for a in labels.labelClasses:
                    a.expression = '"%s" + [Name] + "%s"' %  ("<BOL><FNT name='Arial' size=labelFontSize>","</FNT></BOL>")

        source = parameters[0].valueAsText
        updlayers = parameters[1].valueAsText.split(";")

        for app in updlayers:
            arcpy.ApplySymbologyFromLayer_management(app.strip("'"),source)

        arcpy.RefreshTOC
        arcpy.RefreshActiveView
        return

Basically, all code within a class needs to be indented, as do the return statements in function defs. Hopefully this fixes your issue.

1
  • I had no idea Python did not like mixtures of tabs and spaces. Once I replaced all of my tabs with 4 spaces (to make sure my code was still properly indented), then everything went smoothly. I appreciate all of the help!
    – coolDude
    Sep 30, 2014 at 20:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.