Need help with syntax in UpdateRow parameter variables

2951
9
Jump to solution
01-07-2016 11:18 AM
RichardBunten
New Contributor III

I am new at python coding and I am trying to convert a script to a function.  The script that works is commented out at the bottom.  However, the problem I run into is trying to convert the values in the script at the bottom to variables that I can pass to a function.  I am trying to update the values of the field 'OperatingPressure' with the values that exist in the field 'MAOP'.  I can't get the correct syntax right for the values that will make up the variables of 'aWhereClause' and 'aUpdateExpression'.  Any help would be greatly appreciated.

import arcpy, os, string, logging
from arcpy import env

arcpy.env.workspace = "C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb"
workspace = "C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb"      #workspace

#This is the function that is my final product.
#def queryUpdateField(iList):
  #aTable = iList[0]
  #aWhereClause = iList[1]
  #aUpdateField = iList[2]
  #aUpdateExpression = iList[3]

  #Search for records in table
  # rows = arcpy.UpdateCursor(aTable,aWhereClause)

  # for row in rows:
  # row.setValue(aUpdateField,aUpdateExpression)
  # rows.updateRow(row)
  # del rows, row

#Call function above
#queryUpdateField([workspace + "/Gas/gasDistributionMain",'"MAOP" >= 0',
#'"OPERATINGPRESSURE"','row.getValue("MAOP")'])
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------


#This script is trying to test my variables and get them right before I put them 
#in the line above to call the function
aTable = workspace + "/Gas/gasDistributionMain" # this works
aWhereClause = "'" + '"' + "MAOP" +'"' +" >= 0'"  #fails needs correct syntax
aUpdateField = "OPERATINGPRESSURE" # this works
aUpdateExpression = "row.getValue(" + '"MAOP"'+ ")"  #fails needs correct syntax
print aWhereClause  #debug
print aUpdateExpression  #debug
rows = arcpy.UpdateCursor(aTable,aWhereClause)

for row in rows:
  row.setValue(aUpdateField,row.getValue("MAOP"))
  rows.updateRow(row)
del rows, row
#------------------Script that works that I am trying to convert to a function above----------------------------
# This works!!!
# rows = arcpy.UpdateCursor(workspace + "/Gas/gasDistributionMain",'"MAOP" >= 0')


# for row in rows:
  # row.setValue("OPERATINGPRESSURE",row.getValue("MAOP"))
  # rows.updateRow(row)
# del rows, row
0 Kudos
1 Solution

Accepted Solutions
LukeWebb
Occasional Contributor III

How about this, I added a optional parameter that you can supply if you choose to make it read a value from a field (Supply the name of field in IList[3], otherwise it is expecting you to pass just a Value within the IList[3].

def queryUpdateField(iList, updateType="Value"):
    aTable = iList[0]
    aWhereClause = iList[1]
    aUpdateField = iList[2]
    aUpdateExpression = iList[3]


    rows = arcpy.UpdateCursor(aTable,aWhereClause)
    try:
        for row in rows:
            if updateType == "Value":
                aUpdateExpression = aUpdateExpression
            elif updateType == "Field":
                aUpdateExpression = row.getValue(aUpdateExpression)
            row.setValue(aUpdateField,aUpdateExpression)
            rows.updateRow(row)
        del rows, row
        logger.info("Updated %s field with a value of %s in the FC: %s with the expression %s." %(iList[2],iList[1], iList[0],iList[3]))
        operationsCounter()
    except:
        del rows
        logger.error("Error in function queryUpdateField.",exc_info=True)
        print arcpy.GetMessages()

So to use this function with a supplied value within IList[3] you can call it as:

queryUpdateField(iList)

Or if you want it to read from a field (Whose name is within IList[3]:

queryUpdateField(iList, "Field")

The other thing you can look at is the python function eval() or exec(), but this is never recommended in general and I think the above is ok.

View solution in original post

9 Replies
LukeSturtevant
Occasional Contributor III

Any particular reason why you did not choose to go with the data-access module? You might also consider using 'with' statements to open your data access cursors. Have you printed each of the 'iList' items within your function that you are attempting to parse from the list to see what they look like?

RichardBunten
New Contributor III

I finally figured out the syntax. After testing each step.  Instead of passing the whole updateexpression, I just passed the fieldname for the update expression and it worked.

Below is the final code that works.

import arcpy, os, string, logging

from arcpy import env

arcpy.env.workspace = "C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb"

workspace = "C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb"      #workspace

#This does not work

def queryUpdateField(iList):

  aTable = iList[0]

  aWhereClause = iList[1]

  aUpdateField = iList[2]

  aUpdateExpression = iList[3]

  print aTable

  print aWhereClause

  print aUpdateField

  print aUpdateExpression

# Search for records in table

  rows = arcpy.UpdateCursor(aTable,aWhereClause)

  for row in rows:

  row.setValue(aUpdateField,row.getValue(aUpdateExpression))

  rows.updateRow(row)

  del rows, row

#queryUpdateField([workspace + "/Gas/gasDistributionMain",'"MAOP" >= 0','"OPERATINGPRESSURE"','row.getValue("MAOP")'])

queryUpdateField([workspace + "/Gas/gasDistributionMain",'"MAOP" >= 0',"OPERATINGPRESSURE","MAOP"])

RichardBunten
New Contributor III

After further examination, I would like the function to have the whole expression for the variable aUpdateExpression passed to it.  When I do this it still does not work.

Below is the code as it stands now and the error message that it throws.  It bails on the line row.setValue(aUpdateField, aUpdateExpression)

aUpdateField = "OPERATINGPRESSURE"

aUpdateExpression = "row.getValue(" + '"MAOP"'+ ")"

Is it possible to pass a command like row.getValue() in a variable?

import arcpy, os, string, logging

from arcpy import env

arcpy.env.workspace = "C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb"

workspace = "C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb"      #workspace

aTable = workspace + "/Gas/gasDistributionMain"

#fails on aWhereClause - need correct syntax

#aWhereClause = "'" + '"' + "MAOP" +'"' +" >= 0'"

aWhereClause = '"MAOP" >= 0'

aUpdateField = "OPERATINGPRESSURE"

#fails on aUpdateExpression - need correct syntax

aUpdateExpression = "row.getValue(" + '"MAOP"'+ ")"

#aUpdateExpression = "MAOP"

print aWhereClause

print aUpdateExpression

rows = arcpy.UpdateCursor(aTable,aWhereClause)

for row in rows:

  row.setValue(aUpdateField,aUpdateExpression)

  rows.updateRow(row)

del rows, row

error.JPG

0 Kudos
ChrisPedrezuela
Occasional Contributor III

I think this is just what you want to do,

import arcpy
import os

def updateField(feature, workspace):
    with arcpy.da.UpdateCursor(os.path.join(workspace, feature), ['OPERATINGPRESSURE', 'MAOP'], where_clause='"MAOP" >= 0') as cur:
        for row in cur:
            row[0] = row[1]
            cur.updateRow(row)

if __name__ == '__main__':
    workspace = r'C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb/Gas'
    feature = 'gasDistributionMain'
    updateField(feature, workspace)
0 Kudos
LukeWebb
Occasional Contributor III

I like to triple quote my where Clauses, here is a working version of your own script:

arcpy.env.workspace = "C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb"
workspace = "C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb"      #workspace


aTable = workspace + "/Gas/gasDistributionMain" # this works


aWhereClause ="""             "MAOP" > 0           """  # Non parameterised example


aWhereField = 'MAOP'
aWhereValue = 0
aWhereClause = """             "%s" > %s         """ % (aWhereField, aWhereValue) # Parameterised example


aUpdateField = "OPERATINGPRESSURE" # this works
print aWhereClause  #debug


rows = arcpy.UpdateCursor(aTable,aWhereClause)


for row in rows:
    #row.setValue(aUpdateField,row.getValue(aWhereField)) #Probably a crash
    row.setValue(aUpdateField, "'" + row.getValue(aWhereField) + "'") #If this one doesnt work try above!
    rows.updateRow(row)
del rows, row

The code isnt copying right on one of the lines maybe....

row.setValue(aUpdateField, "'" + row.getValue(aWhereField) + "'") #If this one doesnt work try above! 

0 Kudos
RichardBunten
New Contributor III

Thanks Thanos and Luke.  I appreciate your help.  Sorry, but I guess I am not making my question clear and I apologize in advance if I not following the code you supplied correctly.

I am wanting to know if I can pass the entire statement ""row.getValue(" + '"MAOP"'+ ")" in a variable back to the function.  There are other parts of my code that utilize this function but in those cases I am just calculating a number like 12 into all the records of the aUpdateField.  This time instead of passing a number I want to pass this snippet of code ""row.getValue(" + '"MAOP"'+ ")". 

I think I may just need to make a new function and use your code for this operation.  I was just trying to utilize an existing function that I had to update one field based on another.

PS.  How do I get the line numbers of the code to show up in my message.  I pasted the code in my first message and the line numbers appeared, but the second and third messages the line numbers did not appear with the code?

Below is the function that I am trying to get the variables correct to do the operation that you have solved above.

I want to pass the whole statement row.getValue(""row.getValue(" + '"MAOP"'+ ")" to the variable aUpdateExpression for the function below called queryUpdateField.  When this function is called elsewhere aUpdateExpression is just a number like 125 or 250 or text like 'UNK'.

Thanks for any help you can give me.

#Query subset of atable with aWhereClause and update aUpdateField with aUpdateExpression   

def queryUpdateField(iList):

    aTable = iList[0]

    aWhereClause = iList[1]

    aUpdateField = iList[2]

    aUpdateExpression = iList[3]

    rows = arcpy.UpdateCursor(aTable,aWhereClause)

    try:

        for row in rows:

            row.setValue(aUpdateField,aUpdateExpression)

            rows.updateRow(row)

        del rows, row

        logger.info("Updated %s field with a value of %s in the FC: %s with the expression %s." %(iList[2],iList[1], iList[0],iList[3]))

        operationsCounter()

    except:

        del rows

        logger.error("Error in function queryUpdateField.",exc_info=True)

        print arcpy.GetMessages()

0 Kudos
LukeWebb
Occasional Contributor III

How about this, I added a optional parameter that you can supply if you choose to make it read a value from a field (Supply the name of field in IList[3], otherwise it is expecting you to pass just a Value within the IList[3].

def queryUpdateField(iList, updateType="Value"):
    aTable = iList[0]
    aWhereClause = iList[1]
    aUpdateField = iList[2]
    aUpdateExpression = iList[3]


    rows = arcpy.UpdateCursor(aTable,aWhereClause)
    try:
        for row in rows:
            if updateType == "Value":
                aUpdateExpression = aUpdateExpression
            elif updateType == "Field":
                aUpdateExpression = row.getValue(aUpdateExpression)
            row.setValue(aUpdateField,aUpdateExpression)
            rows.updateRow(row)
        del rows, row
        logger.info("Updated %s field with a value of %s in the FC: %s with the expression %s." %(iList[2],iList[1], iList[0],iList[3]))
        operationsCounter()
    except:
        del rows
        logger.error("Error in function queryUpdateField.",exc_info=True)
        print arcpy.GetMessages()

So to use this function with a supplied value within IList[3] you can call it as:

queryUpdateField(iList)

Or if you want it to read from a field (Whose name is within IList[3]:

queryUpdateField(iList, "Field")

The other thing you can look at is the python function eval() or exec(), but this is never recommended in general and I think the above is ok.

ChrisPedrezuela
Occasional Contributor III

Yup sorry too Richard if I didn't fully considered your requirements. Luke has touched on it already. I highly recommend you switching to using arcpy.da (data access modules) that the Luke S mentioned to his reply to you. Its more flexible than how your using it for update cursor. Its pretty much what I used in my code I showed you. so if I update my code to consider your option for entering values or using values off a field,

import arcpy
import os

def updateViaField(featureclass, updateProcess, fields, wc):
    with arcpy.da.UpdateCursor(featureclass, fields, where_clause=wc) as cur:
        for row in cur:
            row[0] = row[1]
            cur.updateRow(row)

def updateViaValue(featureclass, updateProcess, fields, wc, updateValue):
    with arcpy.da.UpdateCursor(featureclass, fields, where_clause=wc) as cur:
        for row in cur:
            row[0] = updateValue
            cur.updateRow(row)

if __name__ == '__main__':

    '''Inputs'''
    workspace = r'C:/DuluthGIS/SchemaUpdate/SDESchemaTest.gdb/Gas'
    feature = 'gasDistributionMain'
    featureclass = os.path.join(workspace, feature)
    updateProcess = 'Field'
    updateField = 'OPERATINGPRESURE'
    wc = '"MAOP" >= 0'
    updateValue = 123

    '''Pass the condition'''
    if updateProcess == 'Field':
        valueField = 'MAOP'
        fields = [updateField, valueField]
        updateViaField(featureclass, updateProcess, fields, wc)
    else:
        fields = [updateField]
        updateViaValue(featureclass, updateProcess, fields, wc, updateValue)
RichardBunten
New Contributor III

Thanks Luke and Thanos. 

Appreciate your answers and ideas.  I took Luke's idea and used that.  Just modified my code with the If Else statement to accommodate my need to pass values or fields to the function.  I will also look at using arcpy.da.updateCursor that Thanos recommended.  I had not gone down that route since I have not had any performance issues with using arcpy.UpdateCursor, but I guess I should adopt the most up to date tools.

Thanks All.

0 Kudos