Read one field and apply domain value to another field with UpdateCursor: KeyError

864
11
Jump to solution
03-28-2023 09:30 AM
nsidaniel
New Contributor III

 

I'm trying to read the [OWN] field and apply a domain value to 3 different fields with UpdateCursor, yet I keep getting a KeyError:

KeyError                                  Traceback (most recent call last)
In  [84]:
Line 49:    row[0] = lookup_values['Fee']

KeyError: 'Fee'

 

The domains are already set and show up correctly on the a POLYGONS_feature_class. I'm sick of staring at this bit of code! Any ideas?

 

 # defines OpCo, RightsType, and Type_of_Use fields 
    # by info in OWN field

gdb = projectfilepath + projectfileGDB
fc = POLYGONS_feature_class
domains = arcpy.da.ListDomains(gdb)

 # 'OpCo' field
cur = arcpy.UpdateCursor(fc)
for row in cur:
    if row.getValue('OWN') == 'INT %' or 'IT %' or 'TRANSMISSION, TAX DEPARTMENT':       
        fieldname = 'OpCo'
        field = arcpy.ListFields(fc, fieldname)[0]
        for domain in domains:
            if domain.name == field.domain:
                coded_values = domain.codedValues
                lookup_values = dict(zip(coded_values.values(),coded_values.keys()))
                break
# Set 'OpCo' field
        with arcpy.da.UpdateCursor(fc, fieldname) as cursor:
            for row in cursor:
                row[0] = lookup_values['IT']
                cursor.updateRow(row)


# 'RightsType' field  
cur = arcpy.UpdateCursor(fc)
for row in cur:
    if row.getValue('OWN') == 'INT %' or 'IT %' or 'TRANSMISSION, TAX DEPARTMENT':
        fieldname = 'RightsType'              
        field = arcpy.ListFields(fc, fieldname)[0]
        for domain in domains:
            if domain.name == field.domain:
                coded_values = domain.codedValues
                lookup_values = dict(zip(coded_values.values(),coded_values.keys()))
                break
 # Set 'RightsType' field 
        with arcpy.da.UpdateCursor(fc, fieldname) as cursor:
            for row in cursor:
                row[0] = lookup_values['Fee']
                cursor.updateRow(row)   
                
 
 # 'Type_of_Use' field
cur = arcpy.UpdateCursor(fc)
for row in cur:
    if row.getValue('OWN') == 'INT %' or 'IT %' or 'TRANSMISSION, TAX DEPARTMENT': 
        fieldname = 'Type_of_Use'
        field = arcpy.ListFields(fc, fieldname)[0]
        for domain in domains:
            if domain.name == field.domain:
                coded_values = domain.codedValues
                lookup_values = dict(zip(coded_values.values(),coded_values.keys()))
                break
 # Set Type_of_Use field 
        with arcpy.da.UpdateCursor(fc, fieldname) as cursor:
            for row in cursor:
                row[0] = lookup_values['Full T-Line']
                cursor.updateRow(row)

 

0 Kudos
2 Solutions

Accepted Solutions
BlakeTerhune
MVP Regular Contributor

That error means there's no key of "Fee" lookup_values dictionary when you build it for the RightsType field. Some things to check:

  1. Is a domain assigned to that RightsType field? If so, is the domain you expect?
  2. Does that domain have a description of "Fee"? Your zip is putting the description as the key in lookup_values and code in value. Also remember that this lookup value is case sensitive.
  3. Maybe print() lookup_values when you build it for the RightsType field so you can confirm what you're getting.

View solution in original post

BlakeTerhune
MVP Regular Contributor

Like this then?

fields = ["OWN1", "OpCo", "RightsType", "Type_of_Use"]
with arcpy.da.UpdateCursor(fc, fields) as u_cursor:
    for own1, opco, rightstype, type_of_use in u_cursor:
        if own1 in ("ITC", "TRANSMISSION, TAX DEPARTMENT"):
            opco = "ITCT"
        elif own1 == "CONSUMERS":
            opco = "METC"
        u_cursor.updateRow([own1, opco, rightstype, type_of_use])

 

View solution in original post

11 Replies
BlakeTerhune
MVP Regular Contributor

That error means there's no key of "Fee" lookup_values dictionary when you build it for the RightsType field. Some things to check:

  1. Is a domain assigned to that RightsType field? If so, is the domain you expect?
  2. Does that domain have a description of "Fee"? Your zip is putting the description as the key in lookup_values and code in value. Also remember that this lookup value is case sensitive.
  3. Maybe print() lookup_values when you build it for the RightsType field so you can confirm what you're getting.
nsidaniel
New Contributor III

Thanks Blake!

1. Yep, a domain is assigned to the RightsType field

2. Yes, the domain has "Fee"

3. GREAT IDEA!!! I had stored the wrong codes in my domain dictionary.

I had feeling it was something really obvious (it always is, isn't it?

0 Kudos
nsidaniel
New Contributor III

@BlakeTerhune, would you happen to know why when I repeat the code within the same feature class looking for a different domain value within the same domain, the cursor merely writes over the entire field with the new domain?

cur = arcpy.UpdateCursor(fc)
for row in cur:
    if row.getValue('OWN') == 'CONSUMERS':
        fieldname = 'OpCo'              
        field = arcpy.ListFields(fc, fieldname)[0]
        for domain in domains:
            if domain.name == field.domain:
                coded_values = domain.codedValues
                lookup_values = dict(zip(coded_values.values(),coded_values.keys()))
                break
 # Set 'RightsType' field 
        with arcpy.da.UpdateCursor(fc, fieldname) as cursor:
            for row in cursor:
                row[0] = lookup_values['MET']
                cursor.updateRow(row)   

 

0 Kudos
BlakeTerhune
MVP Regular Contributor

I'm either misunderstanding your question or your original intent. Your code is applying the same value to that field on every row. If you want it to apply a lookup value based on what's already in the field, then you probably want to change it like this.

with arcpy.da.UpdateCursor(fc, fieldname) as cursor:
    for row in cursor:
        row[0] = lookup_values[row[0]]
        cursor.updateRow(row)

My apologies if I'm not answering the correct question.

nsidaniel
New Contributor III

@BlakeTerhune, no need to apologize, I appreciate your help! For context, I posted the feature class' attribute table that the code produces below the python.

 

cur = arcpy.UpdateCursor(fc)
for row in cur:
    if row.getValue('OWN1') == 'ITC' or 'TRANSMISSION':
        fieldname = 'OpCo'              
        field = arcpy.ListFields(fc, fieldname)[0]
        for domain in domains:
            if domain.name == field.domain:
                coded_values = domain.codedValues
                lookup_values = dict(zip(coded_values.values(),coded_values.keys()))
                break
 # Set 'OpCo' field 
        with arcpy.da.UpdateCursor(fc, fieldname) as cursor:
            for row in cursor:
                row[0] = lookup_values['ITCT']
                cursor.updateRow(row)



    if row.getValue('OWN1') == 'CONSUMERS':
        fieldname = 'OpCo'              
        field = arcpy.ListFields(fc, fieldname)[0]
        for domain in domains:
            if domain.name == field.domain:
                coded_values = domain.codedValues
                lookup_values = dict(zip(coded_values.values(),coded_values.keys()))
                break
 # Set 'OpCo' field 
        with arcpy.da.UpdateCursor(fc, fieldname) as cursor:
            for row in cursor:
                row[0] = lookup_values['METC']
                cursor.updateRow(row)  

 

nsidaniel_0-1680029717866.png

 

0 Kudos
BlakeTerhune
MVP Regular Contributor

@nsidaniel wrote:

@BlakeTerhune, no need to apologize, I appreciate your help! For context, I posted the feature class' attribute table that the code produces below the python.


So I assume your question is not answered? Could you describe exactly what you want to do?

nsidaniel
New Contributor III

@BlakeTerhune

So, I run the code from my initial question that (thanks to your suggestion) is running wonderfully, here's a sample:

 

cur = arcpy.UpdateCursor(fc)
for row in cur:
    if row.getValue('OWN1') == 'ITC' or 'TRANSMISSION':
        fieldname = 'OpCo'              
        field = arcpy.ListFields(fc, fieldname)[0]
        for domain in domains:
            if domain.name == field.domain:
                coded_values = domain.codedValues
                lookup_values = dict(zip(coded_values.values(),coded_values.keys()))
                break
 # Set 'OpCo' field 
        with arcpy.da.UpdateCursor(fc, fieldname) as cursor:
            for row in cursor:
                row[0] = lookup_values['ITCT']
                cursor.updateRow(row)

 

 

 

But, then I run the next portion:

 

cur = arcpy.UpdateCursor(fc)
for row in cur:
    if row.getValue('OWN1') == 'CONSUMERS':
        fieldname = 'OpCo'              
        field = arcpy.ListFields(fc, fieldname)[0]
        for domain in domains:
            if domain.name == field.domain:
                coded_values = domain.codedValues
                lookup_values = dict(zip(coded_values.values(),coded_values.keys()))
                break
 # Set 'OpCo' field 
        with arcpy.da.UpdateCursor(fc, fieldname) as cursor:
            for row in cursor:
                row[0] = lookup_values['METC']
                cursor.updateRow(row)  

 

 

It spits out:

nsidaniel_0-1680036821003.png 

the OpCo field should all contain "METC"

 

In theory, if OWN1 contains CONSUMERS, OpCo should be"METC"

and if OWN1 contains ITC or TRANSMISSION, OpCo should be"ITCT"

0 Kudos
BlakeTerhune
MVP Regular Contributor

You're still not telling me what you are tying to do. I'm still guessing, but here's another method to consider.

 

# Build dictionary of domain objects for each field.
domains = arcpy.da.ListDomains(gdb)
field_domain = {}
for field in arcpy.ListFields(fc):
    dom = [d for d in domains if d.name == field.domain]
    if dom:
        field_domain[field.name] = dom[0]

# Update data to change code to description.
fields = ["OWN1", "OpCo", "RightsType", "Type_of_Use"]
with arcpy.da.UpdateCursor(fc, fields) as u_cursor:
    for own1, opco, rightstype, type_of_use in u_cursor:
        # Pick the right domain coded values
        if own1 in ("ITC", "TRANSMISSION"):
            coded_values = field_domain["OpCo"].codedValues
        elif "INT " in own1 or "IT " in own1 or own1 == "TRANSMISSION, TAX DEPARTMENT":
            coded_values = field_domain["RightsType"].codedValues
        # elif a_field == some other condition:
        #     coded_values = field_domain["a_field"].codedValues
        else:
            raise Exception(f"This data doesn't match any criteria.\n{[own1, opco, rightstype, type_of_use]}")

        # Change field value.
        own1 = coded_values['ITCT']
        # Update the row.
        u_cursor.updateRow([own1, opco, rightstype, type_of_use])

 

nsidaniel
New Contributor III

I apologize for my terrible explanations, @BlakeTerhune!

My initial question was how to read one field and then apply a domain value to another field with UpdateCursor. (To be honest I had written successful code for this ... then accidentally changed something.) You helped immensely, which I very much appreciate!

After I applied your suggestion, I then attempted to update the code to search the OWN1 field for "ITC", and "TRANSMISSION, TAX DEPARTMENT", or "CONSUMERS.

It was supposed to search the OWN1 field:

If it found "ITC", or "TRANSMISSION, TAX DEPARTMENT", it would change the OpCo field to "ITCT".

If it found "CONSUMERS", it would change the OpCo field to "METC".

Instead, the code wrote only "ITCT" or "METC" in the OpCo field depending on which I ran first. I'm sure it's obvious that I'm new to coding (but unfortunately, I kind of love it), and cannot see what's wrong.

Hopefully, that makes sense! No matter what, thank you for your time.

0 Kudos