3

Environment:

ArcGIS Pro 2.8 with SQL Server Enterprise Geodatabase

Background:

I'm working with ArcPy, and I've written a script tool that performs a few attribute edits. It does the edits to a versioned feature class (from a SQL Server Enterprise GDB).

Issue:

Everything works except the edit do not immediately show up in ArcGIS Pro. It requires the layer to be manually refreshed in order to display the new attributes in the table/labels/etc.

What was tried:

I have not been able to find a way to programmatically refresh the user's data source. I tried to use the updateConnectionProperties pointing to both the map object and the layer object. I've also tried modifying the layer refresh interval and the caching in ArcGIS Pro. Neither of which seemed to do the trick.

Found that we have a C# function that is capable of getting the desired results, but I am trying for a Python equivalent.

How do I refresh a .sde connection to see updates to a feature class?

Refresh Method (Version)

If there isn't a programmatic fix to this, I'm hoping that there's at least a setting I can modify in ArcGIS Pro to actually refresh the data from the server to pull the new attributes.

Sharing the script below:

import arcpy, sys, traceback, os
'''This script is referenced by a custom script tool to calculate the PIN Number and attribute it to the provided parcels layer. If the AKPAR is blank, user can also use tool dialog to attribute it.'''


def calcPin(parX, parY):
    '''PIN calculation based on rounded X&Y values (NAD83 NC State Plane Coordinate System)'''

    #Convert X/Y to string. Use Z fill to populate string to 6 total digits (adding preceeding 0 as needed)
    zf_x = str(round(parX,0)).zfill(6)
    zf_y = str(round(parY,0)).zfill(6)

    #PIN formula provided in NC GIS List Serv & NCPMA handbook
    cPin = str(zf_x)[1:2] + str(zf_y)[0:1]+str(zf_x)[2:3] + str(zf_y)[1:2]+ "-" + str(zf_x)[3:4] + str(zf_y)[2:3]+ "-" + str(zf_x)[4:5] + str(zf_y)[3:4]+str(zf_x)[5:6] + str(zf_y)[4:5]

    return cPin

def largestPoly(ply_Set):
    '''This returns the largest polygon among parts of a multi-part polygon feature'''

    #Iterate through polygons and find largest among multipart feature
    lastArea = 0
    for p in ply_Set:
        #Define feature point array as polygon in NAD83 NC SP
        ply_p = arcpy.Polygon(p, sRef)
        myArea = ply_p.getArea("PLANAR")

        #If this polygon's area is greater than the last read, define it as the largest polygon (ply_largest variable)
        if myArea > lastArea:
            ply_largest = ply_p
        
        lastArea = myArea


    return ply_largest

def refreshLyr(rLayer):
    '''This function doesn't achieve an actual refresh. This doesn't work'''
    fakeConnection = 'Path'
    rDict = {}
    str_dataSource = rLayer.dataSource
    conAry = conAry = str_dataSource.split(',')

    for c in conAry:
        cLst = c.split("=")
        cProp = cLst[0]
        cVal = cLst[1]

        rDict[cProp] = cVal
    
    rrDict = {}
    rrDict['connection_info'] = rDict
    #rLayer.updateConnectionProperties(rrDict, rrDict)

    myProj = arcpy.mp.ArcGISProject("Current")
    myMap = myProj.activeMap
    myMap.updateConnectionProperties(rrDict, fakeConnection)
    myMap.updateConnectionProperties(fakeConnection, rrDict)


#User parameters (parcels layer, akpar, calculated acres)
lyr_parcels = sys.argv[1]
str_akpar = sys.argv[2]
lrr_parcels = arcpy.GetParameter(0)

#Spatial reference of provided layer
dsc_parcels = arcpy.Describe(lyr_parcels)
sRef = dsc_parcels.spatialReference
str_fids = dsc_parcels.FIDSet

#Workspace of provided layer
str_ds = lrr_parcels.dataSource
str_catPath = dsc_parcels.catalogPath
str_ws = os.path.dirname(os.path.dirname(str_catPath))

#Check the parcel selection. If user doesn't have a selection, stop the script (otherwise it'll calculate ALL of the parcels!)
if not(str_fids):
    arcpy.AddMessage("Tool did not complete. Provided layer does not contain a selection.")
    sys.exit() 

#check projection. If not in NAD 83 SP, stop the script.
if sRef.projectionCode != 43020:
    arcpy.AddMessage("Tool did not complete. Provided layer is not in NAD 1983 StatePlane North Carolina FIPS 3200 Feet.")
    sys.exit()

#start edit session
editSession = arcpy.da.Editor(str_ws)
editSession.startEditing(True,True)

#Use Update cursor to attribute the layer.
try:
    with arcpy.da.UpdateCursor(lyr_parcels, ['AKPAR', 'PIN', 'FULL_AKPAR', 'SHAPE@']) as uCur:
        for u in uCur:

            #if user provided AKPAR, set it to the attribute value
            if str_akpar != str(u[0]) and str_akpar !='#':
                att_akpar = str_akpar
                att_fakpar = str_akpar.zfill(7)
                arcpy.AddMessage("Adding User's AKPAR")

                #set attributes for AKPAR and Full AKPAR
                u[0] = int(att_akpar)
                u[2] = att_fakpar


            #get point array of feature (single or multipart)
            ply_plyList = u[3]
            
            #if more than one polygon in feature, set ply_parcel to the largest polygon using above function.
            if len(ply_plyList) > 1:
                ply_parcel = largestPoly(u[3])
            
            #if only ony polygon in feature, set ply_parcel to a polygon built off of it's point array
            else:
                ply_parcel = arcpy.Polygon(u[3][0], sRef)
            
            
            #PIN Calculation. Using label point instead of centroid ensures that the subject point falls within the polygon.
            pnt_label = ply_parcel.labelPoint
            pnt_X = pnt_label.X
            pnt_Y = pnt_label.Y
            att_newPin = calcPin(pnt_X, pnt_Y)

            #Area in acres
            dbl_polyAcres = round(u[3].area/43560,2)

            #write PIN attribute
            u[1] = att_newPin

            #update row.
            editSession.startOperation()
            uCur.updateRow(u)
            editSession.stopOperation()

            #Pop up with new PIN and calculated acreage.
            arcpy.AddMessage("Parcel " + str(u[0]) + " New PIN: " + str(att_newPin))
            arcpy.AddMessage("Parcel " + str(u[0]) + " Calculated Acres: " + str(dbl_polyAcres))
            arcpy.AddMessage("\r\n")

        #delete the cursor
        del uCur


except:
    arcpy.AddMessage("PIN Calcuation Error")
    arcpy.AddMessage(traceback.format_exc())    

finally:

    #stop edit session
    editSession.stopEditing(True)

    #refresh data source (This doesn't work)
    #refreshLyr(lrr_parcels)

    arcpy.AddMessage("Complete")

1 Answer 1

1

Not a true pythonic solution but if you embed your script tool into a task, you can include the database refresh as an automatic/hidden command.

Would love to have it exposed as a method on the map itself but at least a bit of a workaround.

1
  • Thank you! I can definitely try it. Nov 22, 2022 at 21:11

Your Answer

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

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