4

I created a simple tool that renames layers in the TOC using a for loop. As a tool within my normal toolbox it works fine. Now I´m trying to work more and more with the Python Toolbox and want to migrate the script there. It has these two parameters:

def __init__(self):
    """Define the tool (tool name is the name of the class)."""
    self.label = "Rename layers in TOC"

def getParameterInfo(self):
    """Define parameter definitions"""
    param0 = arcpy.Parameter(
        name="in_string",
        displayName="String to be replaced",
        datatype="GPString",
        parameterType="Required",
        direction="Input")

    param1 = arcpy.Parameter(
        name="out_string",
        displayName="will be replaced by",
        datatype="GPString",
        parameterType="Required",
        direction="Input")

    params = [param0,
              param1,
              param2]
    return params
...
def execute(self, parameters, messages):
    """The source code of the tool."""
    in_string = parameters[0].valueAsText
    out_string = parameters[1].valueAsText

    mxd = arcpy.mapping.MapDocument("CURRENT")
    layers = arcpy.mapping.ListLayers(mxd)
    for layer in layers:
        if in_string in layer.name:
            layer.name = layer.name.replace(in_string, out_string)

It goes through layer names in TOC and if in_string is found, it will be replaced by out_string. My problem is that if it founds a layer that matches the criteria, ArcMap probably renames it but immediately after that it removes the layer from the TOC.

As I was searching through the documentation and similar questions and answers here I found out that it treats that layer as a temporary one (that´s why it gets deleted from TOC) and a derived output must be set. That´s the point where I´m getting lost.

If I create a new parameter:

param2 = arcpy.Parameter(
    name="somelayer",
    displayName="somelayer",
    datatype="GPFeatureLayer",
    parameterType="Derived",
    direction="Output")

param2.parameterDependencies = [????]
param2.schema.clone = True

... I don´t think there is a suitable parameter for parameterDependecies because param0 and param1 are both strings. I need somehow to set the derived parameter to the layer that is being currently evaluated (for layer in layers...), is it possible to set the layer as derived while looping?

Where should I put a derived parameter? Or is there another way how I can make the layers in the TOC permament? Or could you give me some example (or maybe the solution) how to make it work? Neither the ArcGIS documentation nor another threads are quite clear for me.

  • As a quick fix have you seen a tool, I think written by Jason Scheirer called something like TBXtoPYT? – PolyGeo Mar 3 '17 at 20:51
  • A link to Jason Scheirer's tool that @PolyGeo mentions can be found in this Q&A gis.stackexchange.com/a/101445/64785 – Midavalo Mar 4 '17 at 1:06
  • I will try it. I wanted to avoid using it because I felt that manually writing the code would help me to strenghten my humble Pythonic experience but there might be no other way to find what´s wrong. – jonlew Mar 6 '17 at 5:55
  • No success. See comments under Midavalo´s answer. – jonlew Mar 6 '17 at 7:19
5

You haven't posted your full Python Toolbox pyt, so unsure whether you've got something in the Toolbox class that might be causing you issues, but your code above works fine for me (once completed). I had to add an arcpy.RefreshTOC() to automatically refresh the Table of Contents to reflect the layer name changes.

Before:
enter image description here

Tool:
enter image description here

After:
enter image description here

Here is the full pyt I used - all I added was the Toolbox class at the top, and the arcpy.RefreshTOC() at the bottom.

import arcpy
class Toolbox(object):
    def __init__(self):
        self.label = 'My Python Test Tool'
        self.tools = [MyTestTool]

class MyTestTool(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Rename layers in TOC"

    def getParameterInfo(self):
        """Define parameter definitions"""
        param0 = arcpy.Parameter(
            name="in_string",
            displayName="String to be replaced",
            datatype="GPString",
            parameterType="Required",
            direction="Input")

        param1 = arcpy.Parameter(
            name="out_string",
            displayName="will be replaced by",
            datatype="GPString",
            parameterType="Required",
            direction="Input")

        params = [param0, param1]
        return params

    def execute(self, parameters, messages):
        """The source code of the tool."""
        in_string = parameters[0].valueAsText
        out_string = parameters[1].valueAsText

        mxd = arcpy.mapping.MapDocument("CURRENT")
        layers = arcpy.mapping.ListLayers(mxd)
        for layer in layers:
            if in_string in layer.name:
                layer.name = layer.name.replace(in_string, out_string)
        arcpy.RefreshTOC()

Biggest difference I see between mine and yours is I'm running mine on ArcGIS 10.5 and you're using 10.1 which I believe was pretty early on for Python Toolboxes.

|improve this answer|||||
  • I have added arcpy.refreshTOC() - that means I have the same code now - and still no success in ArcGIS 10.1. Arcpy refreshes the TOC after the suitable layers had been already deleted (it deletes them from the TOC while running layer.name = layer.name.replace(in_string, out_string) so refreshing after that has no influence. I searched through "What´s new in ArcGIS 10.2 - 10.5" and I couldn´t find anything regarding this issue (probably the "mapping" category in what´s new). I´ll try TbyToPyt, there´s probably no other way how to test it. – jonlew Mar 6 '17 at 5:48
  • @jonlew What happens if you copy/paste my code as-is into a new PYT file and testing that? – Midavalo Mar 6 '17 at 5:55
  • I tried it also. Since your code was except arcpy.refreshTOC() the same, the behavior was the same - the layers were getting lost. I have tried TbyToPyt and left the new .pyt exactly how it converted - the tool runs but with the same problem. Jason´s tool made no corrections to the code in def execute(self, parameters, messages): so the layers are still disappearing. – jonlew Mar 6 '17 at 6:38
  • Interesting thing. I have 6 layers in TOC and the string to be replaced that I enter is in 3 layers. Running the tool: layers_count = 0 for layer in layers: if pattern in layer.name: layers_count += layers_count layer.name = layer.name.replace(in_string, out_string) These 3 layers disappears but it doesn´t count them! – jonlew Mar 6 '17 at 6:45
  • @jonlew Have you tried a different mxd with different layers? I'm starting to wonder if this is an issue with your document or layers, rather than your python – Midavalo Mar 6 '17 at 6:51
1

Instead of debugging what you have, you could try using the Toolbox to Python Toolbox Wrapper written by Jason Scheirer to convert the tools in your standard Toolbox (TBX) into a Python Toolbox (PYT).

|improve this answer|||||
  • No success. See comments under Midavalo´s answer... – jonlew Mar 6 '17 at 12:29
0

As the code in the question (with added arcpy.RefreshTOC() is working fine in ArcGIS 10.2 and later (thanks to Midavalo) while on different machines with ArcGIS 10.1 it fails, it seems that it may be a bug in early implementations of the Python Toolbox.

|improve this answer|||||
  • I have tested on 10.1 and experienced the same result. – Midavalo Mar 16 '17 at 3:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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