3

I'm trying to make a Python script tool which uses the Trace Geometric Network tool (10.3). My script works in the Python window, but as a script-tool, it runs and NOTHING HAPPENS. Messages state: Executing..., Start time..., Running script..., Completed script... Succeeded at... It acts like the tool executed with no errors, but there's no visible output.

The Trace Geometric Network tool refuses to work inside a Python script tool the way it does in the Python window. I tried playing with the parameters, data types in of parameter settings, and deleting and remaking the tool several times. I even tried using other geometric networks with the tool. Finally, I made a bare-bones script with only the trace tool to troubleshoot, and NOTHING. I get the same action as above.

Here's my bare-bones script:

geoNetwork = arcpy.GetParameterAsText(0)

inflags = arcpy.GetParameterAsText(1)

barriers = arcpy.GetParameterAsText(2)

arcpy.TraceGeometricNetwork_management(geoNetwork, "Trace", inflags, "TRACE_DOWNSTREAM", barriers)

Here's a screen shot of how I'm setting my parameters in the tool properties:

Tool Parameter Properties

How can I to get this to work as a Python script tool?

Here's the actual code. As this tool executes, I can see it looping over the flags and selecting them one by one. No output group layer files are added to the map and no apparent traces are made. Again, these functions work as intended if pasted in the python window, but misbehave as python-script tools.

inflags = arcpy.GetParameterAsText(0)
geoNetwork = arcpy.GetParameterAsText(1)
barriers = arcpy.GetParameterAsText(2)
outPath = arcpy.GetParameterAsText(3)
outName = arcpy.GetParameterAsText(4)

def makeFullPath(path, name):
    return path + "\\" + name

def TraceCapture(inflags, geoNetwork, barriers, outPath, outName):  
    mxd = arcpy.mapping.MapDocument("CURRENT")
    df = arcpy.mapping.ListDataFrames(mxd)[0]
    flagList = list(arcpy.da.SearchCursor(inflags, 'UNITID'))
    trace = 1
    segmentCapture = []
    for flag in range(1, len(flagList)+1): 
        try:
            outputLayer = "Trace_" + str(trace)
            expression = '"OBJECTID" =' + str(trace)
            arcpy.SelectLayerByAttribute_management(inflags, "NEW_SELECTION", expression)
            arcpy.TraceGeometricNetwork_management(geoNetwork, outputLayer, inflags, "TRACE_DOWNSTREAM", barriers)
            arcpy.AddMessage("Trace_" + str(trace) + " complete")

            for lyr in arcpy.mapping.ListLayers(mxd, "", df):
                if lyr.name == "Sewers":
                    pipesCursor = arcpy.da.SearchCursor(lyr, 'ASSETID')
                    for i in pipesCursor:
                        segmentCapture.append((flagList[trace - 1][0], i[0]))
                if lyr.name == outputLayer:
                    arcpy.mapping.RemoveLayer(df, lyr)
            trace += 1
        except RuntimeError:
            print "Flag " + str(trace) + " was invalid and skipped."
            trace += 1
            continue

    arcpy.CreateTable_management(outPath, outName)
    outFile = makeFullPath(outPath, outName)
    arcpy.AddField_management(outFile, "manholeID", "TEXT", "", "", 10)
    arcpy.AddField_management(outFile, "pipeID", "TEXT", "", "", 10)

    with arcpy.da.InsertCursor(outFile, ["manholeID", "pipeID"]) as cursor:
        for row in segmentCapture:
            cursor.insertRow(row)

TraceCapture(inflags, geoNetowrk, barriers, outPath, outName)
4

Odds are it has finished, and finished properly. You don't have any outputs on your tool, thus the script tool wont return anything to your ArcMap session.

In most Trace models/scripts I've seen, you need to Select Data to pull out whatever child element you want, then its good to run Copy Features on that item. The output of CopyFeatures should be passed into one more variable you need to define on the Parameters page you've shown. You can set it as a derived output if you're handling the output location of the data in your script.

Model

See the picture of the model here where you can see Select and Make Feature Layer after the Trace tool (but dont use Make Feature Layer, use Copy Features). Note that the Select tool is a ModelBuilder ONLY tool. The workflow is different in Python.

Python

To select an item out of the group layer, you need to have prior knowledge of what it's name will be. The below code shows you can list the sub items of a group layer to get their name. Having prior knowledge of the names, you just need to build up a path to the output using traceName/subLayerName. (arcpy.mapping code is only added for reference to print out all available item names, in practice you probably wouldn't add this to a production tool)

arcpy.Snap_edit(Flags, "'Primary OH Conductor' VERTEX '30 Meters'")

arcpy.TraceGeometricNetwork_management(El_Paso_Electric, "Storm_Net", Flags, "TRACE_UPSTREAM", "", "", "", "", "", "NO_TRACE_ENDS", "TRACE_INDETERMINATE_FLOW", "", "", "AS_IS", "", "", "", "AS_IS")

network = arcpy.mapping.Layer("Storm_Net")
if network.isGroupLayer:
    for sublayer in network:
        arcpy.AddMessage("  {} ".format(sublayer.name))

# Process: Select Data
#arcpy.SelectData_management("Storm_Net", "ServiceLocation")  # <--- dont use

# Build up the path to the item you want, in this case, "Storm_Net" is my output Trace, and "ServiceLocation" is the item inside I want.
arcpy.CopyFeatures_management("Storm_Net/ServiceLocation", outputFeatureClass)
  • I wish the answer was that simple. Select Data is a model-builder only tool, so no python. Second, the output of the Trace is a group layer, which copies the geometric network and selects the trace features. This all works in the python window, but as a script tool, no group layer is created and no selection is made. Also, in my real script, I attempt capture the result in a list of tuples, which is written to a GDB table. I'll update my question with the real code. What's weird is that the script tool loops over my flags, and creates the empty table, but won't execute the trace in between. – Priscilla Dec 16 '15 at 22:13
  • just a guess: make an output parameter of type GroupLayer, and pass the output from Trace into this parameter using SetOutput. The trace tool outputs a group layer. This might return all items of the trace, which is better than none? I'm trying to find if there is another way to grab a single output in python – KHibma Dec 18 '15 at 3:08
  • @Priscilla I updated this answer with some Python code that does what you want. – KHibma Jan 11 '16 at 16:11
  • Thank you for posting this code! This is a great answer. You just taught me two new methods: .Snap_edit and .isGroupLayer – Priscilla Jan 12 '16 at 19:26
2

I wanted to share the final code I used to make a script tool. There were two main issues with the code I posted in my original question. First, was the problem of using 'in_memory' workspace for the trace output group layers, which KHimba answered nicely above. The second problem was how I set the parameter data types in the script tool properties. The 'select by attributes' tool only works for layers in an mxd, and not for feature classes on disk. Nothing was selected while the parameter was looking for a feature class. Instead, I needed to set the data type to layer. I also made adjustments to allow for non-sequential ObjectId's, by removing the counter and just looping through a list of flags. I struggled with this code for a few weeks, so I hope it's helpful for someone else out there.

import arcpy

arcpy.env.workspace = 'in_memory'
arcpy.env.overwriteOutput = True 
mxd = arcpy.mapping.MapDocument("CURRENT")
df = arcpy.mapping.ListDataFrames(mxd)[0]

# Define Parameters
inflags = arcpy.GetParameterAsText(0) #type: layer
geoNetwork = arcpy.GetParameterAsText(1) #type: geometric network
barriers = arcpy.GetParameterAsText(2) #type: layer (optional)
outGDB = arcpy.GetParameterAsText(3) #type: data element
outName = arcpy.GetParameterAsText(4) #type: string

def makeFullPath(path, name):
    return path + "\\" + name

def TraceCapture(inflags, geoNetwork, barriers, outPath, outName):  
    flagList = list(arcpy.da.SearchCursor(inflags, ['OBJECTID', 'UNITID']))
    segmentCapture = []
    for flag in flagList: #using list instead of counter combats errors with non-sequential OBJECTID's
        try:
            trace = flag[0]
            outputLayer = "Trace"
            expression = '"OBJECTID" =' + str(trace)
            arcpy.SelectLayerByAttribute_management(inflags, "NEW_SELECTION", expression)
            arcpy.TraceGeometricNetwork_management(geoNetwork, outputLayer, inflags, "TRACE_DOWNSTREAM", barriers)
            arcpy.AddMessage("Trace_" + str(trace) + " complete")

            #access trace from "in_memory"
            for lyr in arcpy.mapping.Layer(outputLayer):
                for x in arcpy.mapping.ListLayers(lyr):
                    if x.name == 'Sewers':
                        pipesCursor = arcpy.da.SearchCursor(x, 'ASSETID')
                        for i in pipesCursor:
                            segmentCapture.append((flag[1], i[0])) #main event: append tuples relating manhole UnitID to pipe AssetID                   
        except RuntimeError:
            arcpy.AddMessage("Flag " + str(trace) + " was invalid and skipped.")
            continue
    arcpy.SelectLayerByAttribute_management(inflags, "CLEAR_SELECTION")

    #write segmentCapture to a GBD table
    arcpy.CreateTable_management(outPath, outName)
    outTable = makeFullPath(outPath, outName)
    arcpy.AddField_management(outTable, "manholeID", "TEXT", "", "", 10)
    arcpy.AddField_management(outTable, "pipeID", "TEXT", "", "", 10)

    with arcpy.da.InsertCursor(outTable, ["manholeID", "pipeID"]) as cursor:
        for row in segmentCapture:
            cursor.insertRow(row)

    #add new table to the map
    tView = arcpy.mapping.TableView(outTable)
    arcpy.mapping.AddTableView(df, tView)

#execute TraceCapture Tool
TraceCapture(inflags, geoNetwork, barriers, outGDB, outName)

#For display, execute trace for all flags
arcpy.TraceGeometricNetwork_management(geoNetwork, "Trace", inflags, "TRACE_DOWNSTREAM", barriers)

#add final trace to map, from "in_memory location"
addLayer = arcpy.mapping.Layer("Trace")
arcpy.mapping.AddLayer(df, addLayer)

Here's the tool parameter properties: enter image description here

  • hi Priscilla..did the barriers work well? I have some problems with them . – Bahman Rashidi Jan 20 at 11:45
  • Yes - The barriers work well with the tool. I should say that I updated the data type of the flags and barriers to Feature Layer and that seems to work better. The barriers must be features within your geometric network or at least snapped to the geonet, otherwise they won't work. I can help you troubleshoot if needed. – Priscilla Jan 22 at 14:19

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.